1 /* if_vv.c 4.22 83/06/13 */ 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 929