|
|
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 "../vax/cpu.h"
28: #include "../vax/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: struct uba_device *ui;
88: int (*reset)();
89: {
90: struct imp_softc *sc = &imp_softc[ui->ui_unit];
91: register struct ifnet *ifp = &sc->imp_if;
92:
93: /* UNIT COULD BE AMBIGUOUS */
94: ifp->if_unit = ui->ui_unit;
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: if (m == 0) {
457: error = ENOBUFS;
458: goto drop;
459: }
460: m->m_next = m0;
461: m->m_len = sizeof(struct imp_leader);
462: } else {
463: m->m_off -= sizeof(struct imp_leader);
464: m->m_len += sizeof(struct imp_leader);
465: }
466: imp = mtod(m, struct imp_leader *);
467: imp->il_format = IMP_NFF;
468: imp->il_mtype = IMPTYPE_DATA;
469: imp->il_network = dnet;
470: imp->il_host = dhost;
471: imp->il_imp = htons((u_short)dimp);
472: imp->il_length =
473: htons((u_short)(len + sizeof(struct imp_leader)) << 3);
474: imp->il_link = dlink;
475: imp->il_flags = imp->il_htype = imp->il_subtype = 0;
476:
477: leaderexists:
478: return (impsnd(ifp, m));
479: drop:
480: m_freem(m0);
481: return (error);
482: }
483:
484: /*
485: * Put a message on an interface's output queue.
486: * Perform RFNM counting: no more than 8 message may be
487: * in flight to any one host.
488: */
489: impsnd(ifp, m)
490: struct ifnet *ifp;
491: struct mbuf *m;
492: {
493: register struct imp_leader *ip;
494: register struct host *hp;
495: struct impcb *icp;
496: int s, error;
497:
498: ip = mtod(m, struct imp_leader *);
499:
500: /*
501: * Do RFNM counting for data messages
502: * (no more than 8 outstanding to any host)
503: */
504: s = splimp();
505: if (ip->il_mtype == IMPTYPE_DATA) {
506: struct in_addr addr;
507:
508: #ifdef notdef
509: addr.s_net = ip->il_network;
510: #else
511: addr.s_net = ifp->if_net; /* XXX */
512: #endif
513: addr.s_host = ip->il_host;
514: addr.s_imp = ip->il_imp;
515: if ((hp = hostlookup(addr)) == 0)
516: hp = hostenter(addr);
517: if (hp && (hp->h_flags & (HF_DEAD|HF_UNREACH))) {
518: error = hp->h_flags&HF_DEAD ? EHOSTDOWN : EHOSTUNREACH;
519: hp->h_timer = HOSTTIMER;
520: hp->h_flags &= ~HF_INUSE;
521: goto bad;
522: }
523:
524: /*
525: * If IMP would block, queue until RFNM
526: */
527: if (hp) {
528: if (hp->h_rfnm < 8) {
529: hp->h_rfnm++;
530: goto enque;
531: }
532: if (hp->h_qcnt < 8) { /* high water mark */
533: HOST_ENQUE(hp, m);
534: goto start;
535: }
536: }
537: error = ENOBUFS;
538: goto bad;
539: }
540: enque:
541: if (IF_QFULL(&ifp->if_snd)) {
542: IF_DROP(&ifp->if_snd);
543: error = ENOBUFS;
544: bad:
545: m_freem(m);
546: splx(s);
547: return (error);
548: }
549: IF_ENQUEUE(&ifp->if_snd, m);
550: start:
551: icp = &imp_softc[ifp->if_unit].imp_cb;
552: if (icp->ic_oactive == 0)
553: (*icp->ic_start)(ifp->if_unit);
554: splx(s);
555: return (0);
556: }
557:
558: /*
559: * Put three 1822 NOOPs at the head of the output queue.
560: * Part of host-IMP initialization procedure.
561: * (Should return success/failure, but noone knows
562: * what to do with this, so why bother?)
563: * This routine is always called at splimp, so we don't
564: * protect the call to IF_PREPEND.
565: */
566: impnoops(sc)
567: register struct imp_softc *sc;
568: {
569: register i;
570: register struct mbuf *m;
571: register struct control_leader *cp;
572:
573: sc->imp_dropcnt = IMP_DROPCNT;
574: for (i = 0; i < IMP_DROPCNT + 1; i++ ) {
575: if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0)
576: return;
577: m->m_len = sizeof(struct control_leader);
578: cp = mtod(m, struct control_leader *);
579: cp->dl_format = IMP_NFF;
580: cp->dl_link = i;
581: cp->dl_mtype = IMPTYPE_NOOP;
582: IF_PREPEND(&sc->imp_if.if_snd, m);
583: }
584: if (sc->imp_cb.ic_oactive == 0)
585: (*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
586: }
587:
588: /*
589: * Process an ioctl request.
590: */
591: impioctl(ifp, cmd, data)
592: register struct ifnet *ifp;
593: int cmd;
594: caddr_t data;
595: {
596: struct ifreq *ifr = (struct ifreq *)data;
597: struct sockaddr_in *sin;
598: int s = splimp(), error = 0;
599:
600: switch (cmd) {
601:
602: case SIOCSIFADDR:
603: if (ifp->if_flags & IFF_RUNNING)
604: if_rtinit(ifp, -1); /* delete previous route */
605: sin = (struct sockaddr_in *)&ifr->ifr_addr;
606: ifp->if_net = in_netof(sin->sin_addr);
607: sin = (struct sockaddr_in *)&ifp->if_addr;
608: sin->sin_family = AF_INET;
609: /* host number filled in already, or filled in later */
610: sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
611: if (ifp->if_flags & IFF_RUNNING)
612: if_rtinit(ifp, RTF_UP);
613: else
614: impinit(ifp->if_unit);
615: break;
616:
617: default:
618: error = EINVAL;
619: }
620: splx(s);
621: return (error);
622: }
623:
624: #ifdef IMPLEADERS
625: printleader(routine, ip)
626: char *routine;
627: register struct imp_leader *ip;
628: {
629: printf("%s: ", routine);
630: printbyte((char *)ip, 12);
631: printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
632: ip->il_flags);
633: if (ip->il_mtype <= IMPTYPE_READY)
634: printf("%s,", impleaders[ip->il_mtype]);
635: else
636: printf("%x,", ip->il_mtype);
637: printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
638: ntohs(ip->il_imp));
639: if (ip->il_link == IMPLINK_IP)
640: printf("ip,");
641: else
642: printf("%x,", ip->il_link);
643: printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
644: }
645:
646: printbyte(cp, n)
647: register char *cp;
648: int n;
649: {
650: register i, j, c;
651:
652: for (i=0; i<n; i++) {
653: c = *cp++;
654: for (j=0; j<2; j++)
655: putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf]);
656: putchar(' ');
657: }
658: putchar('\n');
659: }
660: #endif
661: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.