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