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