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