xref: /csrg-svn/sys/vax/if/if_vv.c (revision 16581)
1 /*	if_vv.c	6.5	84/06/07	*/
2 
3 #include "vv.h"
4 
5 /*
6  * Proteon 10 Meg Ring Driver.
7  * This device is called "vv" because its "real name",
8  * V2LNI won't work if shortened to the obvious "v2".
9  * Hence the subterfuge.
10  *
11  */
12 #include "../machine/pte.h"
13 
14 #include "../h/param.h"
15 #include "../h/systm.h"
16 #include "../h/mbuf.h"
17 #include "../h/buf.h"
18 #include "../h/protosw.h"
19 #include "../h/socket.h"
20 #include "../h/vmmac.h"
21 #include "../h/errno.h"
22 #include "../h/ioctl.h"
23 
24 #include "../net/if.h"
25 #include "../net/netisr.h"
26 #include "../net/route.h"
27 #include "../netinet/in.h"
28 #include "../netinet/in_systm.h"
29 #include "../netinet/ip.h"
30 #include "../netinet/ip_var.h"
31 
32 #include "../vax/cpu.h"
33 #include "../vax/mtpr.h"
34 #include "../vaxif/if_vv.h"
35 #include "../vaxif/if_uba.h"
36 #include "../vaxuba/ubareg.h"
37 #include "../vaxuba/ubavar.h"
38 
39 /*
40  * N.B. - if WIRECENTER is defined wrong, it can well break
41  * the hardware!!
42  */
43 #define	WIRECENTER
44 
45 #ifdef WIRECENTER
46 #define	VV_CONF	VV_HEN		/* drive wire center relay */
47 #else
48 #define	VV_CONF	VV_STE		/* allow operation without wire center */
49 #endif
50 
51 #define	VVMTU	(1024+512)
52 #define VVMRU	(1024+512+16)	/* space for trailer */
53 
54 int	vv_tracehdr = 0;	/* 1 => trace headers (slowly!!) */
55 int	vv_logreaderrors = 1;	/* 1 => log all read errors */
56 
57 #define vvtracehdr	if (vv_tracehdr) vvprt_hdr
58 
59 int	vvprobe(), vvattach(), vvreset(), vvinit();
60 int	vvidentify(), vvstart(), vvxint(), vvwatchdog();
61 int	vvrint(), vvoutput(), vvioctl(), vvsetaddr();
62 struct	uba_device *vvinfo[NVV];
63 u_short vvstd[] = { 0 };
64 struct	uba_driver vvdriver =
65 	{ vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
66 #define	VVUNIT(x)	minor(x)
67 
68 /*
69  * Software status of each interface.
70  *
71  * Each interface is referenced by a network interface structure,
72  * vs_if, which the routing code uses to locate the interface.
73  * This structure contains the output queue for the interface, its address, ...
74  * We also have, for each interface, a UBA interface structure, which
75  * contains information about the UNIBUS resources held by the interface:
76  * map registers, buffered data paths, etc.  Information is cached in this
77  * structure for use by the if_uba.c routines in running the interface
78  * efficiently.
79  */
80 struct	vv_softc {
81 	struct	ifnet vs_if;		/* network-visible interface */
82 	struct	ifuba vs_ifuba;		/* UNIBUS resources */
83 	short	vs_oactive;		/* is output active */
84 	short	vs_olen;		/* length of last output */
85 	u_short	vs_lastx;		/* address of last packet sent */
86 	u_short	vs_lastr;		/* address of last packet received */
87 	short	vs_tries;		/* transmit current retry count */
88 	short	vs_init;		/* number of ring inits */
89 	short	vs_nottaken;		/* number of packets refused */
90 	short	vs_timeouts;		/* number of transmit timeouts */
91 } vv_softc[NVV];
92 
93 vvprobe(reg)
94 	caddr_t reg;
95 {
96 	register int br, cvec;
97 	register struct vvreg *addr;
98 
99 #ifdef lint
100 	br = 0; cvec = br; br = cvec;
101 #endif
102 	addr = (struct vvreg *)reg;
103 	/* reset interface, enable, and wait till dust settles */
104 	addr->vvicsr = VV_RST;
105 	addr->vvocsr = VV_RST;
106 	DELAY(100000);
107 	/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
108 	addr->vvocsr = VV_IEN;		/* enable interrupt */
109 	addr->vvoba = 0;		/* low 16 bits */
110 	addr->vvoea = 0;		/* extended bits */
111 	addr->vvowc = -1;		/* for 1 word */
112 	addr->vvocsr |= VV_DEN;		/* start the DMA */
113 	DELAY(100000);
114 	addr->vvocsr = 0;
115 	if (cvec && cvec != 0x200)
116 		cvec -= 4;		/* backup so vector => receive */
117 	return(1);
118 }
119 
120 /*
121  * Interface exists: make available by filling in network interface
122  * record.  System will initialize the interface when it is ready
123  * to accept packets.
124  */
125 vvattach(ui)
126 	struct uba_device *ui;
127 {
128 	register struct vv_softc *vs;
129 
130 	vs = &vv_softc[ui->ui_unit];
131 	vs->vs_if.if_unit = ui->ui_unit;
132 	vs->vs_if.if_name = "vv";
133 	vs->vs_if.if_mtu = VVMTU;
134 	vs->vs_if.if_init = vvinit;
135 	vs->vs_if.if_ioctl = vvioctl;
136 	vs->vs_if.if_output = vvoutput;
137 	vs->vs_if.if_reset = vvreset;
138 	vs->vs_if.if_timer = 0;
139 	vs->vs_if.if_watchdog = vvwatchdog;
140 	vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
141 #if defined(VAX750)
142 	/* don't chew up 750 bdp's */
143 	if (cpu == VAX_750 && ui->ui_unit > 0)
144 		vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP;
145 #endif
146 	if_attach(&vs->vs_if);
147 }
148 
149 /*
150  * Reset of interface after UNIBUS reset.
151  * If interface is on specified uba, reset its state.
152  */
153 vvreset(unit, uban)
154 	int unit, uban;
155 {
156 	register struct uba_device *ui;
157 
158 	if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
159 	    ui->ui_ubanum != uban)
160 		return;
161 	printf(" vv%d", unit);
162 	vvinit(unit);
163 }
164 
165 /*
166  * Initialization of interface; clear recorded pending
167  * operations, and reinitialize UNIBUS usage.
168  */
169 vvinit(unit)
170 	int unit;
171 {
172 	register struct vv_softc *vs;
173 	register struct uba_device *ui;
174 	register struct vvreg *addr;
175 	register struct sockaddr_in *sin;
176 	register int ubainfo, s;
177 
178 	vs = &vv_softc[unit];
179 	ui = vvinfo[unit];
180 	sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
181 	/*
182 	 * If the network number is still zero, we've been
183 	 * called too soon.
184 	 */
185 	if (in_netof(sin->sin_addr) == 0)
186 		return;
187 	addr = (struct vvreg *)ui->ui_addr;
188 	if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
189 	    sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
190 		printf("vv%d: can't initialize, if_ubainit() failed\n", unit);
191 		vs->vs_if.if_flags &= ~IFF_UP;
192 		return;
193 	}
194 	/*
195 	 * Now that the uba is set up, figure out our address and
196 	 * update complete our host address.
197 	 */
198 	if ((vs->vs_if.if_host[0] = vvidentify(unit)) == 0) {
199 		vs->vs_if.if_flags &= ~IFF_UP;
200 		return;
201 	}
202 	printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
203 	sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
204 	/*
205 	 * Reset the interface, and join the ring
206 	 */
207 	addr->vvocsr = VV_RST | VV_CPB;		/* clear packet buffer */
208 	addr->vvicsr = VV_RST | VV_CONF;	/* close logical relay */
209 	DELAY(500000);				/* let contacts settle */
210 	vs->vs_init = 0;
211 	vs->vs_nottaken = 0;
212 	vs->vs_timeouts = 0;
213 	vs->vs_lastx = 256;			/* an invalid address */
214 	vs->vs_lastr = 256;			/* an invalid address */
215 	/*
216 	 * Hang a receive and start any
217 	 * pending writes by faking a transmit complete.
218 	 */
219 	s = splimp();
220 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
221 	addr->vviba = (u_short)ubainfo;
222 	addr->vviea = (u_short)(ubainfo >> 16);
223 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
224 	addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
225 	vs->vs_oactive = 1;
226 	vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING;
227 	vvxint(unit);
228 	splx(s);
229 	if_rtinit(&vs->vs_if, RTF_UP);
230 }
231 
232 /*
233  * Return our host address.
234  */
235 vvidentify(unit)
236 	int unit;
237 {
238 	register struct vv_softc *vs;
239 	register struct uba_device *ui;
240 	register struct vvreg *addr;
241 	register struct mbuf *m;
242 	register struct vv_header *v;
243 	register int ubainfo, attempts, waitcount;
244 
245 	/*
246 	 * Build a multicast message to identify our address
247 	 */
248 	vs = &vv_softc[unit];
249 	ui = vvinfo[unit];
250 	addr = (struct vvreg *)ui->ui_addr;
251 	attempts = 0;		/* total attempts, including bad msg type */
252 	m = m_get(M_DONTWAIT, MT_HEADER);
253 	if (m == NULL) {
254 		printf("vv%d: can't initialize, m_get() failed\n", unit);
255 		return (0);
256 	}
257 	m->m_next = 0;
258 	m->m_off = MMINOFF;
259 	m->m_len = sizeof(struct vv_header);
260 	v = mtod(m, struct vv_header *);
261 	v->vh_dhost = VV_BROADCAST;	/* multicast destination address */
262 	v->vh_shost = 0;		/* will be overwritten with ours */
263 	v->vh_version = RING_VERSION;
264 	v->vh_type = RING_WHOAMI;
265 	v->vh_info = 0;
266 	/* map xmit message into uba */
267 	vs->vs_olen =  if_wubaput(&vs->vs_ifuba, m);
268 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
269 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
270 	/*
271 	 * Reset interface, establish Digital Loopback Mode, and
272 	 * send the multicast (to myself) with Input Copy enabled.
273 	 */
274 retry:
275 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
276 	addr->vvicsr = VV_RST;
277 	addr->vviba = (u_short) ubainfo;
278 	addr->vviea = (u_short) (ubainfo >> 16);
279 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
280 	addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
281 
282 	/* let flag timers fire so ring will initialize */
283 	DELAY(2000000);			/* about 2 SECONDS on a 780!! */
284 
285 	addr->vvocsr = VV_RST | VV_CPB;	/* clear packet buffer */
286 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
287 	addr->vvoba = (u_short) ubainfo;
288 	addr->vvoea = (u_short) (ubainfo >> 16);
289 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
290 	addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
291 	/*
292 	 * Wait for receive side to finish.
293 	 * Extract source address (which will be our own),
294 	 * and post to interface structure.
295 	 */
296 	DELAY(10000);
297 	for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
298 		if (waitcount < 10) {
299 			DELAY(1000);
300 			continue;
301 		}
302 		if (attempts++ < VVIDENTRETRY)
303 			goto retry;
304 	}
305 	/* deallocate mbuf used for send packet */
306 	if (vs->vs_ifuba.ifu_xtofree) {
307 		m_freem(vs->vs_ifuba.ifu_xtofree);
308 		vs->vs_ifuba.ifu_xtofree = 0;
309 	}
310 	if (attempts >= VVIDENTRETRY) {
311 		printf("vv%d: can't initialize after %d tries, icsr = %b\n",
312 		    unit, VVIDENTRETRY, 0xffff&(addr->vvicsr), VV_IBITS);
313 		return (0);
314 	}
315 	/* Purge BDP before looking at packet we just received */
316 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
317 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
318 	m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
319 	if (m != NULL)
320 		m_freem(m);
321 	/*
322 	 * Check message type before we believe the source host address
323 	 */
324 	v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
325 	if (v->vh_type != RING_WHOAMI)
326 		goto retry;
327 	return(v->vh_shost);
328 }
329 
330 /*
331  * Start or restart output on interface.
332  * If interface is active, this is a retransmit, so just
333  * restuff registers and go.
334  * If interface is not already active, get another datagram
335  * to send off of the interface queue, and map it to the interface
336  * before starting the output.
337  */
338 vvstart(dev)
339 	dev_t dev;
340 {
341 	register struct uba_device *ui;
342 	register struct vv_softc *vs;
343 	register struct vvreg *addr;
344 	register struct mbuf *m;
345 	register int unit, ubainfo, dest, s;
346 
347 	unit = VVUNIT(dev);
348 	ui = vvinfo[unit];
349 	vs = &vv_softc[unit];
350 	if (vs->vs_oactive)
351 		goto restart;
352 	/*
353 	 * Not already active: dequeue another request
354 	 * and map it to the UNIBUS.  If no more requests,
355 	 * just return.
356 	 */
357 	s = splimp();
358 	IF_DEQUEUE(&vs->vs_if.if_snd, m);
359 	splx(s);
360 	if (m == NULL) {
361 		vs->vs_oactive = 0;
362 		return;
363 	}
364 	dest = mtod(m, struct vv_header *)->vh_dhost;
365 	vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
366 	vs->vs_lastx = dest;
367 restart:
368 	/*
369 	 * Have request mapped to UNIBUS for transmission.
370 	 * Purge any stale data from this BDP, and start the output.
371 	 *
372 	 * Make sure this packet will fit in the interface.
373 	 */
374 	if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) {
375 		printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
376 		panic("vvdriver vs_olen botch");
377 	}
378 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
379 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
380 	addr = (struct vvreg *)ui->ui_addr;
381 	ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
382 	addr->vvoba = (u_short) ubainfo;
383 	addr->vvoea = (u_short) (ubainfo >> 16);
384 	addr->vvowc = -((vs->vs_olen + 1) >> 1);
385 	addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
386 	vs->vs_if.if_timer = VVTIMEOUT;
387 	vs->vs_oactive = 1;
388 }
389 
390 /*
391  * VVLNI transmit interrupt
392  * Start another output if more data to send.
393  */
394 vvxint(unit)
395 	int unit;
396 {
397 	register struct uba_device *ui;
398 	register struct vv_softc *vs;
399 	register struct vvreg *addr;
400 	register int oc;
401 
402 	ui = vvinfo[unit];
403 	vs = &vv_softc[unit];
404 	vs->vs_if.if_timer = 0;
405 	addr = (struct vvreg *)ui->ui_addr;
406 	oc = 0xffff & (addr->vvocsr);
407 	if (vs->vs_oactive == 0) {
408 		printf("vv%d: stray interrupt vvocsr = %b\n", unit,
409 		    oc, VV_OBITS);
410 		return;
411 	}
412 	if (oc &  (VV_OPT | VV_RFS)) {
413 		vs->vs_if.if_collisions++;
414 		if (vs->vs_tries++ < VVRETRY) {
415 			if (oc & VV_OPT)
416 				vs->vs_init++;
417 			if (oc & VV_RFS)
418 				vs->vs_nottaken++;
419 			vvstart(unit);		/* restart this message */
420 			return;
421 		}
422 		if (oc & VV_OPT)
423 			printf("vv%d: output timeout\n", unit);
424 	}
425 	vs->vs_if.if_opackets++;
426 	vs->vs_oactive = 0;
427 	vs->vs_tries = 0;
428 	if (oc & VVXERR) {
429 		vs->vs_if.if_oerrors++;
430 		printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
431 		    VV_OBITS);
432 	}
433 	if (vs->vs_ifuba.ifu_xtofree) {
434 		m_freem(vs->vs_ifuba.ifu_xtofree);
435 		vs->vs_ifuba.ifu_xtofree = 0;
436 	}
437 	vvstart(unit);
438 }
439 
440 /*
441  * Transmit watchdog timer routine.
442  * This routine gets called when we lose a transmit interrupt.
443  * The best we can do is try to restart output.
444  */
445 vvwatchdog(unit)
446 	int unit;
447 {
448 	register struct vv_softc *vs;
449 	register int s;
450 
451 	vs = &vv_softc[unit];
452 	if (vs->vs_if.if_flags & IFF_DEBUG)
453 		printf("vv%d: lost a transmit interrupt.\n", unit);
454 	vs->vs_timeouts++;
455 	s = splimp();
456 	vvstart(unit);
457 	splx(s);
458 }
459 
460 /*
461  * V2lni interface receiver interrupt.
462  * If input error just drop packet.
463  * Otherwise purge input buffered data path and examine
464  * packet to determine type.  If can't determine length
465  * from type, then have to drop packet.  Otherwise decapsulate
466  * packet based on type and pass to type specific higher-level
467  * input routine.
468  */
469 vvrint(unit)
470 	int unit;
471 {
472 	register struct vv_softc *vs;
473 	register struct vvreg *addr;
474 	register struct vv_header *vv;
475 	register struct ifqueue *inq;
476 	register struct mbuf *m;
477 	int ubainfo, len, off, s;
478 	short resid;
479 
480 	vs = &vv_softc[unit];
481 	vs->vs_if.if_ipackets++;
482 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
483 	/*
484 	 * Purge BDP; drop if input error indicated.
485 	 */
486 	if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
487 		UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
488 	if (addr->vvicsr & VVRERR) {
489 		if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
490 			printf("vv%d: VVRERR, vvicsr = %b\n", unit,
491 			    0xffff&(addr->vvicsr), VV_IBITS);
492 		goto dropit;
493 	}
494 
495 	/*
496 	 * Get packet length from word count residue
497 	 *
498 	 * Compute header offset if trailer protocol
499 	 *
500 	 * Pull packet off interface.  Off is nonzero if packet
501 	 * has trailing header; if_rubaget will then force this header
502 	 * information to be at the front.  The vh_info field
503 	 * carries the offset to the trailer data in trailer
504 	 * format packets.
505 	 */
506 	vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
507 	vvtracehdr("vi", vv);
508 	resid = addr->vviwc;
509 	if (resid)
510 		resid |= 0176000;		/* ugly!!!! */
511 	len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
512 	len -= sizeof(struct vv_header);
513 	if (len > VVMRU || len <= 0) {
514 		if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
515 			printf("vv%d: len too big, len = %d, vvicsr = %b\n",
516 			    unit, len, 0xffff&(addr->vvicsr), VV_IBITS);
517 		goto dropit;
518 	}
519 #define	vvdataaddr(vv, off, type)	((type)(((caddr_t)((vv)+1)+(off))))
520 	if (vv->vh_type >= RING_IPTrailer &&
521 	     vv->vh_type < RING_IPTrailer+RING_IPNTrailer) {
522 		off = (vv->vh_type - RING_IPTrailer) * 512;
523 		if (off > VVMTU) {
524 			if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
525 				printf("vv%d: VVMTU, off = %d, vvicsr = %b\n",
526 				    unit, off, 0xffff&(addr->vvicsr), VV_IBITS);
527 			goto dropit;
528 		}
529 		vv->vh_type = *vvdataaddr(vv, off, u_short *);
530 		resid = *(vvdataaddr(vv, off+2, u_short *));
531 		if (off + resid > len) {
532 			if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
533 				printf(
534 				    "vv%d: off = %d, resid = %d, vvicsr = %b\n",
535 				    unit, off, resid,
536 				    0xffff&(addr->vvicsr), VV_IBITS);
537 			goto dropit;
538 		}
539 		len = off + resid;
540 	} else
541 		off = 0;
542 	if (len == 0) {
543 		if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
544 			printf("vv%d: len is zero, vvicsr = %b\n", unit,
545 			    0xffff&(addr->vvicsr), VV_IBITS);
546 		goto dropit;
547 	}
548 	m = if_rubaget(&vs->vs_ifuba, len, off);
549 	if (m == NULL) {
550 		if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG)
551 			printf("vv%d: if_rubaget failed, vvicsr = %b\n", unit,
552 			    0xffff&(addr->vvicsr), VV_IBITS);
553 		goto dropit;
554 	}
555 	if (off) {
556 		m->m_off += 2 * sizeof(u_short);
557 		m->m_len -= 2 * sizeof(u_short);
558 	}
559 
560 	/* Keep track of source address of this packet */
561 	vs->vs_lastr = vv->vh_shost;
562 	/*
563 	 * Demultiplex on packet type
564 	 */
565 	switch (vv->vh_type) {
566 
567 #ifdef INET
568 	case RING_IP:
569 		schednetisr(NETISR_IP);
570 		inq = &ipintrq;
571 		break;
572 #endif
573 	default:
574 		printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
575 		m_freem(m);
576 		goto setup;
577 	}
578 	s = splimp();
579 	if (IF_QFULL(inq)) {
580 		IF_DROP(inq);
581 		m_freem(m);
582 	} else
583 		IF_ENQUEUE(inq, m);
584 
585 	splx(s);
586 	/*
587 	 * Reset for the next packet.
588 	 */
589 setup:
590 	ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
591 	addr->vviba = (u_short) ubainfo;
592 	addr->vviea = (u_short) (ubainfo >> 16);
593 	addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
594 	addr->vvicsr = VV_RST | VV_CONF;
595 	addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
596 	return;
597 
598 	/*
599 	 * Drop packet on floor -- count them!!
600 	 */
601 dropit:
602 	vs->vs_if.if_ierrors++;
603 	goto setup;
604 }
605 
606 /*
607  * V2lni output routine.
608  * Encapsulate a packet of type family for the local net.
609  * Use trailer local net encapsulation if enough data in first
610  * packet leaves a multiple of 512 bytes of data in remainder.
611  */
612 vvoutput(ifp, m0, dst)
613 	struct ifnet *ifp;
614 	struct mbuf *m0;
615 	struct sockaddr *dst;
616 {
617 	register struct mbuf *m;
618 	register struct vv_header *vv;
619 	register int off;
620 	register int unit;
621 	register struct vvreg *addr;
622 	register struct vv_softc *vs;
623 	register int s;
624 	int type, dest, error;
625 
626 	m = m0;
627 	unit = ifp->if_unit;
628 	addr = (struct vvreg *)vvinfo[unit]->ui_addr;
629 	vs = &vv_softc[unit];
630 	/*
631 	 * Check to see if the input side has wedged.
632 	 *
633 	 * We are lower than device ipl when we enter this routine,
634 	 * so if the interface is ready with an input packet then
635 	 * an input interrupt must have slipped through the cracks.
636 	 *
637 	 * Avoid the race with an input interrupt by watching to see
638 	 * if any packets come in.
639 	 */
640 	s = vs->vs_if.if_ipackets;
641 	if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) {
642 		if (vs->vs_if.if_flags & IFF_DEBUG)
643 			printf("vv%d: lost a receive interrupt, icsr = %b\n",
644 			    unit, 0xffff&(addr->vvicsr), VV_IBITS);
645 		s = splimp();
646 		vvrint(unit);
647 		splx(s);
648 	}
649 
650 	switch (dst->sa_family) {
651 
652 #ifdef INET
653 	case AF_INET:
654 		dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
655 		if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
656 			error = EPERM;
657 			goto bad;
658 		}
659 		off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
660 		/* Need per host negotiation. */
661 		if ((ifp->if_flags & IFF_NOTRAILERS) == 0)
662 		if (off > 0 && (off & 0x1ff) == 0 &&
663 		    m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
664 			type = RING_IPTrailer + (off>>9);
665 			m->m_off -= 2 * sizeof (u_short);
666 			m->m_len += 2 * sizeof (u_short);
667 			*mtod(m, u_short *) = RING_IP;
668 			*(mtod(m, u_short *) + 1) = m->m_len;
669 			goto gottrailertype;
670 		}
671 		type = RING_IP;
672 		off = 0;
673 		goto gottype;
674 #endif
675 	default:
676 		printf("vv%d: can't handle af%d\n", unit, dst->sa_family);
677 		error = EAFNOSUPPORT;
678 		goto bad;
679 	}
680 
681 gottrailertype:
682 	/*
683 	 * Packet to be sent as trailer: move first packet
684 	 * (control information) to end of chain.
685 	 */
686 	while (m->m_next)
687 		m = m->m_next;
688 	m->m_next = m0;
689 	m = m0->m_next;
690 	m0->m_next = 0;
691 	m0 = m;
692 gottype:
693 	/*
694 	 * Add local net header.  If no space in first mbuf,
695 	 * allocate another.
696 	 */
697 	if (m->m_off > MMAXOFF ||
698 	    MMINOFF + sizeof (struct vv_header) > m->m_off) {
699 		m = m_get(M_DONTWAIT, MT_HEADER);
700 		if (m == NULL) {
701 			error = ENOBUFS;
702 			goto bad;
703 		}
704 		m->m_next = m0;
705 		m->m_off = MMINOFF;
706 		m->m_len = sizeof (struct vv_header);
707 	} else {
708 		m->m_off -= sizeof (struct vv_header);
709 		m->m_len += sizeof (struct vv_header);
710 	}
711 	vv = mtod(m, struct vv_header *);
712 	vv->vh_shost = ifp->if_host[0];
713 	/* Map the destination address if it's a broadcast */
714 	if ((vv->vh_dhost = dest) == INADDR_ANY)
715 		vv->vh_dhost = VV_BROADCAST;
716 	vv->vh_version = RING_VERSION;
717 	vv->vh_type = type;
718 	vv->vh_info = off;
719 	vvtracehdr("vo", vv);
720 
721 	/*
722 	 * Queue message on interface, and start output if interface
723 	 * not yet active.
724 	 */
725 	s = splimp();
726 	if (IF_QFULL(&ifp->if_snd)) {
727 		IF_DROP(&ifp->if_snd);
728 		error = ENOBUFS;
729 		goto qfull;
730 	}
731 	IF_ENQUEUE(&ifp->if_snd, m);
732 	if (vs->vs_oactive == 0)
733 		vvstart(unit);
734 	splx(s);
735 	return (0);
736 qfull:
737 	m0 = m;
738 	splx(s);
739 bad:
740 	m_freem(m0);
741 	return(error);
742 }
743 
744 /*
745  * Process an ioctl request.
746  */
747 vvioctl(ifp, cmd, data)
748 	register struct ifnet *ifp;
749 	int cmd;
750 	caddr_t data;
751 {
752 	register struct ifreq *ifr;
753 	register int s;
754 	int error;
755 
756 	ifr = (struct ifreq *)data;
757 	error = 0;
758 	s = splimp();
759 	switch (cmd) {
760 
761 	case SIOCSIFADDR:
762 		if (ifp->if_flags & IFF_RUNNING)
763 			if_rtinit(ifp, -1);	/* delete previous route */
764 		vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr);
765 		if (ifp->if_flags & IFF_RUNNING)
766 			if_rtinit(ifp, RTF_UP);
767 		else
768 			vvinit(ifp->if_unit);
769 		break;
770 
771 	default:
772 		error = EINVAL;
773 	}
774 	splx(s);
775 	return(error);
776 }
777 
778 /*
779  * Set up the address for this interface. We use the network number
780  * from the passed address and an invalid host number; vvinit() will
781  * figure out the host number and insert it later.
782  */
783 vvsetaddr(ifp, sin)
784 	register struct ifnet *ifp;
785 	register struct sockaddr_in *sin;
786 {
787 	ifp->if_net = in_netof(sin->sin_addr);
788 	ifp->if_host[0] = 256;			/* an invalid host number */
789 	sin = (struct sockaddr_in *)&ifp->if_addr;
790 	sin->sin_family = AF_INET;
791 	sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]);
792 	sin = (struct sockaddr_in *)&ifp->if_broadaddr;
793 	sin->sin_family = AF_INET;
794 	sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY);
795 	ifp->if_flags |= IFF_BROADCAST;
796 }
797 
798 /*
799  * vvprt_hdr(s, v) print the local net header in "v"
800  *	with title is "s"
801  */
802 vvprt_hdr(s, v)
803 	char *s;
804 	register struct vv_header *v;
805 {
806 	printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
807 		s,
808 		0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
809 		0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
810 		0xffff & (int)(v->vh_info));
811 }
812 
813 #ifdef notdef
814 /*
815  * print "l" hex bytes starting at "s"
816  */
817 vvprt_hex(s, l)
818 	char *s;
819 	int l;
820 {
821 	register int i;
822 	register int z;
823 
824 	for (i=0 ; i < l; i++) {
825 		z = 0xff & (int)(*(s + i));
826 		printf("%c%c ",
827 		"0123456789abcdef"[(z >> 4) & 0x0f],
828 		"0123456789abcdef"[z & 0x0f]
829 		);
830 	}
831 }
832 #endif
833