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