|
|
1.1 root 1: /* if_imp.c 6.1 83/07/29 */
2:
3: #include "imp.h"
4: #if NIMP > 0
5: /*
6: * ARPANET IMP interface driver.
7: *
8: * The IMP-host protocol is handled here, leaving
9: * hardware specifics to the lower level interface driver.
10: *
11: * NB: only handles IMPS on class A networks.
12: */
13: #include "../machine/pte.h"
14:
15: #include "../h/param.h"
16: #include "../h/systm.h"
17: #include "../h/mbuf.h"
18: #include "../h/buf.h"
19: #include "../h/protosw.h"
20: #include "../h/socket.h"
21: #include "../h/vmmac.h"
22: #include "../h/time.h"
23: #include "../h/kernel.h"
24: #include "../h/errno.h"
25: #include "../h/ioctl.h"
26:
27: /*#include "../machine/cpu.h"*/
28: #include "../machine/mtpr.h"
29: /*#include "../vaxuba/ubareg.h"*/
30: /*#include "../vaxuba/ubavar.h"*/
31:
32: #include "../net/if.h"
33: #include "../net/route.h"
34:
35: #include "../net/netisr.h"
36: #include "../netinet/in.h"
37: #include "../netinet/in_systm.h"
38: #include "../netinet/ip.h"
39: #include "../netinet/ip_var.h"
40: /* define IMPLEADERS here to get leader printing code */
41: #include "../netimp/if_imp.h"
42: #include "../netimp/if_imphost.h"
43:
44: /*
45: * IMP software status per interface.
46: * (partially shared with the hardware specific module)
47: *
48: * Each interface is referenced by a network interface structure,
49: * imp_if, which the routing code uses to locate the interface.
50: * This structure contains the output queue for the interface, its
51: * address, ... IMP specific structures used in connecting the
52: * IMP software modules to the hardware specific interface routines
53: * are stored here. The common structures are made visible to the
54: * interface driver by passing a pointer to the hardware routine
55: * at "attach" time.
56: *
57: * NOTE: imp_if and imp_cb are assumed adjacent in hardware code.
58: */
59: struct imp_softc {
60: struct ifnet imp_if; /* network visible interface */
61: struct impcb imp_cb; /* hooks to hardware module */
62: u_char imp_state; /* current state of IMP */
63: char imp_dropcnt; /* used during initialization */
64: } imp_softc[NIMP];
65:
66: /*
67: * Messages from IMP regarding why
68: * it's going down.
69: */
70: static char *impmessage[] = {
71: "in 30 seconds",
72: "for hardware PM",
73: "to reload software",
74: "for emergency reset"
75: };
76:
77: int impdown(), impinit(), impioctl(), impoutput();
78:
79: /*
80: * IMP attach routine. Called from hardware device attach routine
81: * at configuration time with a pointer to the UNIBUS device structure.
82: * Sets up local state and returns pointer to base of ifnet+impcb
83: * structures. This is then used by the device's attach routine
84: * set up its back pointers.
85: */
86: impattach(ui, reset)
87: register int ui;
88: int (*reset)();
89: {
90: struct imp_softc *sc = &imp_softc[ui];
91: register struct ifnet *ifp = &sc->imp_if;
92:
93: /* UNIT COULD BE AMBIGUOUS */
94: ifp->if_unit = ui;
95: ifp->if_name = "imp";
96: ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
97: ifp->if_reset = reset;
98: ifp->if_init = impinit;
99: ifp->if_ioctl = impioctl;
100: ifp->if_output = impoutput;
101: /* reset is handled at the hardware level */
102: if_attach(ifp);
103: return ((int)&sc->imp_if);
104: }
105:
106: /*
107: * IMP initialization routine: call hardware module to
108: * setup UNIBUS resources, init state and get ready for
109: * NOOPs the IMP should send us, and that we want to drop.
110: */
111: impinit(unit)
112: int unit;
113: {
114: int s = splimp();
115: register struct imp_softc *sc = &imp_softc[unit];
116: struct sockaddr_in *sin;
117:
118: sin = (struct sockaddr_in *)&sc->imp_if.if_addr;
119: if (in_netof(sin->sin_addr) == 0)
120: return;
121: if ((*sc->imp_cb.ic_init)(unit) == 0) {
122: sc->imp_state = IMPS_DOWN;
123: sc->imp_if.if_flags &= ~IFF_UP;
124: splx(s);
125: return;
126: }
127: sc->imp_if.if_flags |= IFF_RUNNING;
128: sc->imp_state = IMPS_INIT;
129: impnoops(sc);
130: splx(s);
131: }
132:
133: struct sockproto impproto = { PF_IMPLINK };
134: struct sockaddr_in impdst = { AF_IMPLINK };
135: struct sockaddr_in impsrc = { AF_IMPLINK };
136: #ifdef IMPLEADERS
137: int impprintfs = 0;
138: #endif
139:
140: /*
141: * ARPAnet 1822 input routine.
142: * Called from hardware input interrupt routine to handle 1822
143: * IMP-host messages. Type 0 messages (non-control) are
144: * passed to higher level protocol processors on the basis
145: * of link number. Other type messages (control) are handled here.
146: */
147: impinput(unit, m)
148: int unit;
149: register struct mbuf *m;
150: {
151: register struct imp_leader *ip;
152: register struct imp_softc *sc = &imp_softc[unit];
153: register struct host *hp;
154: register struct ifqueue *inq;
155: struct control_leader *cp;
156: struct in_addr addr;
157: struct mbuf *next;
158: struct sockaddr_in *sin;
159:
160: /* verify leader length. */
161: if (m->m_len < sizeof(struct control_leader) &&
162: (m = m_pullup(m, sizeof(struct control_leader))) == 0)
163: return;
164: cp = mtod(m, struct control_leader *);
165: if (cp->dl_mtype == IMPTYPE_DATA)
166: if (m->m_len < sizeof(struct imp_leader) &&
167: (m = m_pullup(m, sizeof(struct imp_leader))) == 0)
168: return;
169: ip = mtod(m, struct imp_leader *);
170: #ifdef IMPLEADERS
171: if (impprintfs)
172: printleader("impinput", ip);
173: #endif
174:
175: /* check leader type */
176: if (ip->il_format != IMP_NFF) {
177: sc->imp_if.if_collisions++; /* XXX */
178: goto drop;
179: }
180:
181: if (ip->il_mtype != IMPTYPE_DATA) {
182: #ifdef notdef
183: addr.s_net = ip->il_network;
184: #else
185: addr.s_net = sc->imp_if.if_net;
186: #endif
187: addr.s_imp = ip->il_imp;
188: addr.s_host = ip->il_host;
189: }
190: switch (ip->il_mtype) {
191:
192: case IMPTYPE_DATA:
193: break;
194:
195: /*
196: * IMP leader error. Reset the IMP and discard the packet.
197: */
198: case IMPTYPE_BADLEADER:
199: /*
200: * According to 1822 document, this message
201: * will be generated in response to the
202: * first noop sent to the IMP after
203: * the host resets the IMP interface.
204: */
205: if (sc->imp_state != IMPS_INIT) {
206: impmsg(sc, "leader error");
207: hostreset(sc->imp_if.if_net);
208: impnoops(sc);
209: }
210: goto drop;
211:
212: /*
213: * IMP going down. Print message, and if not immediate,
214: * set off a timer to insure things will be reset at the
215: * appropriate time.
216: */
217: case IMPTYPE_DOWN:
218: if (sc->imp_state < IMPS_INIT)
219: goto drop;
220: if ((ip->il_link & IMP_DMASK) == 0) {
221: sc->imp_state = IMPS_GOINGDOWN;
222: timeout(impdown, (caddr_t)sc, 30 * hz);
223: }
224: impmsg(sc, "going down %s",
225: (u_int)impmessage[ip->il_link&IMP_DMASK]);
226: goto drop;
227:
228: /*
229: * A NOP usually seen during the initialization sequence.
230: * Compare the local address with that in the message.
231: * Reset the local address notion if it doesn't match.
232: */
233: case IMPTYPE_NOOP:
234: if (sc->imp_state == IMPS_DOWN) {
235: sc->imp_state = IMPS_INIT;
236: sc->imp_dropcnt = IMP_DROPCNT;
237: }
238: if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt > 0)
239: goto drop;
240: sin = (struct sockaddr_in *)&sc->imp_if.if_addr;
241: if (sin->sin_addr.s_host != ip->il_host ||
242: sin->sin_addr.s_imp != ip->il_imp) {
243: sc->imp_if.if_host[0] =
244: sin->sin_addr.s_host = ip->il_host;
245: sin->sin_addr.s_imp = ip->il_imp;
246: impmsg(sc, "reset (host %d/imp %d)", (u_int)ip->il_host,
247: ntohs(ip->il_imp));
248: }
249: sc->imp_state = IMPS_UP;
250: sc->imp_if.if_flags |= IFF_UP;
251: if_rtinit(&sc->imp_if, RTF_UP);
252: goto drop;
253:
254: /*
255: * RFNM or INCOMPLETE message, send next
256: * message on the q. We could pass incomplete's
257: * up to the next level, but this currently isn't
258: * needed.
259: */
260: case IMPTYPE_RFNM:
261: case IMPTYPE_INCOMPLETE:
262: if (hp = hostlookup(addr)) {
263: if (hp->h_rfnm == 0)
264: hp->h_flags &= ~HF_INUSE;
265: else if (next = hostdeque(hp))
266: (void) impsnd(&sc->imp_if, next);
267: }
268: goto drop;
269:
270: /*
271: * Host or IMP can't be reached. Flush any packets
272: * awaiting transmission and release the host structure.
273: */
274: case IMPTYPE_HOSTDEAD:
275: case IMPTYPE_HOSTUNREACH:
276: impnotify((int)ip->il_mtype, (struct control_leader *)ip,
277: hostlookup(addr));
278: goto rawlinkin;
279:
280: /*
281: * Error in data. Clear RFNM status for this host and send
282: * noops to the IMP to clear the interface.
283: */
284: case IMPTYPE_BADDATA:
285: impmsg(sc, "data error");
286: if (hp = hostlookup(addr))
287: hp->h_rfnm = 0;
288: impnoops(sc);
289: goto drop;
290:
291: /*
292: * Interface reset.
293: */
294: case IMPTYPE_RESET:
295: impmsg(sc, "interface reset");
296: impnoops(sc);
297: goto drop;
298:
299: default:
300: sc->imp_if.if_collisions++; /* XXX */
301: goto drop;
302: }
303:
304: /*
305: * Data for a protocol. Dispatch to the appropriate
306: * protocol routine (running at software interrupt).
307: * If this isn't a raw interface, advance pointer
308: * into mbuf past leader.
309: */
310: switch (ip->il_link) {
311:
312: #ifdef INET
313: case IMPLINK_IP:
314: m->m_len -= sizeof(struct imp_leader);
315: m->m_off += sizeof(struct imp_leader);
316: schednetisr(NETISR_IP);
317: inq = &ipintrq;
318: break;
319: #endif
320:
321: default:
322: rawlinkin:
323: impproto.sp_protocol = ip->il_link;
324: sin = (struct sockaddr_in *)&sc->imp_if.if_addr;
325: impdst.sin_addr = sin->sin_addr;;
326: impsrc.sin_addr.s_net = ip->il_network;
327: impsrc.sin_addr.s_host = ip->il_host;
328: impsrc.sin_addr.s_imp = ip->il_imp;
329: raw_input(m, &impproto, (struct sockaddr *)&impsrc,
330: (struct sockaddr *)&impdst);
331: return;
332: }
333: if (IF_QFULL(inq)) {
334: IF_DROP(inq);
335: goto drop;
336: }
337: IF_ENQUEUE(inq, m);
338: return;
339:
340: drop:
341: m_freem(m);
342: }
343:
344: /*
345: * Bring the IMP down after notification.
346: */
347: impdown(sc)
348: struct imp_softc *sc;
349: {
350: int s = splimp();
351:
352: sc->imp_state = IMPS_DOWN;
353: impmsg(sc, "marked down");
354: hostreset(sc->imp_if.if_net);
355: if_down(&sc->imp_if);
356: splx(s);
357: }
358:
359: /*VARARGS*/
360: impmsg(sc, fmt, a1, a2)
361: struct imp_softc *sc;
362: char *fmt;
363: u_int a1;
364: {
365:
366: printf("imp%d: ", sc->imp_if.if_unit);
367: printf(fmt, a1, a2);
368: printf("\n");
369: }
370:
371: /*
372: * Process an IMP "error" message, passing this
373: * up to the higher level protocol.
374: */
375: impnotify(what, cp, hp)
376: int what;
377: struct control_leader *cp;
378: struct host *hp;
379: {
380: struct in_addr in;
381:
382: #ifdef notdef
383: in.s_net = cp->dl_network;
384: #else
385: in.s_net = 10; /* XXX */
386: #endif
387: in.s_host = cp->dl_host;
388: in.s_imp = cp->dl_imp;
389: if (cp->dl_link != IMPLINK_IP)
390: raw_ctlinput(what, (caddr_t)&in);
391: else
392: ip_ctlinput(what, (caddr_t)&in);
393: if (hp) {
394: hp->h_flags |= (1 << what);
395: hostfree(hp);
396: }
397: }
398:
399: /*
400: * ARPAnet 1822 output routine.
401: * Called from higher level protocol routines to set up messages for
402: * transmission to the imp. Sets up the header and calls impsnd to
403: * enqueue the message for this IMP's hardware driver.
404: */
405: impoutput(ifp, m0, dst)
406: register struct ifnet *ifp;
407: struct mbuf *m0;
408: struct sockaddr *dst;
409: {
410: register struct imp_leader *imp;
411: register struct mbuf *m = m0;
412: int dhost, dimp, dlink, len, dnet;
413: int error = 0;
414:
415: /*
416: * Don't even try if the IMP is unavailable.
417: */
418: if (imp_softc[ifp->if_unit].imp_state != IMPS_UP) {
419: error = ENETDOWN;
420: goto drop;
421: }
422:
423: switch (dst->sa_family) {
424:
425: #ifdef INET
426: case AF_INET: {
427: struct ip *ip = mtod(m0, struct ip *);
428: struct sockaddr_in *sin = (struct sockaddr_in *)dst;
429:
430: dhost = sin->sin_addr.s_host;
431: dimp = sin->sin_addr.s_impno;
432: dlink = IMPLINK_IP;
433: dnet = 0;
434: len = ntohs((u_short)ip->ip_len);
435: break;
436: }
437: #endif
438: case AF_IMPLINK:
439: goto leaderexists;
440:
441: default:
442: printf("imp%d: can't handle af%d\n", ifp->if_unit,
443: dst->sa_family);
444: error = EAFNOSUPPORT;
445: goto drop;
446: }
447:
448: /*
449: * Add IMP leader. If there's not enough space in the
450: * first mbuf, allocate another. If that should fail, we
451: * drop this sucker.
452: */
453: if (m->m_off > MMAXOFF ||
454: MMINOFF + sizeof(struct imp_leader) > m->m_off) {
455: m = m_get(M_DONTWAIT, MT_HEADER);
456: MBUFNULL(3, m); /* for debugging */
457: if (m == 0) {
458: error = ENOBUFS;
459: goto drop;
460: }
461: m->m_next = m0;
462: m->m_len = sizeof(struct imp_leader);
463: } else {
464: m->m_off -= sizeof(struct imp_leader);
465: m->m_len += sizeof(struct imp_leader);
466: }
467: imp = mtod(m, struct imp_leader *);
468: imp->il_format = IMP_NFF;
469: imp->il_mtype = IMPTYPE_DATA;
470: imp->il_network = dnet;
471: imp->il_host = dhost;
472: imp->il_imp = htons((u_short)dimp);
473: imp->il_length =
474: htons((u_short)(len + sizeof(struct imp_leader)) << 3);
475: imp->il_link = dlink;
476: imp->il_flags = imp->il_htype = imp->il_subtype = 0;
477:
478: leaderexists:
479: return (impsnd(ifp, m));
480: drop:
481: m_freem(m0);
482: return (error);
483: }
484:
485: /*
486: * Put a message on an interface's output queue.
487: * Perform RFNM counting: no more than 8 message may be
488: * in flight to any one host.
489: */
490: impsnd(ifp, m)
491: struct ifnet *ifp;
492: struct mbuf *m;
493: {
494: register struct imp_leader *ip;
495: register struct host *hp;
496: struct impcb *icp;
497: int s, error;
498:
499: ip = mtod(m, struct imp_leader *);
500:
501: /*
502: * Do RFNM counting for data messages
503: * (no more than 8 outstanding to any host)
504: */
505: s = splimp();
506: if (ip->il_mtype == IMPTYPE_DATA) {
507: struct in_addr addr;
508:
509: #ifdef notdef
510: addr.s_net = ip->il_network;
511: #else
512: addr.s_net = ifp->if_net; /* XXX */
513: #endif
514: addr.s_host = ip->il_host;
515: addr.s_imp = ip->il_imp;
516: if ((hp = hostlookup(addr)) == 0)
517: hp = hostenter(addr);
518: if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) {
519: error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH;
520: hp->h_timer = HOSTTIMER;
521: hp->h_flags &= ~HF_INUSE;
522: goto bad;
523: }
524:
525: /*
526: * If IMP would block, queue until RFNM
527: */
528: if (hp) {
529: if (hp->h_rfnm < 8) {
530: hp->h_rfnm++;
531: goto enque;
532: }
533: if (hp->h_qcnt < 8) { /* high water mark */
534: HOST_ENQUE(hp, m);
535: goto start;
536: }
537: }
538: error = ENOBUFS;
539: goto bad;
540: }
541: enque:
542: if (IF_QFULL(&ifp->if_snd)) {
543: IF_DROP(&ifp->if_snd);
544: error = ENOBUFS;
545: bad:
546: m_freem(m);
547: splx(s);
548: return (error);
549: }
550: IF_ENQUEUE(&ifp->if_snd, m);
551: start:
552: icp = &imp_softc[ifp->if_unit].imp_cb;
553: if (icp->ic_oactive == 0)
554: (*icp->ic_start)(ifp->if_unit);
555: splx(s);
556: return (0);
557: }
558:
559: /*
560: * Put three 1822 NOOPs at the head of the output queue.
561: * Part of host-IMP initialization procedure.
562: * (Should return success/failure, but noone knows
563: * what to do with this, so why bother?)
564: * This routine is always called at splimp, so we don't
565: * protect the call to IF_PREPEND.
566: */
567: impnoops(sc)
568: register struct imp_softc *sc;
569: {
570: register i;
571: register struct mbuf *m;
572: register struct control_leader *cp;
573:
574: sc->imp_dropcnt = IMP_DROPCNT;
575: for (i = 0; i < IMP_DROPCNT + 1; i++ ) {
576: m = m_getclr(M_DONTWAIT, MT_HEADER);
577: MBUFNULL(4, m); /* for debugging */
578: if (m == 0)
579: return;
580: m->m_len = sizeof(struct control_leader);
581: cp = mtod(m, struct control_leader *);
582: cp->dl_format = IMP_NFF;
583: cp->dl_link = i;
584: cp->dl_mtype = IMPTYPE_NOOP;
585: IF_PREPEND(&sc->imp_if.if_snd, m);
586: }
587: if (sc->imp_cb.ic_oactive == 0)
588: (*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
589: }
590:
591: /*
592: * Process an ioctl request.
593: */
594: impioctl(ifp, cmd, data)
595: register struct ifnet *ifp;
596: int cmd;
597: caddr_t data;
598: {
599: struct ifreq *ifr = (struct ifreq *)data;
600: struct sockaddr_in *sin;
601: int s = splimp(), error = 0;
602:
603: switch (cmd) {
604:
605: case SIOCSIFADDR:
606: if (ifp->if_flags & IFF_RUNNING)
607: if_rtinit(ifp, -1); /* delete previous route */
608: sin = (struct sockaddr_in *)&ifr->ifr_addr;
609: ifp->if_net = in_netof(sin->sin_addr);
610: sin = (struct sockaddr_in *)&ifp->if_addr;
611: sin->sin_family = AF_INET;
612: /* host number filled in already, or filled in later */
613: sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
614: if (ifp->if_flags & IFF_RUNNING)
615: if_rtinit(ifp, RTF_UP);
616: else
617: impinit(ifp->if_unit);
618: break;
619:
620: default:
621: error = EINVAL;
622: }
623: splx(s);
624: return (error);
625: }
626:
627: #ifdef IMPLEADERS
628: printleader(routine, ip)
629: char *routine;
630: register struct imp_leader *ip;
631: {
632: printf("%s: ", routine);
633: printbyte((char *)ip, 12);
634: printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
635: ip->il_flags);
636: if (ip->il_mtype <= IMPTYPE_READY)
637: printf("%s,", impleaders[ip->il_mtype]);
638: else
639: printf("%x,", ip->il_mtype);
640: printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
641: ntohs(ip->il_imp));
642: if (ip->il_link == IMPLINK_IP)
643: printf("ip,");
644: else
645: printf("%x,", ip->il_link);
646: printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
647: }
648:
649: printbyte(cp, n)
650: register char *cp;
651: int n;
652: {
653: register i, j, c;
654:
655: for (i=0; i<n; i++) {
656: c = *cp++;
657: for (j=0; j<2; j++)
658: putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
659: putchar(' ');
660: }
661: putchar('\n');
662: }
663: #endif
664: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.