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