xref: /csrg-svn/sys/vax/if/if_vv.c (revision 7024)
1*7024Ssam /*	if_vv.c	4.1	82/06/04	*/
2*7024Ssam 
3*7024Ssam /*
4*7024Ssam  * Proteon 10 Meg Ring Driver.
5*7024Ssam  * This device is called "vv" because its "real name",
6*7024Ssam  * V2LNI won't work if shortened to the obvious "v2".
7*7024Ssam  * Hence the subterfuge.
8*7024Ssam  */
9*7024Ssam #include "../h/param.h"
10*7024Ssam #include "../h/systm.h"
11*7024Ssam #include "../h/mbuf.h"
12*7024Ssam #include "../h/pte.h"
13*7024Ssam #include "../h/buf.h"
14*7024Ssam #include "../h/protosw.h"
15*7024Ssam #include "../h/socket.h"
16*7024Ssam #include "../h/ubareg.h"
17*7024Ssam #include "../h/ubavar.h"
18*7024Ssam #include "../h/cpu.h"
19*7024Ssam #include "../h/mtpr.h"
20*7024Ssam #include "../h/vmmac.h"
21*7024Ssam #include "../net/in.h"
22*7024Ssam #include "../net/in_systm.h"
23*7024Ssam #include "../net/if.h"
24*7024Ssam #include "../net/if_vv.h"
25*7024Ssam #include "../net/if_uba.h"
26*7024Ssam #include "../net/ip.h"
27*7024Ssam #include "../net/ip_var.h"
28*7024Ssam #include "../net/route.h"
29*7024Ssam 
30*7024Ssam #include "vv.h"
31*7024Ssam #include "imp.h"
32*7024Ssam 
33*7024Ssam /*
34*7024Ssam  * N.B. - if WIRECENTER is defined wrong, it can well break
35*7024Ssam  * the hardware!!
36*7024Ssam  */
37*7024Ssam #undef AUTOIDENTIFY
38*7024Ssam #define	WIRECENTER
39*7024Ssam 
40*7024Ssam #ifdef WIRECENTER
41*7024Ssam #define	VV_CONF	VV_HEN		/* drive wire center relay */
42*7024Ssam #else
43*7024Ssam #define	VV_CONF	VV_STE		/* allow operation without wire center */
44*7024Ssam #endif
45*7024Ssam 
46*7024Ssam #define	VVMTU	(1024+512)
47*7024Ssam 
48*7024Ssam int	vvprobe(), vvattach(), vvrint(), vvxint();
49*7024Ssam struct	uba_device *vvinfo[NVV];
50*7024Ssam u_short vvstd[] = { 0 };
51*7024Ssam struct	uba_driver vvdriver =
52*7024Ssam 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
53*7024Ssam #define	VVUNIT(x)	minor(x)
54*7024Ssam int	vvinit(),vvoutput(),vvreset();
55*7024Ssam 
56*7024Ssam /*
57*7024Ssam  * Software status of each interface.
58*7024Ssam  *
59*7024Ssam  * Each interface is referenced by a network interface structure,
60*7024Ssam  * vs_if, which the routing code uses to locate the interface.
61*7024Ssam  * This structure contains the output queue for the interface, its address, ...
62*7024Ssam  * We also have, for each interface, a UBA interface structure, which
63*7024Ssam  * contains information about the UNIBUS resources held by the interface:
64*7024Ssam  * map registers, buffered data paths, etc.  Information is cached in this
65*7024Ssam  * structure for use by the if_uba.c routines in running the interface
66*7024Ssam  * efficiently.
67*7024Ssam  */
68*7024Ssam struct	vv_softc {
69*7024Ssam 	struct	ifnet vs_if;		/* network-visible interface */
70*7024Ssam 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
71*7024Ssam 	short	vs_oactive;		/* is output active? */
72*7024Ssam 	short	vs_olen;		/* length of last output */
73*7024Ssam 	u_short	vs_lastx;		/* last destination address */
74*7024Ssam 	short	vs_tries;		/* current retry count */
75*7024Ssam 	short	vs_init;		/* number of ring inits */
76*7024Ssam 	short	vs_flush;		/* number of flushed packets */
77*7024Ssam 	short	vs_nottaken;		/* number of packets refused */
78*7024Ssam } vv_softc[NVV];
79*7024Ssam 
80*7024Ssam vvprobe(reg)
81*7024Ssam 	caddr_t reg;
82*7024Ssam {
83*7024Ssam 	register int br, cvec;
84*7024Ssam 	register struct vvreg *addr = (struct vvreg *)reg;
85*7024Ssam 
86*7024Ssam #ifdef lint
87*7024Ssam 	br = 0; cvec = br; br = cvec;
88*7024Ssam #endif
89*7024Ssam 	/* reset interface, enable, and wait till dust settles */
90*7024Ssam 	addr->vvicsr = VV_RST;
91*7024Ssam 	addr->vvocsr = VV_RST;
92*7024Ssam 	DELAY(100000);
93*7024Ssam 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
94*7024Ssam 	addr->vvocsr = VV_IEN;		/* enable interrupt */
95*7024Ssam 	addr->vvoba = 0;		/* low 16 bits */
96*7024Ssam 	addr->vvoea = 0;		/* extended bits */
97*7024Ssam 	addr->vvowc = -1;		/* for 1 word */
98*7024Ssam 	addr->vvocsr |= VV_DEN;		/* start the DMA */
99*7024Ssam 	DELAY(100000);
100*7024Ssam 	addr->vvocsr = 0;
101*7024Ssam 	if (cvec && cvec != 0x200)
102*7024Ssam 		cvec -= 4;		/* backup so vector => recieve */
103*7024Ssam 	return(1);
104*7024Ssam }
105*7024Ssam 
106*7024Ssam /*
107*7024Ssam  * Interface exists: make available by filling in network interface
108*7024Ssam  * record.  System will initialize the interface when it is ready
109*7024Ssam  * to accept packets.
110*7024Ssam  */
111*7024Ssam vvattach(ui)
112*7024Ssam 	struct uba_device *ui;
113*7024Ssam {
114*7024Ssam 	register struct vv_softc *vs = &vv_softc[ui->ui_unit];
115*7024Ssam 	register struct sockaddr_in *sin;
116*7024Ssam COUNT(VVATTACH);
117*7024Ssam 
118*7024Ssam 	vs->vs_if.if_unit = ui->ui_unit;
119*7024Ssam 	vs->vs_if.if_name = "vv";
120*7024Ssam 	vs->vs_if.if_mtu = VVMTU;
121*7024Ssam 	vs->vs_if.if_net = ui->ui_flags;
122*7024Ssam 	vs->vs_if.if_host[0] = 0;	/* this will be reset in vvinit() */
123*7024Ssam 
124*7024Ssam 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
125*7024Ssam 	sin->sin_family = AF_INET;
126*7024Ssam 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
127*7024Ssam 
128*7024Ssam 	sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
129*7024Ssam 	sin->sin_family = AF_INET;
130*7024Ssam 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
131*7024Ssam 	vs->vs_if.if_flags = IFF_BROADCAST;
132*7024Ssam 
133*7024Ssam 	vs->vs_if.if_init = vvinit;
134*7024Ssam 	vs->vs_if.if_output = vvoutput;
135*7024Ssam 	vs->vs_if.if_ubareset = vvreset;
136*7024Ssam 	vs->vs_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16;
137*7024Ssam 	if_attach(&vs->vs_if);
138*7024Ssam #if NIMP == 0
139*7024Ssam 	if (ui->ui_flags & ~0xff)
140*7024Ssam 		vvlhinit((ui->ui_flags &~ 0xff) | 0x0a);
141*7024Ssam #endif
142*7024Ssam }
143*7024Ssam 
144*7024Ssam /*
145*7024Ssam  * Reset of interface after UNIBUS reset.
146*7024Ssam  * If interface is on specified uba, reset its state.
147*7024Ssam  */
148*7024Ssam vvreset(unit, uban)
149*7024Ssam 	int unit, uban;
150*7024Ssam {
151*7024Ssam 	register struct uba_device *ui;
152*7024Ssam COUNT(VVRESET);
153*7024Ssam 
154*7024Ssam 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
155*7024Ssam 	    ui->ui_ubanum != uban)
156*7024Ssam 		return;
157*7024Ssam 	printf(" vv%d", unit);
158*7024Ssam 	vvinit(unit);
159*7024Ssam }
160*7024Ssam 
161*7024Ssam /*
162*7024Ssam  * Initialization of interface; clear recorded pending
163*7024Ssam  * operations, and reinitialize UNIBUS usage.
164*7024Ssam  */
165*7024Ssam vvinit(unit)
166*7024Ssam 	int unit;
167*7024Ssam {
168*7024Ssam 	register struct vv_softc *vs = &vv_softc[unit];
169*7024Ssam 	register struct uba_device *ui = vvinfo[unit];
170*7024Ssam 	register struct vvreg *addr;
171*7024Ssam 	struct sockaddr_in *sin;
172*7024Ssam 	struct mbuf *m;
173*7024Ssam 	struct vv_header *v;
174*7024Ssam 	int ubainfo, retrying, attempts, waitcount, s;
175*7024Ssam 
176*7024Ssam 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
177*7024Ssam 	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
178*7024Ssam 		printf("vv%d: can't initialize\n", unit);
179*7024Ssam 		return;
180*7024Ssam 	}
181*7024Ssam 	addr = (struct vvreg *)ui->ui_addr;
182*7024Ssam 
183*7024Ssam #ifdef AUTOIDENTIFY
184*7024Ssam 	/*
185*7024Ssam 	 * Build a multicast message to identify our address
186*7024Ssam 	 */
187*7024Ssam 	attempts = 0;		/* total attempts, including bad msg type */
188*7024Ssam top:
189*7024Ssam 	retrying = 0;		/* first time through */
190*7024Ssam 	m = m_get(M_DONTWAIT);
191*7024Ssam 	if (m == 0)
192*7024Ssam 		panic("vvinit: can't get mbuf");
193*7024Ssam 	m->m_next = 0;
194*7024Ssam 	m->m_off = MMINOFF;
195*7024Ssam 	m->m_len = sizeof(struct vv_header);
196*7024Ssam 
197*7024Ssam 	v = mtod(m, struct vv_header *);
198*7024Ssam 	v->vh_dhost = 0;		/* multicast destination address */
199*7024Ssam 	v->vh_shost = 0;		/* will be overwritten with ours */
200*7024Ssam 	v->vh_version = RING_VERSION;
201*7024Ssam 	v->vh_type = RING_WHOAMI;
202*7024Ssam 	v->vh_info = 0;
203*7024Ssam 
204*7024Ssam 	/*
205*7024Ssam 	 * Reset interface, establish Digital Loopback Mode, and
206*7024Ssam 	 * send the multicast (to myself) with Input Copy enabled.
207*7024Ssam 	 */
208*7024Ssam retry:
209*7024Ssam 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
210*7024Ssam 	addr->vvicsr = VV_RST;
211*7024Ssam 	addr->vviba = (u_short) ubainfo;
212*7024Ssam 	addr->vviea = (u_short) (ubainfo >> 16);
213*7024Ssam 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
214*7024Ssam 	addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
215*7024Ssam 	/* map xmit message into uba if not already there */
216*7024Ssam 	if (!retrying)
217*7024Ssam 		vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
218*7024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
219*7024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
220*7024Ssam 	addr->vvocsr = VV_RST | VV_CPB;	/* clear packet buffer */
221*7024Ssam 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
222*7024Ssam 	addr->vvoba = (u_short) ubainfo;
223*7024Ssam 	addr->vvoea = (u_short) (ubainfo >> 16);
224*7024Ssam 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
225*7024Ssam 	addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
226*7024Ssam 
227*7024Ssam 	/*
228*7024Ssam 	 * Wait for receive side to finish.
229*7024Ssam 	 * Extract source address (which will our own),
230*7024Ssam 	 * and post to interface structure.
231*7024Ssam 	 */
232*7024Ssam 	DELAY(1000);
233*7024Ssam 	for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) {
234*7024Ssam 		if (waitcount < 10)
235*7024Ssam 			DELAY(1000);
236*7024Ssam 		else {
237*7024Ssam 			if (attempts++ < 10)s
238*7024Ssam 				goto retry;
239*7024Ssam 			else {
240*7024Ssam 				printf("vv%d: can't initialize\n", unit);
241*7024Ssam 				printf("vvinit loopwait: icsr = %b\n",
242*7024Ssam 					0xffff&(addr->vvicsr),VV_IBITS);
243*7024Ssam 				return;
244*7024Ssam 			}
245*7024Ssam 		}
246*7024Ssam 	}
247*7024Ssam 
248*7024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
249*7024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
250*7024Ssam 	if (vs->vs_ifuba.ifu_xtofree)
251*7024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
252*7024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
253*7024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
254*7024Ssam 	m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
255*7024Ssam 	if (m)
256*7024Ssam 		m_freem(m);
257*7024Ssam 	/*
258*7024Ssam 	 * check message type before we believe the source host address
259*7024Ssam 	 */
260*7024Ssam 	v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
261*7024Ssam 	if (v->vh_type == RING_WHOAMI)
262*7024Ssam 		vs->vs_if.if_host[0] = v->vh_shost;
263*7024Ssam 	else
264*7024Ssam 		goto top;
265*7024Ssam #else
266*7024Ssam 	vs->vs_if.if_host[0] = 24;
267*7024Ssam #endif
268*7024Ssam 
269*7024Ssam 	printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
270*7024Ssam 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
271*7024Ssam 	sin->sin_family = AF_INET;
272*7024Ssam 	sin->sin_addr =
273*7024Ssam 	    if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
274*7024Ssam 
275*7024Ssam 	/*
276*7024Ssam 	 * Reset the interface, and join the ring
277*7024Ssam 	 */
278*7024Ssam 	addr->vvocsr = VV_RST | VV_CPB;		/* clear packet buffer */
279*7024Ssam 	addr->vvicsr = VV_RST | VV_CONF;	/* close logical relay */
280*7024Ssam 	sleep((caddr_t)&lbolt, PZERO);		/* let contacts settle */
281*7024Ssam 	vs->vs_init = 0;
282*7024Ssam 	vs->vs_flush = 0;
283*7024Ssam 	vs->vs_nottaken = 0;
284*7024Ssam 
285*7024Ssam 	/*
286*7024Ssam 	 * Hang a receive and start any
287*7024Ssam 	 * pending writes by faking a transmit complete.
288*7024Ssam 	 */
289*7024Ssam 	s = splimp();
290*7024Ssam 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
291*7024Ssam 	addr->vviba = (u_short) ubainfo;
292*7024Ssam 	addr->vviea = (u_short) (ubainfo >> 16);
293*7024Ssam 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
294*7024Ssam 	addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
295*7024Ssam 	vs->vs_oactive = 1;
296*7024Ssam 	vvxint(unit);
297*7024Ssam 	splx(s);
298*7024Ssam 	if_rtinit(&vs->vs_if, RTF_DIRECT|RTF_UP);
299*7024Ssam }
300*7024Ssam 
301*7024Ssam /*
302*7024Ssam  * Start or restart output on interface.
303*7024Ssam  * If interface is not already active, get another datagram
304*7024Ssam  * to send off of the interface queue, and map it to the interface
305*7024Ssam  * before starting the output.
306*7024Ssam  */
307*7024Ssam vvstart(dev)
308*7024Ssam 	dev_t dev;
309*7024Ssam {
310*7024Ssam         int unit = VVUNIT(dev);
311*7024Ssam 	struct uba_device *ui = vvinfo[unit];
312*7024Ssam 	register struct vv_softc *vs = &vv_softc[unit];
313*7024Ssam 	register struct vvreg *addr;
314*7024Ssam 	struct mbuf *m;
315*7024Ssam 	int ubainfo;
316*7024Ssam 	int dest;
317*7024Ssam COUNT(VVSTART);
318*7024Ssam 
319*7024Ssam 	if (vs->vs_oactive)
320*7024Ssam 		goto restart;
321*7024Ssam 
322*7024Ssam 	/*
323*7024Ssam 	 * Not already active: dequeue another request
324*7024Ssam 	 * and map it to the UNIBUS.  If no more requests,
325*7024Ssam 	 * just return.
326*7024Ssam 	 */
327*7024Ssam 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
328*7024Ssam 	if (m == 0) {
329*7024Ssam 		vs->vs_oactive = 0;
330*7024Ssam 		return;
331*7024Ssam 	}
332*7024Ssam 	dest = mtod(m, struct vv_header *)->vh_dhost;
333*7024Ssam 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
334*7024Ssam 	vs->vs_lastx = dest;
335*7024Ssam 
336*7024Ssam restart:
337*7024Ssam 	/*
338*7024Ssam 	 * Have request mapped to UNIBUS for transmission.
339*7024Ssam 	 * Purge any stale data from this BDP, and start the otput.
340*7024Ssam 	 */
341*7024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
342*7024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
343*7024Ssam 	addr = (struct vvreg *)ui->ui_addr;
344*7024Ssam 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
345*7024Ssam 	addr->vvoba = (u_short) ubainfo;
346*7024Ssam 	addr->vvoea = (u_short) (ubainfo >> 16);
347*7024Ssam 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
348*7024Ssam 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
349*7024Ssam 	vs->vs_oactive = 1;
350*7024Ssam }
351*7024Ssam 
352*7024Ssam /*
353*7024Ssam  * VVLNI transmit interrupt
354*7024Ssam  * Start another output if more data to send.
355*7024Ssam  */
356*7024Ssam vvxint(unit)
357*7024Ssam 	int unit;
358*7024Ssam {
359*7024Ssam 	register struct uba_device *ui = vvinfo[unit];
360*7024Ssam 	register struct vv_softc *vs = &vv_softc[unit];
361*7024Ssam 	register struct vvreg *addr;
362*7024Ssam 	register int oc;
363*7024Ssam COUNT(ENXINT);
364*7024Ssam 
365*7024Ssam 	addr = (struct vvreg *)ui->ui_addr;
366*7024Ssam 	oc = 0xffff & (addr->vvocsr);
367*7024Ssam 	if (vs->vs_oactive == 0) {
368*7024Ssam 		printf("vv%d: stray interrupt vvocsr = %b\n", unit,
369*7024Ssam 			oc, VV_OBITS);
370*7024Ssam 		return;
371*7024Ssam 	}
372*7024Ssam 	if (oc &  (VV_OPT | VV_RFS)) {
373*7024Ssam 		if (++(vs->vs_tries) < VVRETRY) {
374*7024Ssam 			if (oc & VV_OPT)
375*7024Ssam 				vs->vs_init++;
376*7024Ssam 			if (oc & VV_RFS)
377*7024Ssam 				vs->vs_nottaken++;
378*7024Ssam 			addr->vvocsr = VV_IEN | VV_ENB | VV_INR;
379*7024Ssam 			return;
380*7024Ssam 		}
381*7024Ssam 		if (oc & VV_OPT)
382*7024Ssam 			printf("vv%d: output timeout\n");
383*7024Ssam 	}
384*7024Ssam 	vs->vs_if.if_opackets++;
385*7024Ssam 	vs->vs_oactive = 0;
386*7024Ssam 	vs->vs_tries = 0;
387*7024Ssam 	if (oc & VVXERR) {
388*7024Ssam 		vs->vs_if.if_oerrors++;
389*7024Ssam 		printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
390*7024Ssam 			VV_OBITS);
391*7024Ssam 	}
392*7024Ssam 	if (vs->vs_ifuba.ifu_xtofree) {
393*7024Ssam 		m_freem(vs->vs_ifuba.ifu_xtofree);
394*7024Ssam 		vs->vs_ifuba.ifu_xtofree = 0;
395*7024Ssam 	}
396*7024Ssam 	if (vs->vs_if.if_snd.ifq_head == 0) {
397*7024Ssam 		vs->vs_lastx = 0;
398*7024Ssam 		return;
399*7024Ssam 	}
400*7024Ssam 	vvstart(unit);
401*7024Ssam }
402*7024Ssam 
403*7024Ssam /*
404*7024Ssam  * V2lni interface receiver interrupt.
405*7024Ssam  * If input error just drop packet.
406*7024Ssam  * Otherwise purge input buffered data path and examine
407*7024Ssam  * packet to determine type.  If can't determine length
408*7024Ssam  * from type, then have to drop packet.  Othewise decapsulate
409*7024Ssam  * packet based on type and pass to type specific higher-level
410*7024Ssam  * input routine.
411*7024Ssam  */
412*7024Ssam vvrint(unit)
413*7024Ssam 	int unit;
414*7024Ssam {
415*7024Ssam 	register struct vv_softc *vs = &vv_softc[unit];
416*7024Ssam 	struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
417*7024Ssam 	register struct vv_header *vv;
418*7024Ssam 	register struct ifqueue *inq;
419*7024Ssam     	struct mbuf *m;
420*7024Ssam 	int ubainfo, len, off;
421*7024Ssam COUNT(VVRINT);
422*7024Ssam 
423*7024Ssam 	vs->vs_if.if_ipackets++;
424*7024Ssam 	/*
425*7024Ssam 	 * Purge BDP; drop if input error indicated.
426*7024Ssam 	 */
427*7024Ssam 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
428*7024Ssam 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
429*7024Ssam 	if (addr->vvicsr & VVRERR) {
430*7024Ssam 		vs->vs_if.if_ierrors++;
431*7024Ssam 		printf("vv%d: error vvicsr = %b\n", unit,
432*7024Ssam 			0xffff&(addr->vvicsr), VV_IBITS);
433*7024Ssam 		goto setup;
434*7024Ssam 	}
435*7024Ssam 	off = 0;
436*7024Ssam 	len = 0;
437*7024Ssam 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
438*7024Ssam 	/*
439*7024Ssam 	 * Demultiplex on packet type and deal with oddities of
440*7024Ssam 	 * trailer protocol format
441*7024Ssam 	 */
442*7024Ssam 	switch (vv->vh_type) {
443*7024Ssam 
444*7024Ssam #ifdef INET
445*7024Ssam 	case RING_IP:
446*7024Ssam 		len = htons((u_short)((struct ip *) vv)->ip_len);
447*7024Ssam 		schednetisr(NETISR_IP);
448*7024Ssam 		inq = &ipintrq;
449*7024Ssam 		break;
450*7024Ssam #endif
451*7024Ssam 	default:
452*7024Ssam 		printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
453*7024Ssam 		goto setup;
454*7024Ssam 	}
455*7024Ssam 	if (len == 0)
456*7024Ssam 		goto setup;
457*7024Ssam 	/*
458*7024Ssam 	 * Pull packet off interface.  Off is nonzero if packet
459*7024Ssam 	 * has trailing header; if_rubaget will then force this header
460*7024Ssam 	 * information to be at the front, but we still have to drop
461*7024Ssam 	 * the two-byte type which is at the front of any trailer data.
462*7024Ssam 	 */
463*7024Ssam 	m = if_rubaget(&vs->vs_ifuba, len, off);
464*7024Ssam 	if (m == 0)
465*7024Ssam 		goto setup;
466*7024Ssam 	IF_ENQUEUE(inq, m);
467*7024Ssam 
468*7024Ssam setup:
469*7024Ssam 	/*
470*7024Ssam 	 * Reset for next packet.
471*7024Ssam 	 */
472*7024Ssam 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
473*7024Ssam 	addr->vviba = (u_short) ubainfo;
474*7024Ssam 	addr->vviea = (u_short) (ubainfo >> 16);
475*7024Ssam 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
476*7024Ssam 	addr->vvicsr = VV_RST | VV_CONF;
477*7024Ssam 	addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
478*7024Ssam 
479*7024Ssam }
480*7024Ssam 
481*7024Ssam /*
482*7024Ssam  * V2lni output routine.
483*7024Ssam  * Encapsulate a packet of type family for the local net.
484*7024Ssam  * Use trailer local net encapsulation if enough data in first
485*7024Ssam  * packet leaves a multiple of 512 bytes of data in remainder.
486*7024Ssam  */
487*7024Ssam vvoutput(ifp, m0, dst)
488*7024Ssam 	struct ifnet *ifp;
489*7024Ssam 	struct mbuf *m0;
490*7024Ssam 	struct sockaddr *dst;
491*7024Ssam {
492*7024Ssam 	register struct mbuf *m = m0;
493*7024Ssam 	register struct vv_header *vv;
494*7024Ssam 	int type, dest, s;
495*7024Ssam 
496*7024Ssam 	switch (dst->sa_family) {
497*7024Ssam 
498*7024Ssam #ifdef INET
499*7024Ssam 	case AF_INET: {
500*7024Ssam 		register struct ip *ip = mtod(m0, struct ip *);
501*7024Ssam 		int off;
502*7024Ssam 
503*7024Ssam 		dest = ip->ip_dst.s_addr >> 24;
504*7024Ssam 		type = RING_IP;
505*7024Ssam 		off = 0;
506*7024Ssam 		goto gottype;
507*7024Ssam 		}
508*7024Ssam #endif
509*7024Ssam 	default:
510*7024Ssam 		printf("vv%d: can't handle af%d\n", ifp->if_unit,
511*7024Ssam 			dst->sa_family);
512*7024Ssam 		m_freem(m0);
513*7024Ssam 		return (0);
514*7024Ssam 	}
515*7024Ssam 
516*7024Ssam gottrailertype:
517*7024Ssam 	/*
518*7024Ssam 	 * Packet to be sent as trailer: move first packet
519*7024Ssam 	 * (control information) to end of chain.
520*7024Ssam 	 */
521*7024Ssam 	while (m->m_next)
522*7024Ssam 		m = m->m_next;
523*7024Ssam 	m->m_next = m0;
524*7024Ssam 	m = m0->m_next;
525*7024Ssam 	m0->m_next = 0;
526*7024Ssam 	m0 = m;
527*7024Ssam 
528*7024Ssam gottype:
529*7024Ssam 	/*
530*7024Ssam 	 * Add local net header.  If no space in first mbuf,
531*7024Ssam 	 * allocate another.
532*7024Ssam 	 */
533*7024Ssam 	if (m->m_off > MMAXOFF ||
534*7024Ssam 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
535*7024Ssam 		m = m_get(M_DONTWAIT);
536*7024Ssam 		if (m == 0) {
537*7024Ssam 			m_freem(m0);
538*7024Ssam 			return (0);
539*7024Ssam 		}
540*7024Ssam 		m->m_next = m0;
541*7024Ssam 		m->m_off = MMINOFF;
542*7024Ssam 		m->m_len = sizeof (struct vv_header);
543*7024Ssam 	} else {
544*7024Ssam 		m->m_off -= sizeof (struct vv_header);
545*7024Ssam 		m->m_len += sizeof (struct vv_header);
546*7024Ssam 	}
547*7024Ssam 	vv = mtod(m, struct vv_header *);
548*7024Ssam 	vv->vh_shost = ifp->if_host[0];
549*7024Ssam 	vv->vh_dhost = dest;
550*7024Ssam 	vv->vh_version = RING_VERSION;
551*7024Ssam 	vv->vh_type = type;
552*7024Ssam 	vv->vh_info = m->m_len;
553*7024Ssam 
554*7024Ssam 	/*
555*7024Ssam 	 * Queue message on interface, and start output if interface
556*7024Ssam 	 * not yet active.
557*7024Ssam 	 */
558*7024Ssam 	s = splimp();
559*7024Ssam 	IF_ENQUEUE(&ifp->if_snd, m);
560*7024Ssam 	if (vv_softc[ifp->if_unit].vs_oactive == 0)
561*7024Ssam 		vvstart(ifp->if_unit);
562*7024Ssam 	splx(s);
563*7024Ssam 	return (1);
564*7024Ssam }
565*7024Ssam 
566*7024Ssam #ifdef notdef
567*7024Ssam /*
568*7024Ssam  * vvprt_hdr(s, v) print the local net header in "v"
569*7024Ssam  * 	with title is "s"
570*7024Ssam  */
571*7024Ssam vvprt_hdr(s, v)
572*7024Ssam 	char *s;
573*7024Ssam 	register struct vv_header *v;
574*7024Ssam {
575*7024Ssam 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
576*7024Ssam 		s,
577*7024Ssam 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
578*7024Ssam 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
579*7024Ssam 		0xffff & (int)(v->vh_info));
580*7024Ssam }
581*7024Ssam 
582*7024Ssam /*
583*7024Ssam  * print "l" hex bytes starting at "s"
584*7024Ssam  */
585*7024Ssam vvprt_hex(s, l)
586*7024Ssam 	char *s;
587*7024Ssam 	int l;
588*7024Ssam {
589*7024Ssam 	register int i;
590*7024Ssam 	register int z;
591*7024Ssam 
592*7024Ssam 	for (i=0 ; i < l; i++) {
593*7024Ssam 		z = 0xff & (int)(*(s + i));
594*7024Ssam 		printf("%c%c ",
595*7024Ssam 		"0123456789abcdef"[(z >> 4) & 0x0f],
596*7024Ssam 		"0123456789abcdef"[z & 0x0f]
597*7024Ssam 		);
598*7024Ssam 	}
599*7024Ssam }
600*7024Ssam #endif
601*7024Ssam 
602*7024Ssam #if NIMP == 0 && NVV > 0
603*7024Ssam /*
604*7024Ssam  * Logical host interface driver.
605*7024Ssam  * Allows host to appear as an ARPAnet
606*7024Ssam  * logical host.  Must also have routing
607*7024Ssam  * table entry set up to forward packets
608*7024Ssam  * to appropriate geteway on localnet.
609*7024Ssam  */
610*7024Ssam struct	ifnet vvlhif;
611*7024Ssam int	looutput();
612*7024Ssam 
613*7024Ssam /*
614*7024Ssam  * Called by localnet interface to allow logical
615*7024Ssam  * host interface to "attach".
616*7024Ssam  */
617*7024Ssam vvlhinit(vvifp, addr)
618*7024Ssam 	struct ifnet *vvifp;
619*7024Ssam 	int addr;
620*7024Ssam {
621*7024Ssam 	register struct ifnet *ifp = &vvlhif;
622*7024Ssam 	register struct sockaddr_in *sin;
623*7024Ssam 
624*7024Ssam COUNT(VVLHINIT);
625*7024Ssam 	ifp->if_name = "lh";
626*7024Ssam 	ifp->if_mtu = VVMTU;
627*7024Ssam 	sin = (struct sockaddr_in *)&ifp->if_addr;
628*7024Ssam 	sin->sin_family = AF_INET;
629*7024Ssam 	sin->sin_addr.s_addr = addr;
630*7024Ssam 	ifp->if_net = netpart(sin->sin_addr);
631*7024Ssam 	ifp->if_flags = IFF_UP;
632*7024Ssam 	ifp->if_output = looutput;
633*7024Ssam 	if_attach(ifp);
634*7024Ssam 	rtinit(&ifp->if_addr, &ifp->if_addr, RTF_DIRECT|RTF_UP|RTF_HOST);
635*7024Ssam }
636*7024Ssam #endif
637