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