1*5640Sroot /*	if_imp.c	4.1	82/02/01	*/
2*5640Sroot 
3*5640Sroot #include "imp.h"
4*5640Sroot #if NIMP > 0
5*5640Sroot /*
6*5640Sroot  * ARPAnet IMP interface driver.
7*5640Sroot  *
8*5640Sroot  * The IMP-host protocol is handled here, leaving
9*5640Sroot  * hardware specifics to the lower level interface driver.
10*5640Sroot  */
11*5640Sroot #include "../h/param.h"
12*5640Sroot #include "../h/systm.h"
13*5640Sroot #include "../h/mbuf.h"
14*5640Sroot #include "../h/pte.h"
15*5640Sroot #include "../h/buf.h"
16*5640Sroot #include "../h/protosw.h"
17*5640Sroot #include "../h/socket.h"
18*5640Sroot #include "../h/ubareg.h"
19*5640Sroot #include "../h/ubavar.h"
20*5640Sroot #include "../h/cpu.h"
21*5640Sroot #include "../h/mtpr.h"
22*5640Sroot #include "../h/vmmac.h"
23*5640Sroot #include "../net/in.h"
24*5640Sroot #include "../net/in_systm.h"
25*5640Sroot #include "../net/if.h"
26*5640Sroot #include "../net/if_imp.h"
27*5640Sroot #include "../net/host.h"
28*5640Sroot #include "../net/ip.h"
29*5640Sroot #include "../net/ip_var.h"
30*5640Sroot 
31*5640Sroot /*
32*5640Sroot  * IMP software status per interface.
33*5640Sroot  * (partially shared with the hardware specific module)
34*5640Sroot  *
35*5640Sroot  * Each interface is referenced by a network interface structure,
36*5640Sroot  * imp_if, which the routing code uses to locate the interface.
37*5640Sroot  * This structure contains the output queue for the interface, its
38*5640Sroot  * address, ...  IMP specific structures used in connecting the
39*5640Sroot  * IMP software modules to the hardware specific interface routines
40*5640Sroot  * are also stored here.  These structures are visible in the interface
41*5640Sroot  * driver through back pointers set up in the hardware's attach routine.
42*5640Sroot  *
43*5640Sroot  * NOTE: imp_if and imp_cb are assumed adjacent in hardware code.
44*5640Sroot  */
45*5640Sroot struct imp_softc {
46*5640Sroot 	struct	ifnet imp_if;		/* network visible interface */
47*5640Sroot 	struct	impcb imp_cb;		/* hooks to hardware module */
48*5640Sroot 	u_char	imp_state;		/* current state of IMP */
49*5640Sroot 	char	imp_dropcnt;		/* used during initialization */
50*5640Sroot 	short	imp_timer;		/* going down timer */
51*5640Sroot } imp_softc[NIMP];
52*5640Sroot 
53*5640Sroot /*
54*5640Sroot  * Messages from IMP regarding why
55*5640Sroot  * it's going down.
56*5640Sroot  */
57*5640Sroot static char *impmsg[] = {
58*5640Sroot 	"in 30 seconds",
59*5640Sroot 	"for hardware PM",
60*5640Sroot 	"to reload software",
61*5640Sroot 	"for emergency reset"
62*5640Sroot };
63*5640Sroot 
64*5640Sroot /*
65*5640Sroot  * IMP attach routine.  Called from hardware device attach routine
66*5640Sroot  * at configuration time with a pointer to the UNIBUS device structure.
67*5640Sroot  * Sets up local state and returns pointer to base of ifnet+impcb
68*5640Sroot  * structures.  This is then used by the device's attach routine
69*5640Sroot  * set up its back pointers.
70*5640Sroot  */
71*5640Sroot impattach(ui)
72*5640Sroot 	struct uba_device *ui;
73*5640Sroot {
74*5640Sroot 	struct imp_softc *sc = &imp_softc[ui->ui_unit];
75*5640Sroot 	register struct ifnet *ifp = &sc->imp_if;
76*5640Sroot 
77*5640Sroot COUNT(IMPATTACH);
78*5640Sroot 	/* UNIT COULD BE AMBIGUOUS */
79*5640Sroot 	ifp->if_unit = ui->ui_unit;
80*5640Sroot 	ifp->if_name = "imp";
81*5640Sroot 	ifp->if_mtu = IMP_MTU;
82*5640Sroot 	ifp->if_net = ui->ui_flags;
83*5640Sroot /*	ifp->if_host = ...	*/
84*5640Sroot /*	ifp->if_addr = if_makeaddr(ifp->if_net, ifp->if_host);	*/
85*5640Sroot 	if_attach(ifp);
86*5640Sroot 	/* kludge to hand pointers back to hardware attach routine */
87*5640Sroot 	return ((int)&sc->imp_if);
88*5640Sroot }
89*5640Sroot 
90*5640Sroot /*
91*5640Sroot  * IMP initialization routine: call hardware module to
92*5640Sroot  * setup UNIBUS resources, init state and get ready for
93*5640Sroot  * NOOPs the IMP should send us, and that we want to drop.
94*5640Sroot  */
95*5640Sroot impinit(unit)
96*5640Sroot 	int unit;
97*5640Sroot {
98*5640Sroot 	register struct imp_softc *sc = &imp_softc[unit];
99*5640Sroot 
100*5640Sroot 	(*sc->imp_cb.ic_init)(unit);
101*5640Sroot 	sc->imp_state = IMPS_INIT;
102*5640Sroot 	sc->imp_dropcnt = IMP_DROPCNT;
103*5640Sroot }
104*5640Sroot 
105*5640Sroot struct sockproto impproto = { PF_IMPLINK };
106*5640Sroot struct sockaddr_in impaddr = { AF_IMPLINK };
107*5640Sroot 
108*5640Sroot /*
109*5640Sroot  * ARPAnet 1822 input routine.
110*5640Sroot  * Called from hardware input interrupt routine to handle 1822
111*5640Sroot  * IMP-host messages.  Type 0 messages (non-control) are
112*5640Sroot  * passed to higher level protocol processors on the basis
113*5640Sroot  * of link number.  Other type messages (control) are handled here.
114*5640Sroot  */
115*5640Sroot impinput(unit, m0)
116*5640Sroot 	int unit;
117*5640Sroot 	struct mbuf *m0;
118*5640Sroot {
119*5640Sroot 	int s;
120*5640Sroot 	register struct mbuf *m;
121*5640Sroot 	register struct imp_leader *ip;
122*5640Sroot 	register struct imp_softc *sc = &imp_softc[unit];
123*5640Sroot 	register struct host *hp;
124*5640Sroot 	register struct ifqueue *inq;
125*5640Sroot 	struct in_addr addr;
126*5640Sroot 
127*5640Sroot COUNT(IMP_INPUT);
128*5640Sroot 	m = m0;
129*5640Sroot 	if (m->m_len < sizeof(struct imp_leader) &&
130*5640Sroot 	    m_pullup(m, sizeof(struct imp_leader)) == 0)
131*5640Sroot 		goto drop;
132*5640Sroot 	ip = mtod(m, struct imp_leader *);
133*5640Sroot 
134*5640Sroot 	/* check leader type. */
135*5640Sroot 	if (ip->il_format != IMP_NFF)
136*5640Sroot 		goto drop;
137*5640Sroot 
138*5640Sroot 	/*
139*5640Sroot 	 * Certain messages require a host structure.
140*5640Sroot 	 * Do this in one shot here.
141*5640Sroot 	 */
142*5640Sroot 	switch (ip->il_mtype) {
143*5640Sroot 
144*5640Sroot 	case IMPTYPE_RFNM:
145*5640Sroot 	case IMPTYPE_INCOMPLETE:
146*5640Sroot 	case IMPTYPE_HOSTDEAD:
147*5640Sroot 	case IMPTYPE_HOSTUNREACH:
148*5640Sroot 	case IMPTYPE_BADDATA:
149*5640Sroot 		addr.s_host = ntohs(ip->il_host);
150*5640Sroot 		hp = h_lookup(addr);
151*5640Sroot 		break;
152*5640Sroot 	}
153*5640Sroot 
154*5640Sroot 	switch (ip->il_mtype) {
155*5640Sroot 
156*5640Sroot 	/*
157*5640Sroot 	 * Data for a protocol.  Dispatch to the appropriate
158*5640Sroot 	 * protocol routine (running at software interrupt).
159*5640Sroot 	 * If this isn't a raw interface, advance pointer
160*5640Sroot 	 * into mbuf past leader.
161*5640Sroot 	 */
162*5640Sroot 	case IMPTYPE_DATA:
163*5640Sroot 		ip->il_length = ntohs(ip->il_length) >> 3;
164*5640Sroot 		break;
165*5640Sroot 
166*5640Sroot 	/*
167*5640Sroot 	 * IMP leader error.  Reset the IMP and discard the packet.
168*5640Sroot 	 */
169*5640Sroot 	case IMPTYPE_BADLEADER:
170*5640Sroot 		imperr(sc, "leader error");
171*5640Sroot 		h_reset(sc->imp_if.if_net);	/* XXX */
172*5640Sroot 		impnoops(sc);
173*5640Sroot 		goto drop;
174*5640Sroot 
175*5640Sroot 	/*
176*5640Sroot 	 * IMP going down.  Print message, and if not immediate,
177*5640Sroot 	 * set off a timer to insure things will be reset at the
178*5640Sroot 	 * appropriate time.
179*5640Sroot 	 */
180*5640Sroot 	case IMPTYPE_DOWN:
181*5640Sroot 		if ((ip->il_link & IMP_DMASK) == 0) {
182*5640Sroot 			sc->imp_state = IMPS_GOINGDOWN;
183*5640Sroot 			sc->imp_timer = IMPTV_DOWN;
184*5640Sroot 		}
185*5640Sroot 		imperr(sc, "going down %s", impmsg[ip->il_link & IMP_DMASK]);
186*5640Sroot 		goto drop;
187*5640Sroot 
188*5640Sroot 	/*
189*5640Sroot 	 * A NOP usually seen during the initialization sequence.
190*5640Sroot 	 * Compare the local address with that in the message.
191*5640Sroot 	 * Reset the local address notion if it doesn't match.
192*5640Sroot 	 */
193*5640Sroot 	case IMPTYPE_NOOP:
194*5640Sroot 		if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt == 0) {
195*5640Sroot 			sc->imp_state = IMPS_UP;
196*5640Sroot 			/* restart output in case something was q'd */
197*5640Sroot 			(*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
198*5640Sroot 		}
199*5640Sroot 		if (ip->il_host != sc->imp_if.if_addr.s_host ||
200*5640Sroot 		    ip->il_impno != sc->imp_if.if_addr.s_imp) {
201*5640Sroot 			sc->imp_if.if_addr.s_host = ip->il_host;
202*5640Sroot 			sc->imp_if.if_addr.s_imp = ip->il_imp;
203*5640Sroot 			imperr(sc, "imp%d: address set to %d/%d\n",
204*5640Sroot 				ip->il_host, ip->il_impno);
205*5640Sroot 		}
206*5640Sroot 		goto drop;
207*5640Sroot 
208*5640Sroot 	/*
209*5640Sroot 	 * RFNM or INCOMPLETE message, record in
210*5640Sroot 	 * host table and prime output routine.
211*5640Sroot 	 *
212*5640Sroot 	 * SHOULD RETRANSMIT ON INCOMPLETE.
213*5640Sroot 	 */
214*5640Sroot 	case IMPTYPE_RFNM:
215*5640Sroot 	case IMPTYPE_INCOMPLETE:
216*5640Sroot 		if (hp && hp->h_rfnm) {
217*5640Sroot 			register struct mbuf *n;
218*5640Sroot 
219*5640Sroot 			hp->h_rfnm--;
220*5640Sroot 			/* poke holding queue */
221*5640Sroot 			if (n = hp->h_q) {
222*5640Sroot 				if (n->m_act == n)
223*5640Sroot 					hp->h_q = 0;
224*5640Sroot 				else {
225*5640Sroot 					n = n->m_act;
226*5640Sroot 					hp->h_q->m_act = n->m_act;
227*5640Sroot 				}
228*5640Sroot 				(void) impsnd(n, sc);
229*5640Sroot 			}
230*5640Sroot 		}
231*5640Sroot 		break;
232*5640Sroot 
233*5640Sroot 	/*
234*5640Sroot 	 * Host or IMP can't be reached.  Flush any packets
235*5640Sroot 	 * awaiting transmission and release the host structure.
236*5640Sroot 	 *
237*5640Sroot 	 * HOW DO WE NOTIFY THE PROTOCOL?
238*5640Sroot 	 * HOW DO WE AGE THE HOST STRUCTURE TO SAVE STATUS?
239*5640Sroot 	 */
240*5640Sroot 	case IMPTYPE_HOSTDEAD:
241*5640Sroot 	case IMPTYPE_HOSTUNREACH:
242*5640Sroot 		if (hp)
243*5640Sroot 			h_free(hp);		/* won't work right */
244*5640Sroot 		break;
245*5640Sroot 
246*5640Sroot 	/*
247*5640Sroot 	 * Error in data.  Clear RFNM status for this host and send
248*5640Sroot 	 * noops to the IMP to clear the interface.
249*5640Sroot 	 */
250*5640Sroot 	case IMPTYPE_BADDATA:
251*5640Sroot 		imperr(sc, "data error");
252*5640Sroot 		if (hp)
253*5640Sroot 			hp->h_rfnm = 0;
254*5640Sroot 		impnoops(sc);
255*5640Sroot 		break;
256*5640Sroot 
257*5640Sroot 	/*
258*5640Sroot 	 * IMP reset complete.
259*5640Sroot 	 */
260*5640Sroot 	case IMPTYPE_RESET:
261*5640Sroot 		if (sc->imp_state == IMPS_DOWN)
262*5640Sroot 			sc->imp_state = IMPS_UP;
263*5640Sroot 		else
264*5640Sroot 			imperr(sc, "unexpected reset");
265*5640Sroot 		goto drop;
266*5640Sroot 
267*5640Sroot 	default:
268*5640Sroot 		sc->imp_if.if_collisions++;		/* XXX */
269*5640Sroot 		goto drop;
270*5640Sroot 	}
271*5640Sroot 
272*5640Sroot 	/*
273*5640Sroot 	 * Queue on protocol's input queue.
274*5640Sroot 	 */
275*5640Sroot 	switch (ip->il_link) {
276*5640Sroot 
277*5640Sroot #ifdef INET
278*5640Sroot 	case IMPLINK_IP:
279*5640Sroot 		m->m_len -= sizeof(struct imp_leader);
280*5640Sroot 		m->m_off += sizeof(struct imp_leader);
281*5640Sroot 		setipintr();
282*5640Sroot 		inq = &ipintrq;
283*5640Sroot 		break;
284*5640Sroot #endif
285*5640Sroot 
286*5640Sroot 	default:
287*5640Sroot 		impproto.sp_protocol = ip->il_link;
288*5640Sroot 		impaddr.sin_addr.s_net = ip->il_network;
289*5640Sroot 		impaddr.sin_addr.s_host = ip->il_host;
290*5640Sroot 		impaddr.sin_addr.s_imp = ip->il_imp;
291*5640Sroot 		raw_input(m, impproto, impaddr);
292*5640Sroot 		return;
293*5640Sroot 	}
294*5640Sroot 	IF_ENQUEUE(inq, m);
295*5640Sroot 	return;
296*5640Sroot 
297*5640Sroot drop:
298*5640Sroot 	m_freem(m);
299*5640Sroot }
300*5640Sroot 
301*5640Sroot /*VARARGS*/
302*5640Sroot imperr(sc, fmt, a1, a2)
303*5640Sroot 	struct imp_softc *sc;
304*5640Sroot 	char *fmt;
305*5640Sroot {
306*5640Sroot 	printf("imp%d: ", sc->imp_if.if_unit);
307*5640Sroot 	printf(fmt, a1, a2);
308*5640Sroot 	printf("\n");
309*5640Sroot }
310*5640Sroot 
311*5640Sroot /*
312*5640Sroot  * ARPAnet 1822 output routine.
313*5640Sroot  * Called from higher level protocol routines to set up messages for
314*5640Sroot  * transmission to the imp.  Sets up the header and calls impsnd to
315*5640Sroot  * enqueue the message for this IMP's hardware driver.
316*5640Sroot  */
317*5640Sroot impoutput(ifp, m0, pf)
318*5640Sroot 	register struct ifnet *ifp;
319*5640Sroot 	struct mbuf *m0;
320*5640Sroot {
321*5640Sroot 	register struct imp_leader *imp;
322*5640Sroot 	register struct mbuf *m = m0;
323*5640Sroot 	int x, dhost, dimp, dlink, len;
324*5640Sroot 
325*5640Sroot 	/*
326*5640Sroot 	 * Don't even try if the IMP is unavailable.
327*5640Sroot 	 */
328*5640Sroot 	if (imp_softc[ifp->if_unit].imp_state == IMPS_DOWN) {
329*5640Sroot 		m_freem(m0);
330*5640Sroot 		return (0);
331*5640Sroot 	}
332*5640Sroot 
333*5640Sroot 	switch (pf) {
334*5640Sroot 
335*5640Sroot #ifdef INET
336*5640Sroot 	case PF_INET: {
337*5640Sroot 		register struct ip *ip = mtod(m0, struct ip *);
338*5640Sroot 
339*5640Sroot 		dhost = ip->ip_dst.s_host;
340*5640Sroot 		dimp = ip->ip_dst.s_imp;
341*5640Sroot 		dlink = IMPLINK_IP;
342*5640Sroot 		len = ntohs(ip->ip_len);
343*5640Sroot 		break;
344*5640Sroot 	}
345*5640Sroot #endif
346*5640Sroot 	case PF_IMPLINK:
347*5640Sroot 		goto leaderexists;
348*5640Sroot 
349*5640Sroot 	default:
350*5640Sroot 		printf("imp%d: can't encapsulate pf%d\n", ifp->if_unit, pf);
351*5640Sroot 		m_freem(m0);
352*5640Sroot 		return (0);
353*5640Sroot 	}
354*5640Sroot 
355*5640Sroot 	/*
356*5640Sroot 	 * Add IMP leader.  If there's not enough space in the
357*5640Sroot 	 * first mbuf, allocate another.  If that should fail, we
358*5640Sroot 	 * drop this sucker.
359*5640Sroot 	 */
360*5640Sroot 	if (m->m_off > MMAXOFF ||
361*5640Sroot 	    MMINOFF + sizeof(struct imp_leader) > m->m_off) {
362*5640Sroot 		m = m_get(M_DONTWAIT);
363*5640Sroot 		if (m == 0) {
364*5640Sroot 			m_freem(m0);
365*5640Sroot 			return (0);
366*5640Sroot 		}
367*5640Sroot 		m->m_next = m0;
368*5640Sroot 		m->m_off = MMINOFF;
369*5640Sroot 		m->m_len = sizeof(struct imp_leader);
370*5640Sroot 	} else {
371*5640Sroot 		m->m_off -= sizeof(struct imp_leader);
372*5640Sroot 		m->m_len += sizeof(struct imp_leader);
373*5640Sroot 	}
374*5640Sroot 	imp = mtod(m, struct imp_leader *);
375*5640Sroot 	imp->il_format = IMP_NFF;
376*5640Sroot 	imp->il_host = dhost;
377*5640Sroot 	imp->il_impno = dimp;
378*5640Sroot 	imp->il_length = (len + sizeof(struct imp_leader)) << 3;
379*5640Sroot 	imp->il_link = dlink;
380*5640Sroot 
381*5640Sroot leaderexists:
382*5640Sroot 	/*
383*5640Sroot 	 * Hand message to impsnd to perform RFNM counting
384*5640Sroot 	 * and eventual transmission.
385*5640Sroot 	 */
386*5640Sroot 	return (impsnd(ifp, m));
387*5640Sroot }
388*5640Sroot 
389*5640Sroot /*
390*5640Sroot  * Put a message on an interface's output queue.
391*5640Sroot  * Perform RFNM counting: no more than 8 message may be
392*5640Sroot  * in flight to any one host.
393*5640Sroot  */
394*5640Sroot impsnd(ifp, m)
395*5640Sroot 	struct ifnet *ifp;
396*5640Sroot 	struct mbuf *m;
397*5640Sroot {
398*5640Sroot 	register struct imp_leader *ip;
399*5640Sroot 	register struct host *hp;
400*5640Sroot 	struct impcb *icp;
401*5640Sroot 	int x;
402*5640Sroot 
403*5640Sroot 	ip = mtod(m, struct imp_leader *);
404*5640Sroot 
405*5640Sroot 	/*
406*5640Sroot 	 * Do RFNM counting for data messages
407*5640Sroot 	 * (no more than 8 outstanding to any host)
408*5640Sroot 	 */
409*5640Sroot 	if (ip->il_mtype == IMPTYPE_DATA) {
410*5640Sroot 		struct in_addr addr;
411*5640Sroot 
412*5640Sroot                 addr.s_net = ifp->if_net;
413*5640Sroot                 addr.s_host = ip->il_host;
414*5640Sroot                 addr.s_imp = ip->il_imp;
415*5640Sroot         	hp = h_enter(addr);
416*5640Sroot 
417*5640Sroot 		/*
418*5640Sroot 		 * If IMP would block, queue until rfnm
419*5640Sroot 		 */
420*5640Sroot 		if (hp) {
421*5640Sroot 			register struct mbuf *n;
422*5640Sroot 			int cnt;
423*5640Sroot 
424*5640Sroot 			if (hp->h_rfnm < 8) {
425*5640Sroot 				hp->h_rfnm++;
426*5640Sroot 				goto enque;
427*5640Sroot 			}
428*5640Sroot 			/*
429*5640Sroot 			 * Keeping the count in the host structure
430*5640Sroot 			 * causes the packing scheme to lose too much.
431*5640Sroot 			 */
432*5640Sroot 			cnt = 0, n = hp->h_q;
433*5640Sroot 			for (; n != (struct mbuf *)hp; n = n->m_act)
434*5640Sroot 				cnt++;
435*5640Sroot 			if (cnt >= 8)
436*5640Sroot 				goto drop;
437*5640Sroot 			if ((n = hp->h_q) == 0)
438*5640Sroot 				hp->h_q = m->m_act = m;
439*5640Sroot 			else {
440*5640Sroot 				m->m_act = n->m_act;
441*5640Sroot 				hp->h_q = n->m_act = m;
442*5640Sroot 			}
443*5640Sroot 			goto start;
444*5640Sroot 		}
445*5640Sroot drop:
446*5640Sroot 		m_freem(m);
447*5640Sroot 		return (0);
448*5640Sroot 	}
449*5640Sroot enque:
450*5640Sroot         x = splimp();
451*5640Sroot 	IF_ENQUEUE(&ifp->if_snd, m);
452*5640Sroot 	splx(x);
453*5640Sroot 
454*5640Sroot start:
455*5640Sroot 	icp = &imp_softc[ifp->if_unit].imp_cb;
456*5640Sroot 	if (icp->ic_oactive == 0)
457*5640Sroot 		(*icp->ic_start)(ifp->if_unit);
458*5640Sroot 	return (1);
459*5640Sroot }
460*5640Sroot 
461*5640Sroot /*
462*5640Sroot  * Put three 1822 NOOPs at the head of the output queue.
463*5640Sroot  * Part of host-IMP initialization procedure.
464*5640Sroot  * (Should return success/failure, but noone knows
465*5640Sroot  * what to do with this, so why bother?)
466*5640Sroot  */
467*5640Sroot impnoops(sc)
468*5640Sroot 	register struct imp_softc *sc;
469*5640Sroot {
470*5640Sroot 	register i;
471*5640Sroot 	register struct mbuf *m;
472*5640Sroot 	register struct imp_leader *ip;
473*5640Sroot 	int x;
474*5640Sroot 
475*5640Sroot 	sc->imp_state = IMPS_INIT;
476*5640Sroot 	sc->imp_dropcnt = IMP_DROPCNT;
477*5640Sroot 	for (i = 0; i < IMP_DROPCNT; i++ ) {
478*5640Sroot 		if ((m = m_getclr(M_DONTWAIT)) == 0)
479*5640Sroot 			return;
480*5640Sroot 		m->m_off = MMINOFF;
481*5640Sroot 		m->m_len = sizeof(struct imp_leader);
482*5640Sroot 		ip = mtod(m, struct imp_leader *);
483*5640Sroot 		ip->il_format = IMP_NFF;
484*5640Sroot                 ip->il_link = i;
485*5640Sroot                 ip->il_mtype = IMPTYPE_NOOP;
486*5640Sroot 		x = splimp();
487*5640Sroot 		IF_PREPEND(&sc->imp_if.if_snd, m);
488*5640Sroot 		splx(x);
489*5640Sroot 	}
490*5640Sroot 	if (sc->imp_cb.ic_oactive == 0)
491*5640Sroot 		(*sc->imp_cb.ic_start)(sc->imp_if.if_unit);
492*5640Sroot }
493*5640Sroot #endif
494