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