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