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