BSD 4_2 development
[unix-history] / .ref-BSD-4_1c_2 / a / sys / vaxif / if_vv.c
CommitLineData
e9c22e58
C
1/* if_vv.c 4.14 83/02/21 */
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 * UNTESTED WITH 4.1C
12 */
13#include "../machine/pte.h"
14
15#include "../h/param.h"
16#include "../h/systm.h"
17#include "../h/mbuf.h"
18#include "../h/buf.h"
19#include "../h/protosw.h"
20#include "../h/socket.h"
21#include "../h/vmmac.h"
22#include "../h/errno.h"
23#include "../h/time.h"
24#include "../h/kernel.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
59int vv_dotrailer = 0, /* 1 => do trailer protocol */
60 vv_tracehdr = 0, /* 1 => trace headers (slowly!!) */
61 vv_tracetimeout = 1; /* 1 => trace input error-rate limiting */
62 vv_logreaderrors = 0; /* 1 => log all read errors */
63
64#define vvtracehdr if (vv_tracehdr) vvprt_hdr
65#define vvtrprintf if (vv_tracetimeout) printf
66
67int vv_ticking = 0; /* error flywheel is running */
68
69/*
70 * Interval in HZ - 50 msec.
71 * N.B. all times below are in units of flywheel ticks
72 */
73#define VV_FLYWHEEL 3
74#define VV_ERRORTHRESHOLD 100 /* errors/flywheel-interval */
75#define VV_MODE1ATTEMPTS 10 /* number mode 1 retries */
76#define VV_MODE1DELAY 2 /* period interface is PAUSEd - 100ms */
77#define VV_MODE2DELAY 4 /* base interval host relay is off - 200ms */
78#define VV_MAXDELAY 6400 /* max interval host relay is off - 2 minutes */
79
80int vvprobe(), vvattach(), vvrint(), vvxint();
81struct uba_device *vvinfo[NVV];
82u_short vvstd[] = { 0 };
83struct uba_driver vvdriver =
84 { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo };
85#define VVUNIT(x) minor(x)
86int vvinit(),vvoutput(),vvreset();
87
88/*
89 * Software status of each interface.
90 *
91 * Each interface is referenced by a network interface structure,
92 * vs_if, which the routing code uses to locate the interface.
93 * This structure contains the output queue for the interface, its address, ...
94 * We also have, for each interface, a UBA interface structure, which
95 * contains information about the UNIBUS resources held by the interface:
96 * map registers, buffered data paths, etc. Information is cached in this
97 * structure for use by the if_uba.c routines in running the interface
98 * efficiently.
99 */
100struct vv_softc {
101 struct ifnet vs_if; /* network-visible interface */
102 struct ifuba vs_ifuba; /* UNIBUS resources */
103 short vs_oactive; /* is output active */
104 short vs_iactive; /* is input active */
105 short vs_olen; /* length of last output */
106 u_short vs_lastx; /* last destination address */
107 short vs_tries; /* transmit current retry count */
108 short vs_init; /* number of ring inits */
109 short vs_nottaken; /* number of packets refused */
110 /* input error rate limiting state */
111 short vs_major; /* recovery major state */
112 short vs_minor; /* recovery minor state */
113 short vs_retry; /* recovery retry count */
114 short vs_delayclock; /* recovery delay clock */
115 short vs_delayrange; /* increasing delay interval */
116 short vs_dropped; /* number of packes tossed in last dt */
117} vv_softc[NVV];
118
119/*
120 * States of vs_iactive.
121 */
122#define ACTIVE 1 /* interface should post new receives */
123#define PAUSE 0 /* interface should NOT post new receives */
124#define OPEN -1 /* PAUSE and open host relay */
125
126/*
127 * Recovery major states.
128 */
129#define MODE0 0 /* everything is wonderful */
130#define MODE1 1 /* hopefully whatever will go away */
131#define MODE2 2 /* drastic measures - open host relay for increasing intervals */
132
133vvprobe(reg)
134 caddr_t reg;
135{
136 register int br, cvec;
137 register struct vvreg *addr = (struct vvreg *)reg;
138
139#ifdef lint
140 br = 0; cvec = br; br = cvec;
141#endif
142 /* reset interface, enable, and wait till dust settles */
143 addr->vvicsr = VV_RST;
144 addr->vvocsr = VV_RST;
145 DELAY(100000);
146 /* generate interrupt by doing 1 word DMA from 0 in uba space!! */
147 addr->vvocsr = VV_IEN; /* enable interrupt */
148 addr->vvoba = 0; /* low 16 bits */
149 addr->vvoea = 0; /* extended bits */
150 addr->vvowc = -1; /* for 1 word */
151 addr->vvocsr |= VV_DEN; /* start the DMA */
152 DELAY(100000);
153 addr->vvocsr = 0;
154 if (cvec && cvec != 0x200)
155 cvec -= 4; /* backup so vector => recieve */
156 return(1);
157}
158
159/*
160 * Interface exists: make available by filling in network interface
161 * record. System will initialize the interface when it is ready
162 * to accept packets.
163 */
164vvattach(ui)
165 struct uba_device *ui;
166{
167 register struct vv_softc *vs = &vv_softc[ui->ui_unit];
168 register struct sockaddr_in *sin;
169
170 vs->vs_if.if_unit = ui->ui_unit;
171 vs->vs_if.if_name = "vv";
172 vs->vs_if.if_mtu = VVMTU;
173 vs->vs_if.if_net = ui->ui_flags;
174 vs->vs_if.if_host[0] = 0; /* this will be reset in vvinit() */
175 sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
176 sin->sin_family = AF_INET;
177 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
178 sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr;
179 sin->sin_family = AF_INET;
180 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST);
181 vs->vs_if.if_flags = IFF_BROADCAST;
182 vs->vs_if.if_init = vvinit;
183 vs->vs_if.if_output = vvoutput;
184 vs->vs_if.if_reset = vvreset;
185 vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16;
186 if_attach(&vs->vs_if);
187}
188
189/*
190 * Reset of interface after UNIBUS reset.
191 * If interface is on specified uba, reset its state.
192 */
193vvreset(unit, uban)
194 int unit, uban;
195{
196 register struct uba_device *ui;
197
198 if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 ||
199 ui->ui_ubanum != uban)
200 return;
201 printf(" vv%d", unit);
202 vvinit(unit);
203}
204
205/*
206 * Initialization of interface; clear recorded pending
207 * operations, and reinitialize UNIBUS usage.
208 */
209vvinit(unit)
210 int unit;
211{
212 register struct vv_softc *vs = &vv_softc[unit];
213 register struct uba_device *ui = vvinfo[unit];
214 register struct vvreg *addr;
215 struct sockaddr_in *sin;
216 int ubainfo, s;
217 int vvtimeout();
218
219 addr = (struct vvreg *)ui->ui_addr;
220 if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum,
221 sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) {
222 printf("vv%d: can't initialize\n", unit);
223 vs->vs_if.if_flags &= ~IFF_UP;
224 return;
225 }
226 if (vv_ticking++ == 0)
227 timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
228 /*
229 * Discover our host address and post it
230 */
231 vs->vs_if.if_host[0] = vvidentify(unit);
232 printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]);
233 sin = (struct sockaddr_in *)&vs->vs_if.if_addr;
234 sin->sin_family = AF_INET;
235 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]);
236
237 /*
238 * Reset the interface, and join the ring
239 */
240 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
241 addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */
242 sleep((caddr_t)&lbolt, PZERO); /* let contacts settle */
243 vs->vs_init = 0;
244 vs->vs_dropped = 0;
245 vs->vs_nottaken = 0;
246
247 /*
248 * Hang a receive and start any
249 * pending writes by faking a transmit complete.
250 */
251 s = splimp();
252 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
253 addr->vviba = (u_short) ubainfo;
254 addr->vviea = (u_short) (ubainfo >> 16);
255 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
256 addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB;
257 vs->vs_iactive = ACTIVE;
258 vs->vs_oactive = 1;
259 vs->vs_if.if_flags |= IFF_UP;
260 vvxint(unit);
261 splx(s);
262 if_rtinit(&vs->vs_if, RTF_UP);
263}
264
265/*
266 * vvidentify() - return our host address
267 */
268vvidentify(unit)
269{
270 register struct vv_softc *vs = &vv_softc[unit];
271 register struct uba_device *ui = vvinfo[unit];
272 register struct vvreg *addr;
273 struct mbuf *m;
274 struct vv_header *v;
275 int ubainfo, retrying, attempts, waitcount, s;
276
277 /*
278 * Build a multicast message to identify our address
279 */
280 addr = (struct vvreg *)ui->ui_addr;
281 attempts = 0; /* total attempts, including bad msg type */
282 retrying = 0; /* first time through */
283 m = m_get(M_DONTWAIT, MT_HEADER);
284 if (m == 0)
285 panic("vvinit: can't get mbuf");
286 m->m_next = 0;
287 m->m_off = MMINOFF;
288 m->m_len = sizeof(struct vv_header);
289 v = mtod(m, struct vv_header *);
290 v->vh_dhost = VV_BROADCAST; /* multicast destination address */
291 v->vh_shost = 0; /* will be overwritten with ours */
292 v->vh_version = RING_VERSION;
293 v->vh_type = RING_WHOAMI;
294 v->vh_info = 0;
295 /* map xmit message into uba */
296 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
297 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
298 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
299 /*
300 * Reset interface, establish Digital Loopback Mode, and
301 * send the multicast (to myself) with Input Copy enabled.
302 */
303retry:
304 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
305 addr->vvicsr = VV_RST;
306 addr->vviba = (u_short) ubainfo;
307 addr->vviea = (u_short) (ubainfo >> 16);
308 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
309 addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB;
310
311 /* let flag timers fire so ring will initialize */
312 sleep((caddr_t) &lbolt, PZERO);
313 sleep((caddr_t) &lbolt, PZERO);
314
315 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */
316 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
317 addr->vvoba = (u_short) ubainfo;
318 addr->vvoea = (u_short) (ubainfo >> 16);
319 addr->vvowc = -((vs->vs_olen + 1) >> 1);
320 addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB;
321 /*
322 * Wait for receive side to finish.
323 * Extract source address (which will our own),
324 * and post to interface structure.
325 */
326 DELAY(1000);
327 for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) {
328 if (waitcount < 10) {
329 DELAY(1000);
330 continue;
331 }
332 if (attempts++ >= 10) {
333 printf("vv%d: can't initialize\n", unit);
334 printf("vvinit loopwait: icsr = %b\n",
335 0xffff&(addr->vvicsr), VV_IBITS);
336 vs->vs_if.if_flags &= ~IFF_UP;
337 return;
338 }
339 goto retry;
340 }
341 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
342 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
343 if (vs->vs_ifuba.ifu_xtofree)
344 m_freem(vs->vs_ifuba.ifu_xtofree);
345 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
346 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
347 m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0);
348 if (m != NULL)
349 m_freem(m);
350 /*
351 * Check message type before we believe the source host address
352 */
353 v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
354 if (v->vh_type != RING_WHOAMI)
355 goto retry;
356 return(v->vh_shost);
357}
358
359/*
360 * vvtimeout() - called by timer flywheel to monitor input packet
361 * discard rate. Interfaces getting too many errors are shut
362 * down for a while. If the condition persists, the interface
363 * is marked down.
364 */
365vvtimeout(junk)
366 int junk;
367{
368 register struct vv_softc *vs;
369 register int i;
370 register struct vvreg *addr;
371 int ubainfo;
372
373 timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL);
374 for (i = 0; i < NVV; i++) {
375 vs = &vv_softc[i];
376 addr = (struct vvreg *)vvinfo[i]->ui_addr;
377 if (vs->vs_if.if_flags & IFF_UP == 0) continue;
378 switch (vs->vs_major) {
379
380 /*
381 * MODE0: generally OK, just check error rate
382 */
383 case MODE0:
384 if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
385 vs->vs_dropped = 0;
386 continue;
387 }
388 /* suspend reads for a while */
389 vvtrprintf("vv%d going MODE1 in vvtimeout\n",i);
390 vs->vs_major = MODE1;
391 vs->vs_iactive = PAUSE; /* no new reads */
392 vs->vs_retry = VV_MODE1ATTEMPTS;
393 vs->vs_delayclock = VV_MODE1DELAY;
394 vs->vs_minor = 0;
395 continue;
396
397 /*
398 * MODE1: excessive error rate observed
399 * Scheme: try simply suspending reads for a
400 * short while a small number of times
401 */
402 case MODE1:
403 if (vs->vs_delayclock > 0) {
404 vs->vs_delayclock--;
405 continue;
406 }
407 switch (vs->vs_minor) {
408
409 case 0: /* reenable reads */
410 vvtrprintf("vv%d M1m0\n",i);
411 vs->vs_dropped = 0;
412 vs->vs_iactive = ACTIVE;
413 vs->vs_minor = 1; /* next state */
414 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
415 addr->vviba = (u_short) ubainfo;
416 addr->vviea = (u_short) (ubainfo >> 16);
417 addr->vviwc =
418 -(sizeof (struct vv_header) + VVMTU) >> 1;
419 addr->vvicsr = VV_RST | VV_CONF;
420 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
421 continue;
422
423 case 1: /* see if it worked */
424 vvtrprintf("vv%d M1m1\n",i);
425 if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
426 vs->vs_dropped = 0;
427 vs->vs_major = MODE0; /* yeah!! */
428 continue;
429 }
430 if (vs->vs_retry -- > 0) {
431 vs->vs_dropped = 0;
432 vs->vs_iactive = PAUSE;
433 vs->vs_delayclock = VV_MODE1DELAY;
434 vs->vs_minor = 0; /* recheck */
435 continue;
436 }
437 vs->vs_major = MODE2;
438 vs->vs_minor = 0;
439 vs->vs_dropped = 0;
440 vs->vs_iactive = OPEN;
441 vs->vs_delayrange = VV_MODE2DELAY;
442 vs->vs_delayclock = VV_MODE2DELAY;
443 /* fall thru ... */
444 }
445
446 /*
447 * MODE2: simply ignoring traffic didn't relieve condition
448 * Scheme: open host relay for intervals linearly
449 * increasing up to some maximum of a several minutes.
450 * This allows broken networks to return to operation
451 * without rebooting.
452 */
453 case MODE2:
454 if (vs->vs_delayclock > 0) {
455 vs->vs_delayclock--;
456 continue;
457 }
458 switch (vs->vs_minor) {
459
460 case 0: /* close relay and reenable reads */
461 vvtrprintf("vv%d M2m0\n",i);
462 vs->vs_dropped = 0;
463 vs->vs_iactive = ACTIVE;
464 vs->vs_minor = 1; /* next state */
465 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
466 addr->vviba = (u_short) ubainfo;
467 addr->vviea = (u_short) (ubainfo >> 16);
468 addr->vviwc =
469 -(sizeof (struct vv_header) + VVMTU) >> 1;
470 addr->vvicsr = VV_RST | VV_CONF;
471 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
472 continue;
473
474 case 1: /* see if it worked */
475 vvtrprintf("vv%d M2m1\n",i);
476 if (vs->vs_dropped < VV_ERRORTHRESHOLD) {
477 vs->vs_dropped = 0;
478 vs->vs_major = MODE0; /* yeah!! */
479 continue;
480 }
481 vvtrprintf("vv%d M2m1 ++ delay\n",i);
482 vs->vs_dropped = 0;
483 vs->vs_iactive = OPEN;
484 vs->vs_minor = 0;
485 if (vs->vs_delayrange < VV_MAXDELAY)
486 vs->vs_delayrange +=
487 (vs->vs_delayrange/2);
488 vs->vs_delayclock = vs->vs_delayrange;
489 continue;
490 }
491
492 default:
493 printf("vv%d: major state screwed\n", i);
494 vs->vs_if.if_flags &= ~IFF_UP;
495 }
496 }
497}
498
499/*
500 * Start or restart output on interface.
501 * If interface is active, this is a retransmit, so just
502 * restuff registers and go.
503 * If interface is not already active, get another datagram
504 * to send off of the interface queue, and map it to the interface
505 * before starting the output.
506 */
507vvstart(dev)
508 dev_t dev;
509{
510 int unit = VVUNIT(dev);
511 struct uba_device *ui = vvinfo[unit];
512 register struct vv_softc *vs = &vv_softc[unit];
513 register struct vvreg *addr;
514 struct mbuf *m;
515 int ubainfo;
516 int dest;
517
518 if (vs->vs_oactive)
519 goto restart;
520 /*
521 * Not already active: dequeue another request
522 * and map it to the UNIBUS. If no more requests,
523 * just return.
524 */
525 IF_DEQUEUE(&vs->vs_if.if_snd, m);
526 if (m == NULL) {
527 vs->vs_oactive = 0;
528 return;
529 }
530 dest = mtod(m, struct vv_header *)->vh_dhost;
531 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m);
532 vs->vs_lastx = dest;
533restart:
534 /*
535 * Have request mapped to UNIBUS for transmission.
536 * Purge any stale data from this BDP, and start the otput.
537 */
538 if (vs->vs_olen > VVMTU) {
539 printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen);
540 panic("vvdriver vs_olen botch");
541 }
542 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
543 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp);
544 addr = (struct vvreg *)ui->ui_addr;
545 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info;
546 addr->vvoba = (u_short) ubainfo;
547 addr->vvoea = (u_short) (ubainfo >> 16);
548 addr->vvowc = -((vs->vs_olen + 1) >> 1);
549 addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB;
550 vs->vs_oactive = 1;
551}
552
553/*
554 * VVLNI transmit interrupt
555 * Start another output if more data to send.
556 */
557vvxint(unit)
558 int unit;
559{
560 register struct uba_device *ui = vvinfo[unit];
561 register struct vv_softc *vs = &vv_softc[unit];
562 register struct vvreg *addr;
563 register int oc;
564
565 addr = (struct vvreg *)ui->ui_addr;
566 oc = 0xffff & (addr->vvocsr);
567 if (vs->vs_oactive == 0) {
568 printf("vv%d: stray interrupt vvocsr = %b\n", unit,
569 oc, VV_OBITS);
570 return;
571 }
572 if (oc & (VV_OPT | VV_RFS)) {
573 vs->vs_if.if_collisions++;
574 if (vs->vs_tries++ < VVRETRY) {
575 if (oc & VV_OPT)
576 vs->vs_init++;
577 if (oc & VV_RFS)
578 vs->vs_nottaken++;
579 vvstart(unit); /* restart this message */
580 return;
581 }
582 if (oc & VV_OPT)
583 printf("vv%d: output timeout\n");
584 }
585 vs->vs_if.if_opackets++;
586 vs->vs_oactive = 0;
587 vs->vs_tries = 0;
588 if (oc & VVXERR) {
589 vs->vs_if.if_oerrors++;
590 printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc,
591 VV_OBITS);
592 }
593 if (vs->vs_ifuba.ifu_xtofree) {
594 m_freem(vs->vs_ifuba.ifu_xtofree);
595 vs->vs_ifuba.ifu_xtofree = 0;
596 }
597 if (vs->vs_if.if_snd.ifq_head == 0) {
598 vs->vs_lastx = 256; /* an invalid address */
599 return;
600 }
601 vvstart(unit);
602}
603
604/*
605 * V2lni interface receiver interrupt.
606 * If input error just drop packet.
607 * Otherwise purge input buffered data path and examine
608 * packet to determine type. If can't determine length
609 * from type, then have to drop packet. Othewise decapsulate
610 * packet based on type and pass to type specific higher-level
611 * input routine.
612 */
613vvrint(unit)
614 int unit;
615{
616 register struct vv_softc *vs = &vv_softc[unit];
617 struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr;
618 register struct vv_header *vv;
619 register struct ifqueue *inq;
620 struct mbuf *m;
621 int ubainfo, len, off;
622 short resid;
623
624 vs->vs_if.if_ipackets++;
625 /*
626 * Purge BDP; drop if input error indicated.
627 */
628 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP)
629 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp);
630 if (addr->vvicsr & VVRERR) {
631 if (vv_logreaderrors)
632 printf("vv%d: error vvicsr = %b\n", unit,
633 0xffff&(addr->vvicsr), VV_IBITS);
634 goto dropit;
635 }
636
637 /*
638 * Get packet length from word count residue
639 *
640 * Compute header offset if trailer protocol
641 *
642 * Pull packet off interface. Off is nonzero if packet
643 * has trailing header; if_rubaget will then force this header
644 * information to be at the front. The vh_info field
645 * carries the offset to the trailer data in trailer
646 * format packets.
647 */
648 vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr);
649 vvtracehdr("vi", vv);
650 resid = addr->vviwc;
651 if (resid)
652 resid |= 0176000; /* ugly!!!! */
653 len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1;
654 len -= sizeof(struct vv_header);
655 if (len > VVMRU || len <= 0)
656 goto dropit;
657#define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off))))
658 if (vv_dotrailer && vv->vh_type >= RING_IPTrailer &&
659 vv->vh_type < RING_IPTrailer+RING_IPNTrailer){
660 off = (vv->vh_type - RING_IPTrailer) * 512;
661 if (off > VVMTU)
662 goto dropit;
663 vv->vh_type = *vvdataaddr(vv, off, u_short *);
664 resid = *(vvdataaddr(vv, off+2, u_short *));
665 if (off + resid > len)
666 goto dropit;
667 len = off + resid;
668 } else
669 off = 0;
670 if (len == 0)
671 goto dropit;
672 m = if_rubaget(&vs->vs_ifuba, len, off);
673 if (m == NULL)
674 goto dropit;
675 if (off) {
676 m->m_off += 2 * sizeof(u_short);
677 m->m_len -= 2 * sizeof(u_short);
678 }
679
680 /*
681 * Demultiplex on packet type
682 */
683 switch (vv->vh_type) {
684
685#ifdef INET
686 case RING_IP:
687 schednetisr(NETISR_IP);
688 inq = &ipintrq;
689 break;
690#endif
691 default:
692 printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type);
693 m_freem(m);
694 goto setup;
695 }
696 if (IF_QFULL(inq)) {
697 IF_DROP(inq);
698 m_freem(m);
699 } else
700 IF_ENQUEUE(inq, m);
701setup:
702 /*
703 * Check the error rate and start recovery if needed
704 * this has to go here since the timer flywheel runs at
705 * a lower ipl and never gets a chance to change the mode
706 */
707 if (vs->vs_major == MODE0 && vs->vs_dropped > VV_ERRORTHRESHOLD) {
708 vvtrprintf("vv%d going MODE1 in vvrint\n",unit);
709 vs->vs_major = MODE1;
710 vs->vs_iactive = PAUSE; /* no new reads */
711 vs->vs_retry = VV_MODE1ATTEMPTS;
712 vs->vs_delayclock = VV_MODE1DELAY;
713 vs->vs_minor = 0;
714 vs->vs_dropped = 0;
715 }
716 switch (vs->vs_iactive) {
717
718 case ACTIVE: /* Restart the read for next packet */
719 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info;
720 addr->vviba = (u_short) ubainfo;
721 addr->vviea = (u_short) (ubainfo >> 16);
722 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1;
723 addr->vvicsr = VV_RST | VV_CONF;
724 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB;
725 return;
726
727 case PAUSE: /* requested to not start any new reads */
728 vs->vs_dropped = 0;
729 return;
730
731 case OPEN: /* request to open host relay */
732 vs->vs_dropped = 0;
733 addr->vvicsr = 0;
734 return;
735
736 default:
737 printf("vv%d: vs_iactive = %d\n", unit, vs->vs_iactive);
738 return;
739 }
740 /*
741 * Drop packet on floor -- count them!!
742 */
743dropit:
744 vs->vs_if.if_ierrors++;
745 vs->vs_dropped++;
746 /*
747 printf("vv%d: error vvicsr = %b\n", unit,
748 0xffff&(addr->vvicsr), VV_IBITS);
749 */
750 goto setup;
751}
752
753/*
754 * V2lni output routine.
755 * Encapsulate a packet of type family for the local net.
756 * Use trailer local net encapsulation if enough data in first
757 * packet leaves a multiple of 512 bytes of data in remainder.
758 */
759vvoutput(ifp, m0, dst)
760 struct ifnet *ifp;
761 struct mbuf *m0;
762 struct sockaddr *dst;
763{
764 register struct mbuf *m = m0;
765 register struct vv_header *vv;
766 register int off;
767 int type, dest, s, error;
768
769 switch (dst->sa_family) {
770
771#ifdef INET
772 case AF_INET: {
773 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
774 if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) {
775 error = EPERM;
776 goto bad;
777 }
778 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
779 if (vv_dotrailer && off > 0 && (off & 0x1ff) == 0 &&
780 m->m_off >= MMINOFF + 2 * sizeof (u_short)) {
781 type = RING_IPTrailer + (off>>9);
782 m->m_off -= 2 * sizeof (u_short);
783 m->m_len += 2 * sizeof (u_short);
784 *mtod(m, u_short *) = RING_IP;
785 *(mtod(m, u_short *) + 1) = m->m_len;
786 goto gottrailertype;
787 }
788 type = RING_IP;
789 off = 0;
790 goto gottype;
791 }
792#endif
793 default:
794 printf("vv%d: can't handle af%d\n", ifp->if_unit,
795 dst->sa_family);
796 error = EAFNOSUPPORT;
797 goto bad;
798 }
799
800gottrailertype:
801 /*
802 * Packet to be sent as trailer: move first packet
803 * (control information) to end of chain.
804 */
805 while (m->m_next)
806 m = m->m_next;
807 m->m_next = m0;
808 m = m0->m_next;
809 m0->m_next = 0;
810 m0 = m;
811gottype:
812 /*
813 * Add local net header. If no space in first mbuf,
814 * allocate another.
815 */
816 if (m->m_off > MMAXOFF ||
817 MMINOFF + sizeof (struct vv_header) > m->m_off) {
818 m = m_get(M_DONTWAIT, MT_HEADER);
819 if (m == NULL) {
820 error = ENOBUFS;
821 goto bad;
822 }
823 m->m_next = m0;
824 m->m_off = MMINOFF;
825 m->m_len = sizeof (struct vv_header);
826 } else {
827 m->m_off -= sizeof (struct vv_header);
828 m->m_len += sizeof (struct vv_header);
829 }
830 vv = mtod(m, struct vv_header *);
831 vv->vh_shost = ifp->if_host[0];
832 vv->vh_dhost = dest;
833 vv->vh_version = RING_VERSION;
834 vv->vh_type = type;
835 vv->vh_info = off;
836 vvtracehdr("vo", vv);
837
838 /*
839 * Queue message on interface, and start output if interface
840 * not yet active.
841 */
842 s = splimp();
843 if (IF_QFULL(&ifp->if_snd)) {
844 IF_DROP(&ifp->if_snd);
845 error = ENOBUFS;
846 goto qfull;
847 }
848 IF_ENQUEUE(&ifp->if_snd, m);
849 if (vv_softc[ifp->if_unit].vs_oactive == 0)
850 vvstart(ifp->if_unit);
851 splx(s);
852 return (0);
853qfull:
854 m0 = m;
855 splx(s);
856bad:
857 m_freem(m0);
858 return(error);
859}
860
861/*
862 * vvprt_hdr(s, v) print the local net header in "v"
863 * with title is "s"
864 */
865vvprt_hdr(s, v)
866 char *s;
867 register struct vv_header *v;
868{
869 printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
870 s,
871 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost),
872 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type),
873 0xffff & (int)(v->vh_info));
874}
875
876/*
877 * print "l" hex bytes starting at "s"
878 */
879vvprt_hex(s, l)
880 char *s;
881 int l;
882{
883 register int i;
884 register int z;
885
886 for (i=0 ; i < l; i++) {
887 z = 0xff & (int)(*(s + i));
888 printf("%c%c ",
889 "0123456789abcdef"[(z >> 4) & 0x0f],
890 "0123456789abcdef"[z & 0x0f]
891 );
892 }
893}