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