|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted
6: * provided that the above copyright notice and this paragraph are
7: * duplicated in all such forms and that any documentation,
8: * advertising materials, and other materials related to such
9: * distribution and use acknowledge that the software was developed
10: * by the University of California, Berkeley. The name of the
11: * University may not be used to endorse or promote products derived
12: * from this software without specific prior written permission.
13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16: *
17: * @(#)if_imp.c 7.8 (Berkeley) 6/29/88
18: */
19:
20: #include "imp.h"
21: #if NIMP > 0
22: /*
23: * ARPANET IMP (PSN) interface driver.
24: *
25: * The IMP-host protocol (AHIP) is handled here, leaving
26: * hardware specifics to the lower level interface driver.
27: */
28: #include "param.h"
29: #include "systm.h"
30: #include "mbuf.h"
31: #include "buf.h"
32: #include "protosw.h"
33: #include "socket.h"
34: #include "time.h"
35: #include "kernel.h"
36: #include "errno.h"
37: #include "ioctl.h"
38: #include "syslog.h"
39:
40: #include "../machine/mtpr.h"
41:
42: #include "../net/if.h"
43: #include "../net/netisr.h"
44: #include "../netinet/in.h"
45: #include "../netinet/in_systm.h"
46: #include "../netinet/in_var.h"
47: #include "../netinet/ip.h"
48: #include "../netinet/ip_var.h"
49: #define IMPMESSAGES
50: /* define IMPLEADERS here to get leader printing code */
51: #include "if_imp.h"
52: #include "if_imphost.h"
53:
54: struct imp_softc imp_softc[NIMP];
55: #ifndef lint
56: int nimp = NIMP; /* for netstat */
57: #endif
58: struct ifqueue impintrq;
59: int impqmaxlen = IFQ_MAXLEN;
60: int imphqlen = 12 + IMP_MAXHOSTMSG; /* max packets to queue per host */
61:
62: int imppri = LOG_ERR;
63: #ifdef IMPLEADERS
64: int impprintfs = 0;
65: #endif
66: #ifdef IMPINIT
67: int imptraceinit = 0;
68: #endif
69:
70:
71: #define HOSTDEADTIMER (30 * PR_SLOWHZ) /* How long to wait when down */
72:
73: int impdown(), impinit(), impioctl(), impoutput(), imptimo();
74:
75: /*
76: * IMP attach routine. Called from hardware device attach routine
77: * at configuration time with a pointer to the device structure.
78: * Sets up local state and returns pointer to base of ifnet+impcb
79: * structures. This is then used by the device's attach routine
80: * set up its back pointers.
81: */
82: struct imp_softc *
83: impattach(hwname, hwunit, reset)
84: char *hwname;
85: int hwunit;
86: int (*reset)();
87: {
88: struct imp_softc *sc;
89: register struct ifnet *ifp;
90: static int impunit;
91:
92: #ifdef lint
93: impintr();
94: #endif
95: if (impunit >= NIMP) {
96: printf("imp%d: not configured\n", impunit++);
97: return (0);
98: }
99: sc = &imp_softc[impunit];
100: ifp = &sc->imp_if;
101: sc->imp_cb.ic_hwname = hwname;
102: sc->imp_cb.ic_hwunit = hwunit;
103: ifp->if_unit = impunit;
104: ifp->if_name = "imp";
105: ifp->if_mtu = IMPMTU - sizeof(struct imp_leader);
106: ifp->if_reset = reset;
107: ifp->if_init = impinit;
108: ifp->if_ioctl = impioctl;
109: ifp->if_output = impoutput;
110: ifp->if_watchdog = imptimo;
111: if_attach(ifp);
112: impunit++;
113: return (sc);
114: }
115:
116: /*
117: * IMP initialization routine: call hardware module to
118: * setup resources, init state and get ready for
119: * NOOPs the IMP should send us, and that we want to drop.
120: */
121: impinit(unit)
122: int unit;
123: {
124: int s;
125: register struct imp_softc *sc = &imp_softc[unit];
126:
127: if (sc->imp_if.if_addrlist == 0)
128: return;
129: s = splimp();
130: #ifdef IMPINIT
131: if (imptraceinit)
132: log(imppri, "impinit\n");
133: #endif
134: sc->imp_state = IMPS_WINIT;
135: if ((*sc->imp_cb.ic_init)(sc->imp_cb.ic_hwunit) == 0)
136: sc->imp_if.if_flags &= ~IFF_UP;
137: impintrq.ifq_maxlen = impqmaxlen;
138: splx(s);
139: }
140:
141: /*
142: * ARPAnet 1822/AHIP input routine.
143: * Called from hardware input interrupt routine to handle 1822
144: * IMP-host messages. Data messages are passed to higher-level
145: * protocol processors on the basis of link number.
146: * Other type messages (control) are handled here.
147: */
148: impinput(unit, m)
149: int unit;
150: register struct mbuf *m;
151: {
152: register struct control_leader *cp;
153: #define ip ((struct imp_leader *)cp)
154: register struct imp_softc *sc = &imp_softc[unit];
155: struct ifnet *ifp;
156: register struct host *hp;
157: register struct ifqueue *inq;
158: struct sockaddr_in *sin;
159: int s;
160:
161: /*
162: * Pull the interface pointer out of the mbuf
163: * and save for later; adjust mbuf to look at rest of data.
164: */
165: ifp = *(mtod(m, struct ifnet **));
166: IF_ADJ(m);
167: /* verify leader length. */
168: if (m->m_len < sizeof(struct control_leader) &&
169: (m = m_pullup(m, sizeof(struct control_leader))) == 0)
170: return;
171: cp = mtod(m, struct control_leader *);
172: if (cp->dl_mtype == IMPTYPE_DATA &&
173: m->m_len < sizeof(struct imp_leader)) {
174: if ((m = m_pullup(m, sizeof(struct imp_leader))) == 0)
175: return;
176: cp = mtod(m, struct control_leader *);
177: }
178: #ifdef IMPLEADERS
179: if (impprintfs)
180: printleader("impinput", ip);
181: #endif
182: inq = &impintrq;
183:
184: /* check leader type */
185: if (cp->dl_format != IMP_NFF) {
186: /*
187: * We get 1822L NOOPs and RESET
188: * at initialization.
189: */
190: #ifdef IMPINIT
191: if (imptraceinit)
192: log(imppri, "input, format %x mtype %d\n",
193: cp->dl_format, cp->dl_mtype);
194: #endif
195: if (cp->dl_format != IMP_1822L_I2H ||
196: (cp->dl_mtype != IMPTYPE_NOOP &&
197: cp->dl_mtype != IMPTYPE_RESET)) {
198: sc->imp_garbage++;
199: sc->imp_if.if_collisions++; /* XXX */
200: }
201: } else switch (cp->dl_mtype) {
202:
203: case IMPTYPE_DATA:
204: /*
205: * Data for a protocol. Dispatch to the appropriate
206: * protocol routine (running at software interrupt).
207: * If this isn't a raw interface, advance pointer
208: * into mbuf past leader.
209: */
210: switch (cp->dl_link) {
211:
212: case IMPLINK_IP:
213: m->m_len -= sizeof(struct imp_leader);
214: m->m_off += sizeof(struct imp_leader);
215: schednetisr(NETISR_IP);
216: inq = &ipintrq;
217: break;
218:
219: default:
220: break;
221: }
222: break;
223:
224: /*
225: * IMP leader error. Reset the IMP and discard the packet.
226: */
227: case IMPTYPE_BADLEADER:
228: /*
229: * According to 1822 document, this message
230: * will be generated in response to the
231: * first noop sent to the IMP after
232: * the host resets the IMP interface.
233: */
234: #ifdef IMPINIT
235: if (imptraceinit)
236: log(imppri, "badleader\n");
237: #endif
238: if (sc->imp_state != IMPS_INIT) {
239: impmsg(sc, "leader error");
240: sc->imp_msgready = 0;
241: hostreset(unit);
242: impnoops(sc);
243: sc->imp_garbage++;
244: }
245: break;
246:
247: /*
248: * IMP going down. Print message, and if not immediate,
249: * set off a timer to insure things will be reset at the
250: * appropriate time.
251: */
252: case IMPTYPE_DOWN:
253: { int type, when;
254:
255: type = cp->dl_link & IMP_DMASK;
256: when = (cp->dl_link & IMPDOWN_WHENMASK) >> IMPDOWN_WHENSHIFT;
257: #ifdef IMPINIT
258: if (imptraceinit)
259: log(imppri, "input DOWN %s %d\n",
260: impmessage[type], when * IMPDOWN_WHENUNIT);
261: #endif
262: if (type != IMPDOWN_GOING && when)
263: impmsg(sc, "going down %s in %d minutes",
264: (u_int)impmessage[type], when * IMPDOWN_WHENUNIT);
265: else
266: impmsg(sc, "going down %s", (u_int)impmessage[type]);
267: if (sc->imp_state != IMPS_UP)
268: break;
269: if (type == IMPDOWN_GOING) {
270: sc->imp_state = IMPS_GOINGDOWN;
271: timeout(impdown, (caddr_t)sc, IMPTV_DOWN * hz);
272: } else if (when == 0)
273: sc->imp_state = IMPS_WINIT;
274: sc->imp_dropcnt = 0;
275: break;
276: }
277:
278: /*
279: * A NOP, usually seen during the initialization sequence.
280: * Compare the local address with that in the message.
281: * Reset the local address notion if it doesn't match.
282: */
283: case IMPTYPE_NOOP:
284: #ifdef IMPINIT
285: if (imptraceinit)
286: log(imppri, "noop\n");
287: #endif
288: if (sc->imp_state == IMPS_WINIT) {
289: sc->imp_dropcnt = 0;
290: impnoops(sc);
291: sc->imp_state = IMPS_INIT;
292: }
293: sc->imp_dropcnt++;
294: if (sc->imp_state == IMPS_INIT && cp->dl_imp != 0) {
295: struct in_addr leader_addr;
296:
297: sin = (struct sockaddr_in *)&sc->imp_if.if_addrlist->ifa_addr;
298: imp_leader_to_addr(&leader_addr, cp, &sc->imp_if);
299: if (sin->sin_addr.s_addr != leader_addr.s_addr) {
300: impmsg(sc, "address reset to x%x (%d/%d)",
301: ntohl(leader_addr.s_addr),
302: (u_int)cp->dl_host,
303: ntohs(cp->dl_imp));
304: sin->sin_addr.s_addr = leader_addr.s_addr;
305: }
306: }
307: break;
308:
309: /*
310: * RFNM or INCOMPLETE message, decrement rfnm count
311: * and prepare to send next message.
312: * If the rfnm allows another queued
313: * message to be sent, bump msgready
314: * and start IMP if idle.
315: * We could pass incomplete's up to the next level,
316: * but this currently isn't needed.
317: * Pass "bad" incompletes and rfnms to the raw socket.
318: */
319: case IMPTYPE_INCOMPLETE:
320: sc->imp_incomplete++;
321: /* FALL THROUGH */
322: case IMPTYPE_RFNM:
323: if ((hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host,
324: unit)) == 0 || hp->h_rfnm == 0) {
325: sc->imp_badrfnm++;
326: if (hp)
327: hostfree(hp);
328: break;
329: }
330: imprestarthost(sc, hp);
331: if (cp->dl_mtype == IMPTYPE_RFNM)
332: goto drop;
333: break;
334:
335: /*
336: * Host or IMP can't be reached. Flush any packets
337: * awaiting transmission and release the host structure.
338: * Enqueue for notifying protocols at software interrupt time.
339: */
340: case IMPTYPE_HOSTDEAD:
341: case IMPTYPE_HOSTUNREACH:
342: if (hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, unit)) {
343: hp->h_flags |= (1 << (int)cp->dl_mtype);
344: sc->imp_msgready -=
345: MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm);
346: hp->h_rfnm = 0;
347: hostflush(hp);
348: hp->h_timer = HOSTDEADTIMER;
349: }
350: break;
351:
352: /*
353: * Error in data. Clear RFNM status for this host and send
354: * noops to the IMP to clear the interface.
355: */
356: case IMPTYPE_BADDATA:
357: impmsg(sc, "data error");
358: if (hp = hostlookup((int)cp->dl_imp, (int)cp->dl_host, unit)) {
359: sc->imp_msgready -=
360: MIN(hp->h_qcnt, IMP_MAXHOSTMSG - hp->h_rfnm);
361: if (hp->h_rfnm)
362: hostrelease(hp);
363: else
364: hostfree(hp);
365: }
366: impnoops(sc);
367: break;
368:
369: /*
370: * Interface reset.
371: */
372: case IMPTYPE_RESET:
373: #ifdef IMPINIT
374: if (imptraceinit)
375: log(imppri, "reset complete\n");
376: #endif
377: if (sc->imp_state != IMPS_INIT) {
378: impmsg(sc, "interface reset");
379: impnoops(sc);
380: }
381: /* clear RFNM counts */
382: sc->imp_msgready = 0;
383: hostreset(unit);
384: if (sc->imp_state != IMPS_DOWN) {
385: sc->imp_state = IMPS_UP;
386: sc->imp_if.if_flags |= IFF_UP;
387: #ifdef IMPINIT
388: if (imptraceinit)
389: log(imppri, "IMP UP\n");
390: #endif
391: }
392: break;
393:
394: default:
395: sc->imp_garbage++;
396: sc->imp_if.if_collisions++; /* XXX */
397: break;
398: }
399:
400: if (inq == &impintrq)
401: schednetisr(NETISR_IMP);
402: /*
403: * Re-insert interface pointer in the mbuf chain
404: * for the next protocol up.
405: */
406: if (M_HASCL(m) && (mtod(m, int) & CLOFSET) < sizeof(struct ifnet *)) {
407: struct mbuf *n;
408:
409: MGET(n, M_DONTWAIT, MT_HEADER);
410: if (n == 0)
411: goto drop;
412: n->m_next = m;
413: m = n;
414: m->m_len = 0;
415: m->m_off = MMINOFF + sizeof(struct ifnet *);
416: }
417: m->m_off -= sizeof(struct ifnet *);
418: m->m_len += sizeof(struct ifnet *);
419: *(mtod(m, struct ifnet **)) = ifp;
420:
421: s = splimp();
422: if (!IF_QFULL(inq)) {
423: IF_ENQUEUE(inq, m);
424: splx(s);
425: return;
426: }
427: splx(s);
428: IF_DROP(inq);
429: drop:
430: m_freem(m);
431: #undef ip
432: }
433:
434: /*
435: * Bring the IMP down after notification.
436: */
437: impdown(sc)
438: struct imp_softc *sc;
439: {
440: int s = splimp();
441:
442: if (sc->imp_state == IMPS_GOINGDOWN) {
443: sc->imp_state = IMPS_WINIT;
444: impmsg(sc, "marked down");
445: sc->imp_msgready = 0;
446: hostreset(sc->imp_if.if_unit);
447: if_down(&sc->imp_if);
448: }
449: #ifdef IMPINIT
450: else if (imptraceinit)
451: log(imppri, "impdown, state now %d (ignored)\n", sc->imp_state);
452: #endif
453: splx(s);
454: }
455:
456: /*VARARGS2*/
457: impmsg(sc, fmt, a1)
458: struct imp_softc *sc;
459: char *fmt;
460: u_int a1;
461: {
462:
463: log(imppri, "imp%d: %r\n", sc->imp_if.if_unit, fmt, &a1);
464: }
465:
466: struct sockproto impproto = { PF_IMPLINK };
467: struct sockaddr_in impdst = { AF_IMPLINK };
468: struct sockaddr_in impsrc = { AF_IMPLINK };
469:
470: /*
471: * Pick up the IMP "error" messages enqueued earlier,
472: * passing these up to the higher level protocol
473: * and the raw interface.
474: */
475: impintr()
476: {
477: register struct mbuf *m;
478: register struct control_leader *cp;
479: struct ifnet *ifp;
480: int s;
481:
482: for (;;) {
483: s = splimp();
484: IF_DEQUEUEIF(&impintrq, m, ifp);
485: splx(s);
486: if (m == 0)
487: return;
488:
489: cp = mtod(m, struct control_leader *);
490: imp_leader_to_addr(&impsrc.sin_addr, cp, ifp);
491: impproto.sp_protocol = cp->dl_link;
492: impdst.sin_addr = IA_SIN(ifp->if_addrlist)->sin_addr;
493:
494: if (cp->dl_mtype == IMPTYPE_HOSTDEAD ||
495: cp->dl_mtype == IMPTYPE_HOSTUNREACH)
496: switch (cp->dl_link) {
497:
498: case IMPLINK_IP:
499: pfctlinput((int)cp->dl_mtype,
500: (struct sockaddr *)&impsrc);
501: break;
502: default:
503: raw_ctlinput((int)cp->dl_mtype,
504: (struct sockaddr *)&impsrc);
505: break;
506: }
507:
508: raw_input(m, &impproto, (struct sockaddr *)&impsrc,
509: (struct sockaddr *)&impdst);
510: }
511: }
512:
513: /*
514: * ARPAnet 1822 output routine.
515: * Called from higher level protocol routines to set up messages for
516: * transmission to the imp. Sets up the header and calls impsnd to
517: * enqueue the message for this IMP's hardware driver.
518: */
519: impoutput(ifp, m0, dst)
520: register struct ifnet *ifp;
521: struct mbuf *m0;
522: struct sockaddr *dst;
523: {
524: register struct imp_leader *imp;
525: register struct mbuf *m = m0;
526: caddr_t pkt = mtod(m, caddr_t);
527: int error = 0;
528:
529: /*
530: * Don't even try if the IMP is unavailable.
531: */
532: if (!IMPS_RUNNING(imp_softc[ifp->if_unit].imp_state)) {
533: error = ENETDOWN;
534: goto drop;
535: }
536:
537: /*
538: * If AF_IMPLINK, leader exists; just send.
539: * Otherwise, construct leader according to address family.
540: */
541: if (dst->sa_family != AF_IMPLINK) {
542: /*
543: * Add IMP leader. If there's not enough space in the
544: * first mbuf, allocate another. If that should fail, we
545: * drop this sucker.
546: */
547: if (m->m_off > MMAXOFF ||
548: MMINOFF + sizeof(struct imp_leader) > m->m_off) {
549: MGET(m, M_DONTWAIT, MT_HEADER);
550: if (m == 0) {
551: error = ENOBUFS;
552: goto drop;
553: }
554: m->m_next = m0;
555: m->m_len = sizeof(struct imp_leader);
556: } else {
557: m->m_off -= sizeof(struct imp_leader);
558: m->m_len += sizeof(struct imp_leader);
559: }
560: imp = mtod(m, struct imp_leader *);
561: imp->il_format = IMP_NFF;
562: imp->il_mtype = IMPTYPE_DATA;
563: imp->il_flags = 0;
564: imp->il_htype = 0;
565: imp->il_subtype = 0;
566:
567: switch (dst->sa_family) {
568:
569: case AF_INET:
570: imp->il_link = IMPLINK_IP;
571: imp_addr_to_leader((struct control_leader *)imp,
572: ((struct sockaddr_in *)dst)->sin_addr.s_addr);
573: imp->il_length = htons(ntohs((u_short)
574: ((struct ip *)pkt)->ip_len) << 3);
575: break;
576:
577: default:
578: printf("imp%d: can't handle af%d\n", ifp->if_unit,
579: dst->sa_family);
580: error = EAFNOSUPPORT;
581: m0 = m;
582: goto drop;
583: }
584: }
585: return (impsnd(ifp, m));
586: drop:
587: m_freem(m0);
588: return (error);
589: }
590:
591: /*
592: * Put a message on an interface's output queue.
593: * Perform RFNM counting: no more than 8 message may be
594: * in flight to any one host.
595: */
596: impsnd(ifp, m)
597: struct ifnet *ifp;
598: struct mbuf *m;
599: {
600: register struct control_leader *imp;
601: register struct host *hp;
602: register struct imp_softc *sc = &imp_softc[ifp->if_unit];
603: int s, error = 0;
604:
605: imp = mtod(m, struct control_leader *);
606:
607: /*
608: * Do RFNM counting for data messages
609: * (no more than 8 outstanding to any host).
610: * Queue data messages per host if 8 are already outstanding
611: * or if the hardware interface is already doing output.
612: * Increment imp_msgready if the message could be sent now,
613: * but must be queued because the imp output is busy.
614: */
615: s = splimp();
616: if (imp->dl_mtype == IMPTYPE_DATA) {
617: hp = hostenter((int)imp->dl_imp, (int)imp->dl_host,
618: ifp->if_unit);
619: if (hp) {
620: if (hp->h_flags & (HF_DEAD|HF_UNREACH))
621: error = hp->h_flags & HF_DEAD ?
622: EHOSTDOWN : EHOSTUNREACH;
623: else if (hp->h_rfnm < IMP_MAXHOSTMSG &&
624: sc->imp_cb.ic_oactive == 0) {
625: /*
626: * Send without queuing;
627: * adjust rfnm count and timer.
628: */
629: if (hp->h_rfnm++ == 0)
630: hp->h_timer = RFNMTIMER;
631: goto send;
632: } else if (hp->h_rfnm + hp->h_qcnt < imphqlen) {
633: HOST_ENQUE(hp, m);
634: if (hp->h_rfnm + hp->h_qcnt <= IMP_MAXHOSTMSG)
635: sc->imp_msgready++;
636: } else {
637: error = ENOBUFS;
638: IF_DROP(&ifp->if_snd);
639: }
640: } else
641: error = ENOBUFS;
642: } else if (sc->imp_cb.ic_oactive == 0)
643: goto send;
644: else
645: IF_ENQUEUE(&ifp->if_snd, m);
646:
647: splx(s);
648: if (error)
649: m_freem(m);
650: return (error);
651:
652: send:
653: sc->imp_if.if_timer = IMP_OTIMER;
654: (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
655: splx(s);
656: return (0);
657: }
658:
659: /*
660: * Start another output operation on IMP; called from hardware
661: * transmit-complete interrupt routine at splimp or from imp routines
662: * when output is not in progress. If there are any packets on shared
663: * output queue, send them, otherwise send the next data packet for a host.
664: * Host data packets are sent round-robin based on destination by walking
665: * the host list.
666: */
667: impstart(sc)
668: register struct imp_softc *sc;
669: {
670: register struct mbuf *m;
671: int first = 1; /* XXX */
672: register struct host *hp;
673: int index;
674:
675: IF_DEQUEUE(&sc->imp_if.if_snd, m);
676: if (m) {
677: sc->imp_if.if_timer = IMP_OTIMER;
678: (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
679: return;
680: }
681: if (sc->imp_msgready) {
682: if ((m = sc->imp_hostq) == 0 && (m = sc->imp_hosts) == 0)
683: panic("imp msgready");
684: index = sc->imp_hostent;
685: for (hp = &mtod(m, struct hmbuf *)->hm_hosts[index]; ;
686: hp++, index++) {
687: if (index >= HPMBUF) {
688: if ((m = m->m_next) == 0)
689: m = sc->imp_hosts;
690: index = 0;
691: hp = mtod(m, struct hmbuf *)->hm_hosts;
692: first = 0; /* XXX */
693: }
694: if (hp->h_qcnt && hp->h_rfnm < IMP_MAXHOSTMSG) {
695: /*
696: * Found host entry with another message
697: * to send. Deliver it to the IMP.
698: * Start with succeeding host next time.
699: */
700: impstarthost(sc, hp);
701: sc->imp_hostq = m;
702: sc->imp_hostent = index + 1;
703: return;
704: }
705: if (m == sc->imp_hostq && !first &&
706: index + 1 >= sc->imp_hostent) { /* XXX */
707: log(imppri, "imp: can't find %d msgready\n",
708: sc->imp_msgready);
709: sc->imp_msgready = 0;
710: break;
711: }
712: }
713: }
714: sc->imp_if.if_timer = 0;
715: }
716:
717: /*
718: * Restart output for a host that has received a RFNM
719: * or incomplete or has timed out while waiting for a RFNM.
720: * Must be called at splimp.
721: */
722: imprestarthost(sc, hp)
723: register struct imp_softc *sc;
724: struct host *hp;
725: {
726:
727: if (--hp->h_rfnm > 0)
728: hp->h_timer = RFNMTIMER;
729: /*
730: * If the RFNM moved a queued message into the window,
731: * update msgready and start IMP if idle.
732: */
733: if (hp->h_qcnt > IMP_MAXHOSTMSG - 1 - hp->h_rfnm) {
734: sc->imp_msgready++;
735: if (sc->imp_cb.ic_oactive == 0)
736: impstarthost(sc, hp);
737: }
738: if (hp->h_rfnm == 0 && hp->h_qcnt == 0)
739: hostidle(hp);
740: }
741:
742: /*
743: * Send the next message queued for a host
744: * when ready to send another message to the IMP.
745: * Called only when output is not in progress.
746: * Bump RFNM counter and start RFNM timer
747: * when we send the message to the IMP.
748: * Must be called at splimp.
749: */
750: impstarthost(sc, hp)
751: register struct imp_softc *sc;
752: register struct host *hp;
753: {
754: struct mbuf *m;
755:
756: if (hp->h_rfnm++ == 0)
757: hp->h_timer = RFNMTIMER;
758: HOST_DEQUE(hp, m);
759: sc->imp_if.if_timer = IMP_OTIMER;
760: (*sc->imp_cb.ic_output)(sc->imp_cb.ic_hwunit, m);
761: sc->imp_msgready--;
762: }
763:
764: /*
765: * "Watchdog" timeout. When the output timer expires,
766: * we assume we have been blocked by the imp.
767: * No need to restart, just collect statistics.
768: */
769: imptimo(unit)
770: int unit;
771: {
772:
773: imp_softc[unit].imp_block++;
774: }
775:
776: /*
777: * Put three 1822 NOOPs at the head of the output queue.
778: * Part of host-IMP initialization procedure.
779: * (Should return success/failure, but noone knows
780: * what to do with this, so why bother?)
781: * This routine is always called at splimp, so we don't
782: * protect the call to IF_PREPEND.
783: */
784: impnoops(sc)
785: register struct imp_softc *sc;
786: {
787: register i;
788: register struct mbuf *m;
789: register struct control_leader *cp;
790:
791: #ifdef IMPINIT
792: if (imptraceinit)
793: log(imppri, "impnoops\n");
794: #endif
795: for (i = 0; i < IMP_NOOPCNT; i++) {
796: if ((m = m_getclr(M_DONTWAIT, MT_HEADER)) == 0)
797: return;
798: m->m_len = sizeof(struct control_leader);
799: cp = mtod(m, struct control_leader *);
800: cp->dl_format = IMP_NFF;
801: cp->dl_link = i;
802: cp->dl_mtype = IMPTYPE_NOOP;
803: IF_PREPEND(&sc->imp_if.if_snd, m);
804: }
805: if (sc->imp_cb.ic_oactive == 0)
806: impstart(sc);
807: }
808:
809: /*
810: * Process an ioctl request.
811: */
812: impioctl(ifp, cmd, data)
813: register struct ifnet *ifp;
814: int cmd;
815: caddr_t data;
816: {
817: struct ifaddr *ifa = (struct ifaddr *) data;
818: int s = splimp(), error = 0;
819: #define sc ((struct imp_softc *)ifp)
820:
821: switch (cmd) {
822:
823: case SIOCSIFADDR:
824: if (ifa->ifa_addr.sa_family != AF_INET) {
825: error = EINVAL;
826: break;
827: }
828: if ((ifp->if_flags & IFF_UP) == 0)
829: impinit(ifp->if_unit);
830: break;
831:
832: case SIOCSIFFLAGS:
833: if ((ifp->if_flags & IFF_UP) == 0 &&
834: sc->imp_state != IMPS_DOWN) {
835: if (sc->imp_cb.ic_down &&
836: (*sc->imp_cb.ic_down)(sc->imp_cb.ic_hwunit)) {
837: sc->imp_state = IMPS_DOWN;
838: sc->imp_msgready = 0;
839: hostreset(ifp->if_unit);
840: if_down(ifp);
841: }
842: } else if (ifp->if_flags & IFF_UP && sc->imp_state == IMPS_DOWN)
843: impinit(ifp->if_unit);
844: break;
845:
846: default:
847: error = EINVAL;
848: break;
849: }
850: splx(s);
851: return (error);
852: }
853:
854: #ifdef IMPLEADERS
855: printleader(routine, ip)
856: char *routine;
857: register struct imp_leader *ip;
858: {
859: printf("%s: ", routine);
860: printbyte((char *)ip, 12);
861: printf("<fmt=%x,net=%x,flags=%x,mtype=", ip->il_format, ip->il_network,
862: ip->il_flags);
863: if (ip->il_mtype <= IMPTYPE_READY)
864: printf("%s,", impleaders[ip->il_mtype]);
865: else
866: printf("%x,", ip->il_mtype);
867: printf("htype=%x,host=%x,imp=%x,link=", ip->il_htype, ip->il_host,
868: ntohs(ip->il_imp));
869: if (ip->il_link == IMPLINK_IP)
870: printf("ip,");
871: else
872: printf("%x,", ip->il_link);
873: printf("subtype=%x,len=%x>\n",ip->il_subtype,ntohs(ip->il_length)>>3);
874: }
875:
876: printbyte(cp, n)
877: register char *cp;
878: int n;
879: {
880: register i, j, c;
881:
882: for (i=0; i<n; i++) {
883: c = *cp++;
884: for (j=0; j<2; j++)
885: putchar("0123456789abcdef"[(c>>((1-j)*4))&0xf], 0);
886: putchar(' ', 0);
887: }
888: putchar('\n', 0);
889: }
890: #endif
891:
892: /*
893: * Routine to convert from IMP Leader to InterNet Address.
894: *
895: * This procedure is necessary because IMPs may be assigned Class A, B, or C
896: * network numbers, but only have 8 bits in the leader to reflect the
897: * IMP "network number". The strategy is to take the network number from
898: * the ifnet structure, and blend in the host-on-imp and imp-on-net numbers
899: * from the leader.
900: *
901: * There is no support for "Logical Hosts".
902: *
903: * Class A: Net.Host.0.Imp
904: * Class B: Net.net.Host.Imp
905: * Class C: Net.net.net.(Host4|Imp4)
906: */
907: imp_leader_to_addr(ap, cp, ifp)
908: struct in_addr *ap;
909: register struct control_leader *cp;
910: struct ifnet *ifp;
911: {
912: register u_long final;
913: register struct sockaddr_in *sin;
914: int imp = ntohs(cp->dl_imp);
915:
916: sin = (struct sockaddr_in *)(&ifp->if_addrlist->ifa_addr);
917: final = ntohl(sin->sin_addr.s_addr);
918:
919: if (IN_CLASSA(final)) {
920: final &= IN_CLASSA_NET;
921: final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<16);
922: } else if (IN_CLASSB(final)) {
923: final &= IN_CLASSB_NET;
924: final |= (imp & 0xFF) | ((cp->dl_host & 0xFF)<<8);
925: } else {
926: final &= IN_CLASSC_NET;
927: final |= (imp & 0x0F) | ((cp->dl_host & 0x0F)<<4);
928: }
929: ap->s_addr = htonl(final);
930: }
931:
932: /*
933: * Function to take InterNet address and fill in IMP leader fields.
934: */
935: imp_addr_to_leader(imp, a)
936: register struct control_leader *imp;
937: u_long a;
938: {
939: register u_long addr = ntohl(a);
940:
941: imp->dl_network = 0; /* !! */
942:
943: if (IN_CLASSA(addr)) {
944: imp->dl_host = ((addr>>16) & 0xFF);
945: imp->dl_imp = addr & 0xFF;
946: } else if (IN_CLASSB(addr)) {
947: imp->dl_host = ((addr>>8) & 0xFF);
948: imp->dl_imp = addr & 0xFF;
949: } else {
950: imp->dl_host = ((addr>>4) & 0xF);
951: imp->dl_imp = addr & 0xF;
952: }
953: imp->dl_imp = htons(imp->dl_imp);
954: }
955: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.