1 /* if_vv.c 4.20 83/05/27 */ 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 25 #include "../net/if.h" 26 #include "../net/netisr.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 "../vax/mtpr.h" 35 #include "../vax/cpu.h" 36 37 #include "../vaxuba/ubareg.h" 38 #include "../vaxuba/ubavar.h" 39 40 #include "../vaxif/if_vv.h" 41 #include "../vaxif/if_uba.h" 42 43 /* 44 * N.B. - if WIRECENTER is defined wrong, it can well break 45 * the hardware!! 46 */ 47 #define WIRECENTER 48 49 #ifdef WIRECENTER 50 #define VV_CONF VV_HEN /* drive wire center relay */ 51 #else 52 #define VV_CONF VV_STE /* allow operation without wire center */ 53 #endif 54 55 #define VVMTU (1024+512) 56 #define VVMRU (1024+512+16) /* space for trailer */ 57 58 int vv_dotrailer = 0, /* 1 => do trailer protocol */ 59 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(),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 register struct sockaddr_in *sin; 168 169 vs->vs_if.if_unit = ui->ui_unit; 170 vs->vs_if.if_name = "vv"; 171 vs->vs_if.if_mtu = VVMTU; 172 vs->vs_if.if_net = ui->ui_flags; 173 vs->vs_if.if_host[0] = 0; /* this will be reset in vvinit() */ 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 sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr; 178 sin->sin_family = AF_INET; 179 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST); 180 vs->vs_if.if_flags = IFF_BROADCAST; 181 vs->vs_if.if_init = vvinit; 182 vs->vs_if.if_output = vvoutput; 183 vs->vs_if.if_reset = vvreset; 184 vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16; 185 #if defined(VAX750) 186 /* don't chew up 750 bdp's */ 187 if (cpu == VAX_750 && ui->ui_unit > 0) 188 vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 189 #endif 190 if_attach(&vs->vs_if); 191 } 192 193 /* 194 * Reset of interface after UNIBUS reset. 195 * If interface is on specified uba, reset its state. 196 */ 197 vvreset(unit, uban) 198 int unit, uban; 199 { 200 register struct uba_device *ui; 201 202 if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 203 ui->ui_ubanum != uban) 204 return; 205 printf(" vv%d", unit); 206 vvinit(unit); 207 } 208 209 /* 210 * Initialization of interface; clear recorded pending 211 * operations, and reinitialize UNIBUS usage. 212 */ 213 vvinit(unit) 214 int unit; 215 { 216 register struct vv_softc *vs = &vv_softc[unit]; 217 register struct uba_device *ui = vvinfo[unit]; 218 register struct vvreg *addr; 219 struct sockaddr_in *sin; 220 int ubainfo, s; 221 int vvtimeout(); 222 223 addr = (struct vvreg *)ui->ui_addr; 224 if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 225 sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 226 printf("vv%d: can't initialize\n", unit); 227 vs->vs_if.if_flags &= ~IFF_UP; 228 return; 229 } 230 if (vv_ticking++ == 0) 231 timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL); 232 /* 233 * Discover our host address and post it 234 */ 235 vs->vs_if.if_host[0] = vvidentify(unit); 236 printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); 237 sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 238 sin->sin_family = AF_INET; 239 sin->sin_addr = 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 DELAY(500000); /* 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 vvidentify(unit) 273 { 274 register struct vv_softc *vs = &vv_softc[unit]; 275 register struct uba_device *ui = vvinfo[unit]; 276 register struct vvreg *addr; 277 struct mbuf *m; 278 struct vv_header *v; 279 int ubainfo, attempts, waitcount; 280 281 /* 282 * Build a multicast message to identify our address 283 */ 284 addr = (struct vvreg *)ui->ui_addr; 285 attempts = 0; /* total attempts, including bad msg type */ 286 m = m_get(M_DONTWAIT, MT_HEADER); 287 if (m == NULL) 288 panic("vvinit: can't get mbuf"); 289 m->m_next = 0; 290 m->m_off = MMINOFF; 291 m->m_len = sizeof(struct vv_header); 292 v = mtod(m, struct vv_header *); 293 v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 294 v->vh_shost = 0; /* will be overwritten with ours */ 295 v->vh_version = RING_VERSION; 296 v->vh_type = RING_WHOAMI; 297 v->vh_info = 0; 298 /* map xmit message into uba */ 299 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 300 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 301 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 302 /* 303 * Reset interface, establish Digital Loopback Mode, and 304 * send the multicast (to myself) with Input Copy enabled. 305 */ 306 retry: 307 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 308 addr->vvicsr = VV_RST; 309 addr->vviba = (u_short) ubainfo; 310 addr->vviea = (u_short) (ubainfo >> 16); 311 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 312 addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 313 314 /* let flag timers fire so ring will initialize */ 315 DELAY(2000000); 316 317 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 318 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 319 addr->vvoba = (u_short) ubainfo; 320 addr->vvoea = (u_short) (ubainfo >> 16); 321 addr->vvowc = -((vs->vs_olen + 1) >> 1); 322 addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 323 /* 324 * Wait for receive side to finish. 325 * Extract source address (which will our own), 326 * and post to interface structure. 327 */ 328 DELAY(1000); 329 for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) { 330 if (waitcount < 10) { 331 DELAY(1000); 332 continue; 333 } 334 if (attempts++ >= 10) { 335 printf("vv%d: can't initialize\n", unit); 336 printf("vvinit loopwait: icsr = %b\n", 337 0xffff&(addr->vvicsr), VV_IBITS); 338 vs->vs_if.if_flags &= ~IFF_UP; 339 return (0); 340 } 341 goto retry; 342 } 343 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 344 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 345 if (vs->vs_ifuba.ifu_xtofree) 346 m_freem(vs->vs_ifuba.ifu_xtofree); 347 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 348 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 349 m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 350 if (m != NULL) 351 m_freem(m); 352 /* 353 * Check message type before we believe the source host address 354 */ 355 v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 356 if (v->vh_type != RING_WHOAMI) 357 goto retry; 358 return(v->vh_shost); 359 } 360 361 /* 362 * vvtimeout() - called by timer flywheel to monitor input packet 363 * discard rate. Interfaces getting too many errors are shut 364 * down for a while. If the condition persists, the interface 365 * is marked down. 366 */ 367 /*ARGSUSED*/ 368 vvtimeout(junk) 369 int junk; 370 { 371 register struct vv_softc *vs; 372 register int i; 373 register struct vvreg *addr; 374 int ubainfo; 375 376 timeout(vvtimeout, (caddr_t) 0, VV_FLYWHEEL); 377 for (i = 0; i < NVV; i++) { 378 vs = &vv_softc[i]; 379 addr = (struct vvreg *)vvinfo[i]->ui_addr; 380 if ((vs->vs_if.if_flags & IFF_UP) == 0) 381 continue; 382 switch (vs->vs_major) { 383 384 /* 385 * MODE0: generally OK, just check error rate 386 */ 387 case MODE0: 388 if (vs->vs_dropped < VV_ERRORTHRESHOLD) { 389 vs->vs_dropped = 0; 390 continue; 391 } 392 /* suspend reads for a while */ 393 vvtrprintf("vv%d going MODE1 in vvtimeout\n",i); 394 vs->vs_major = MODE1; 395 vs->vs_iactive = PAUSE; /* no new reads */ 396 vs->vs_retry = VV_MODE1ATTEMPTS; 397 vs->vs_delayclock = VV_MODE1DELAY; 398 vs->vs_minor = 0; 399 continue; 400 401 /* 402 * MODE1: excessive error rate observed 403 * Scheme: try simply suspending reads for a 404 * short while a small number of times 405 */ 406 case MODE1: 407 if (vs->vs_delayclock > 0) { 408 vs->vs_delayclock--; 409 continue; 410 } 411 switch (vs->vs_minor) { 412 413 case 0: /* reenable reads */ 414 vvtrprintf("vv%d M1m0\n",i); 415 vs->vs_dropped = 0; 416 vs->vs_iactive = ACTIVE; 417 vs->vs_minor = 1; /* next state */ 418 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 419 addr->vviba = (u_short) ubainfo; 420 addr->vviea = (u_short) (ubainfo >> 16); 421 addr->vviwc = 422 -(sizeof (struct vv_header) + VVMTU) >> 1; 423 addr->vvicsr = VV_RST | VV_CONF; 424 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 425 continue; 426 427 case 1: /* see if it worked */ 428 vvtrprintf("vv%d M1m1\n",i); 429 if (vs->vs_dropped < VV_ERRORTHRESHOLD) { 430 vs->vs_dropped = 0; 431 vs->vs_major = MODE0; /* yeah!! */ 432 continue; 433 } 434 if (vs->vs_retry -- > 0) { 435 vs->vs_dropped = 0; 436 vs->vs_iactive = PAUSE; 437 vs->vs_delayclock = VV_MODE1DELAY; 438 vs->vs_minor = 0; /* recheck */ 439 continue; 440 } 441 vs->vs_major = MODE2; 442 vs->vs_minor = 0; 443 vs->vs_dropped = 0; 444 vs->vs_iactive = OPEN; 445 vs->vs_delayrange = VV_MODE2DELAY; 446 vs->vs_delayclock = VV_MODE2DELAY; 447 /* fall thru ... */ 448 } 449 450 /* 451 * MODE2: simply ignoring traffic didn't relieve condition 452 * Scheme: open host relay for intervals linearly 453 * increasing up to some maximum of a several minutes. 454 * This allows broken networks to return to operation 455 * without rebooting. 456 */ 457 case MODE2: 458 if (vs->vs_delayclock > 0) { 459 vs->vs_delayclock--; 460 continue; 461 } 462 switch (vs->vs_minor) { 463 464 case 0: /* close relay and reenable reads */ 465 vvtrprintf("vv%d M2m0\n",i); 466 vs->vs_dropped = 0; 467 vs->vs_iactive = ACTIVE; 468 vs->vs_minor = 1; /* next state */ 469 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 470 addr->vviba = (u_short) ubainfo; 471 addr->vviea = (u_short) (ubainfo >> 16); 472 addr->vviwc = 473 -(sizeof (struct vv_header) + VVMTU) >> 1; 474 addr->vvicsr = VV_RST | VV_CONF; 475 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 476 continue; 477 478 case 1: /* see if it worked */ 479 vvtrprintf("vv%d M2m1\n",i); 480 if (vs->vs_dropped < VV_ERRORTHRESHOLD) { 481 vs->vs_dropped = 0; 482 vs->vs_major = MODE0; /* yeah!! */ 483 continue; 484 } 485 vvtrprintf("vv%d M2m1 ++ delay\n",i); 486 vs->vs_dropped = 0; 487 vs->vs_iactive = OPEN; 488 vs->vs_minor = 0; 489 if (vs->vs_delayrange < VV_MAXDELAY) 490 vs->vs_delayrange += 491 (vs->vs_delayrange/2); 492 vs->vs_delayclock = vs->vs_delayrange; 493 continue; 494 } 495 496 default: 497 printf("vv%d: major state screwed\n", i); 498 vs->vs_if.if_flags &= ~IFF_UP; 499 } 500 } 501 } 502 503 /* 504 * Start or restart output on interface. 505 * If interface is active, this is a retransmit, so just 506 * restuff registers and go. 507 * If interface is not already active, get another datagram 508 * to send off of the interface queue, and map it to the interface 509 * before starting the output. 510 */ 511 vvstart(dev) 512 dev_t dev; 513 { 514 int unit = VVUNIT(dev); 515 struct uba_device *ui = vvinfo[unit]; 516 register struct vv_softc *vs = &vv_softc[unit]; 517 register struct vvreg *addr; 518 struct mbuf *m; 519 int ubainfo; 520 int dest; 521 522 if (vs->vs_oactive) 523 goto restart; 524 /* 525 * Not already active: dequeue another request 526 * and map it to the UNIBUS. If no more requests, 527 * just return. 528 */ 529 IF_DEQUEUE(&vs->vs_if.if_snd, m); 530 if (m == NULL) { 531 vs->vs_oactive = 0; 532 return; 533 } 534 dest = mtod(m, struct vv_header *)->vh_dhost; 535 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 536 vs->vs_lastx = dest; 537 restart: 538 /* 539 * Have request mapped to UNIBUS for transmission. 540 * Purge any stale data from this BDP, and start the otput. 541 */ 542 if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) { 543 printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen); 544 panic("vvdriver vs_olen botch"); 545 } 546 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 547 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 548 addr = (struct vvreg *)ui->ui_addr; 549 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 550 addr->vvoba = (u_short) ubainfo; 551 addr->vvoea = (u_short) (ubainfo >> 16); 552 addr->vvowc = -((vs->vs_olen + 1) >> 1); 553 addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 554 vs->vs_oactive = 1; 555 } 556 557 /* 558 * VVLNI transmit interrupt 559 * Start another output if more data to send. 560 */ 561 vvxint(unit) 562 int unit; 563 { 564 register struct uba_device *ui = vvinfo[unit]; 565 register struct vv_softc *vs = &vv_softc[unit]; 566 register struct vvreg *addr; 567 register int oc; 568 569 addr = (struct vvreg *)ui->ui_addr; 570 oc = 0xffff & (addr->vvocsr); 571 if (vs->vs_oactive == 0) { 572 printf("vv%d: stray interrupt vvocsr = %b\n", unit, 573 oc, VV_OBITS); 574 return; 575 } 576 if (oc & (VV_OPT | VV_RFS)) { 577 vs->vs_if.if_collisions++; 578 if (vs->vs_tries++ < VVRETRY) { 579 if (oc & VV_OPT) 580 vs->vs_init++; 581 if (oc & VV_RFS) 582 vs->vs_nottaken++; 583 vvstart(unit); /* restart this message */ 584 return; 585 } 586 if (oc & VV_OPT) 587 printf("vv%d: output timeout\n"); 588 } 589 vs->vs_if.if_opackets++; 590 vs->vs_oactive = 0; 591 vs->vs_tries = 0; 592 if (oc & VVXERR) { 593 vs->vs_if.if_oerrors++; 594 printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 595 VV_OBITS); 596 } 597 if (vs->vs_ifuba.ifu_xtofree) { 598 m_freem(vs->vs_ifuba.ifu_xtofree); 599 vs->vs_ifuba.ifu_xtofree = 0; 600 } 601 if (vs->vs_if.if_snd.ifq_head == 0) { 602 vs->vs_lastx = 256; /* an invalid address */ 603 return; 604 } 605 vvstart(unit); 606 } 607 608 /* 609 * V2lni interface receiver interrupt. 610 * If input error just drop packet. 611 * Otherwise purge input buffered data path and examine 612 * packet to determine type. If can't determine length 613 * from type, then have to drop packet. Othewise decapsulate 614 * packet based on type and pass to type specific higher-level 615 * input routine. 616 */ 617 vvrint(unit) 618 int unit; 619 { 620 register struct vv_softc *vs = &vv_softc[unit]; 621 struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr; 622 register struct vv_header *vv; 623 register struct ifqueue *inq; 624 struct mbuf *m; 625 int ubainfo, len, off; 626 short resid; 627 628 vs->vs_if.if_ipackets++; 629 /* 630 * Purge BDP; drop if input error indicated. 631 */ 632 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 633 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 634 if (addr->vvicsr & VVRERR) { 635 if (vv_logreaderrors) 636 printf("vv%d: error vvicsr = %b\n", unit, 637 0xffff&(addr->vvicsr), VV_IBITS); 638 goto dropit; 639 } 640 641 /* 642 * Get packet length from word count residue 643 * 644 * Compute header offset if trailer protocol 645 * 646 * Pull packet off interface. Off is nonzero if packet 647 * has trailing header; if_rubaget will then force this header 648 * information to be at the front. The vh_info field 649 * carries the offset to the trailer data in trailer 650 * format packets. 651 */ 652 vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 653 vvtracehdr("vi", vv); 654 resid = addr->vviwc; 655 if (resid) 656 resid |= 0176000; /* ugly!!!! */ 657 len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1; 658 len -= sizeof(struct vv_header); 659 if (len > VVMRU || len <= 0) 660 goto dropit; 661 #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 662 if (vv_dotrailer && vv->vh_type >= RING_IPTrailer && 663 vv->vh_type < RING_IPTrailer+RING_IPNTrailer){ 664 off = (vv->vh_type - RING_IPTrailer) * 512; 665 if (off > VVMTU) 666 goto dropit; 667 vv->vh_type = *vvdataaddr(vv, off, u_short *); 668 resid = *(vvdataaddr(vv, off+2, u_short *)); 669 if (off + resid > len) 670 goto dropit; 671 len = off + resid; 672 } else 673 off = 0; 674 if (len == 0) 675 goto dropit; 676 m = if_rubaget(&vs->vs_ifuba, len, off); 677 if (m == NULL) 678 goto dropit; 679 if (off) { 680 m->m_off += 2 * sizeof(u_short); 681 m->m_len -= 2 * sizeof(u_short); 682 } 683 684 /* 685 * Demultiplex on packet type 686 */ 687 switch (vv->vh_type) { 688 689 #ifdef INET 690 case RING_IP: 691 schednetisr(NETISR_IP); 692 inq = &ipintrq; 693 break; 694 #endif 695 default: 696 printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 697 m_freem(m); 698 goto setup; 699 } 700 if (IF_QFULL(inq)) { 701 IF_DROP(inq); 702 m_freem(m); 703 } else 704 IF_ENQUEUE(inq, m); 705 setup: 706 /* 707 * Check the error rate and start recovery if needed 708 * this has to go here since the timer flywheel runs at 709 * a lower ipl and never gets a chance to change the mode 710 */ 711 if (vs->vs_major == MODE0 && vs->vs_dropped > VV_ERRORTHRESHOLD) { 712 vvtrprintf("vv%d going MODE1 in vvrint\n",unit); 713 vs->vs_major = MODE1; 714 vs->vs_iactive = PAUSE; /* no new reads */ 715 vs->vs_retry = VV_MODE1ATTEMPTS; 716 vs->vs_delayclock = VV_MODE1DELAY; 717 vs->vs_minor = 0; 718 vs->vs_dropped = 0; 719 } 720 switch (vs->vs_iactive) { 721 722 case ACTIVE: /* Restart the read for next packet */ 723 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 724 addr->vviba = (u_short) ubainfo; 725 addr->vviea = (u_short) (ubainfo >> 16); 726 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 727 addr->vvicsr = VV_RST | VV_CONF; 728 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 729 return; 730 731 case PAUSE: /* requested to not start any new reads */ 732 vs->vs_dropped = 0; 733 return; 734 735 case OPEN: /* request to open host relay */ 736 vs->vs_dropped = 0; 737 addr->vvicsr = 0; 738 return; 739 740 default: 741 printf("vv%d: vs_iactive = %d\n", unit, vs->vs_iactive); 742 return; 743 } 744 /* 745 * Drop packet on floor -- count them!! 746 */ 747 dropit: 748 vs->vs_if.if_ierrors++; 749 vs->vs_dropped++; 750 /* 751 printf("vv%d: error vvicsr = %b\n", unit, 752 0xffff&(addr->vvicsr), VV_IBITS); 753 */ 754 goto setup; 755 } 756 757 /* 758 * V2lni output routine. 759 * Encapsulate a packet of type family for the local net. 760 * Use trailer local net encapsulation if enough data in first 761 * packet leaves a multiple of 512 bytes of data in remainder. 762 */ 763 vvoutput(ifp, m0, dst) 764 struct ifnet *ifp; 765 struct mbuf *m0; 766 struct sockaddr *dst; 767 { 768 register struct mbuf *m = m0; 769 register struct vv_header *vv; 770 register int off; 771 int type, dest, s, error; 772 773 switch (dst->sa_family) { 774 775 #ifdef INET 776 case AF_INET: { 777 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 778 if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) { 779 error = EPERM; 780 goto bad; 781 } 782 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 783 if (vv_dotrailer && off > 0 && (off & 0x1ff) == 0 && 784 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 785 type = RING_IPTrailer + (off>>9); 786 m->m_off -= 2 * sizeof (u_short); 787 m->m_len += 2 * sizeof (u_short); 788 *mtod(m, u_short *) = RING_IP; 789 *(mtod(m, u_short *) + 1) = m->m_len; 790 goto gottrailertype; 791 } 792 type = RING_IP; 793 off = 0; 794 goto gottype; 795 } 796 #endif 797 default: 798 printf("vv%d: can't handle af%d\n", ifp->if_unit, 799 dst->sa_family); 800 error = EAFNOSUPPORT; 801 goto bad; 802 } 803 804 gottrailertype: 805 /* 806 * Packet to be sent as trailer: move first packet 807 * (control information) to end of chain. 808 */ 809 while (m->m_next) 810 m = m->m_next; 811 m->m_next = m0; 812 m = m0->m_next; 813 m0->m_next = 0; 814 m0 = m; 815 gottype: 816 /* 817 * Add local net header. If no space in first mbuf, 818 * allocate another. 819 */ 820 if (m->m_off > MMAXOFF || 821 MMINOFF + sizeof (struct vv_header) > m->m_off) { 822 m = m_get(M_DONTWAIT, MT_HEADER); 823 if (m == NULL) { 824 error = ENOBUFS; 825 goto bad; 826 } 827 m->m_next = m0; 828 m->m_off = MMINOFF; 829 m->m_len = sizeof (struct vv_header); 830 } else { 831 m->m_off -= sizeof (struct vv_header); 832 m->m_len += sizeof (struct vv_header); 833 } 834 vv = mtod(m, struct vv_header *); 835 vv->vh_shost = ifp->if_host[0]; 836 vv->vh_dhost = dest; 837 vv->vh_version = RING_VERSION; 838 vv->vh_type = type; 839 vv->vh_info = off; 840 vvtracehdr("vo", vv); 841 842 /* 843 * Queue message on interface, and start output if interface 844 * not yet active. 845 */ 846 s = splimp(); 847 if (IF_QFULL(&ifp->if_snd)) { 848 IF_DROP(&ifp->if_snd); 849 error = ENOBUFS; 850 goto qfull; 851 } 852 IF_ENQUEUE(&ifp->if_snd, m); 853 if (vv_softc[ifp->if_unit].vs_oactive == 0) 854 vvstart(ifp->if_unit); 855 splx(s); 856 return (0); 857 qfull: 858 m0 = m; 859 splx(s); 860 bad: 861 m_freem(m0); 862 return(error); 863 } 864 865 /* 866 * vvprt_hdr(s, v) print the local net header in "v" 867 * with title is "s" 868 */ 869 vvprt_hdr(s, v) 870 char *s; 871 register struct vv_header *v; 872 { 873 printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 874 s, 875 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 876 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 877 0xffff & (int)(v->vh_info)); 878 } 879 880 #ifdef notdef 881 /* 882 * print "l" hex bytes starting at "s" 883 */ 884 vvprt_hex(s, l) 885 char *s; 886 int l; 887 { 888 register int i; 889 register int z; 890 891 for (i=0 ; i < l; i++) { 892 z = 0xff & (int)(*(s + i)); 893 printf("%c%c ", 894 "0123456789abcdef"[(z >> 4) & 0x0f], 895 "0123456789abcdef"[z & 0x0f] 896 ); 897 } 898 } 899 #endif 900