1 /* if_vv.c 6.5 84/06/07 */ 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/ioctl.h" 23 24 #include "../net/if.h" 25 #include "../net/netisr.h" 26 #include "../net/route.h" 27 #include "../netinet/in.h" 28 #include "../netinet/in_systm.h" 29 #include "../netinet/ip.h" 30 #include "../netinet/ip_var.h" 31 32 #include "../vax/cpu.h" 33 #include "../vax/mtpr.h" 34 #include "../vaxif/if_vv.h" 35 #include "../vaxif/if_uba.h" 36 #include "../vaxuba/ubareg.h" 37 #include "../vaxuba/ubavar.h" 38 39 /* 40 * N.B. - if WIRECENTER is defined wrong, it can well break 41 * the hardware!! 42 */ 43 #define WIRECENTER 44 45 #ifdef WIRECENTER 46 #define VV_CONF VV_HEN /* drive wire center relay */ 47 #else 48 #define VV_CONF VV_STE /* allow operation without wire center */ 49 #endif 50 51 #define VVMTU (1024+512) 52 #define VVMRU (1024+512+16) /* space for trailer */ 53 54 int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ 55 int vv_logreaderrors = 1; /* 1 => log all read errors */ 56 57 #define vvtracehdr if (vv_tracehdr) vvprt_hdr 58 59 int vvprobe(), vvattach(), vvreset(), vvinit(); 60 int vvidentify(), vvstart(), vvxint(), vvwatchdog(); 61 int vvrint(), vvoutput(), vvioctl(), vvsetaddr(); 62 struct uba_device *vvinfo[NVV]; 63 u_short vvstd[] = { 0 }; 64 struct uba_driver vvdriver = 65 { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; 66 #define VVUNIT(x) minor(x) 67 68 /* 69 * Software status of each interface. 70 * 71 * Each interface is referenced by a network interface structure, 72 * vs_if, which the routing code uses to locate the interface. 73 * This structure contains the output queue for the interface, its address, ... 74 * We also have, for each interface, a UBA interface structure, which 75 * contains information about the UNIBUS resources held by the interface: 76 * map registers, buffered data paths, etc. Information is cached in this 77 * structure for use by the if_uba.c routines in running the interface 78 * efficiently. 79 */ 80 struct vv_softc { 81 struct ifnet vs_if; /* network-visible interface */ 82 struct ifuba vs_ifuba; /* UNIBUS resources */ 83 short vs_oactive; /* is output active */ 84 short vs_olen; /* length of last output */ 85 u_short vs_lastx; /* address of last packet sent */ 86 u_short vs_lastr; /* address of last packet received */ 87 short vs_tries; /* transmit current retry count */ 88 short vs_init; /* number of ring inits */ 89 short vs_nottaken; /* number of packets refused */ 90 short vs_timeouts; /* number of transmit timeouts */ 91 } vv_softc[NVV]; 92 93 vvprobe(reg) 94 caddr_t reg; 95 { 96 register int br, cvec; 97 register struct vvreg *addr; 98 99 #ifdef lint 100 br = 0; cvec = br; br = cvec; 101 #endif 102 addr = (struct vvreg *)reg; 103 /* reset interface, enable, and wait till dust settles */ 104 addr->vvicsr = VV_RST; 105 addr->vvocsr = VV_RST; 106 DELAY(100000); 107 /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ 108 addr->vvocsr = VV_IEN; /* enable interrupt */ 109 addr->vvoba = 0; /* low 16 bits */ 110 addr->vvoea = 0; /* extended bits */ 111 addr->vvowc = -1; /* for 1 word */ 112 addr->vvocsr |= VV_DEN; /* start the DMA */ 113 DELAY(100000); 114 addr->vvocsr = 0; 115 if (cvec && cvec != 0x200) 116 cvec -= 4; /* backup so vector => receive */ 117 return(1); 118 } 119 120 /* 121 * Interface exists: make available by filling in network interface 122 * record. System will initialize the interface when it is ready 123 * to accept packets. 124 */ 125 vvattach(ui) 126 struct uba_device *ui; 127 { 128 register struct vv_softc *vs; 129 130 vs = &vv_softc[ui->ui_unit]; 131 vs->vs_if.if_unit = ui->ui_unit; 132 vs->vs_if.if_name = "vv"; 133 vs->vs_if.if_mtu = VVMTU; 134 vs->vs_if.if_init = vvinit; 135 vs->vs_if.if_ioctl = vvioctl; 136 vs->vs_if.if_output = vvoutput; 137 vs->vs_if.if_reset = vvreset; 138 vs->vs_if.if_timer = 0; 139 vs->vs_if.if_watchdog = vvwatchdog; 140 vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16; 141 #if defined(VAX750) 142 /* don't chew up 750 bdp's */ 143 if (cpu == VAX_750 && ui->ui_unit > 0) 144 vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; 145 #endif 146 if_attach(&vs->vs_if); 147 } 148 149 /* 150 * Reset of interface after UNIBUS reset. 151 * If interface is on specified uba, reset its state. 152 */ 153 vvreset(unit, uban) 154 int unit, uban; 155 { 156 register struct uba_device *ui; 157 158 if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || 159 ui->ui_ubanum != uban) 160 return; 161 printf(" vv%d", unit); 162 vvinit(unit); 163 } 164 165 /* 166 * Initialization of interface; clear recorded pending 167 * operations, and reinitialize UNIBUS usage. 168 */ 169 vvinit(unit) 170 int unit; 171 { 172 register struct vv_softc *vs; 173 register struct uba_device *ui; 174 register struct vvreg *addr; 175 register struct sockaddr_in *sin; 176 register int ubainfo, s; 177 178 vs = &vv_softc[unit]; 179 ui = vvinfo[unit]; 180 sin = (struct sockaddr_in *)&vs->vs_if.if_addr; 181 /* 182 * If the network number is still zero, we've been 183 * called too soon. 184 */ 185 if (in_netof(sin->sin_addr) == 0) 186 return; 187 addr = (struct vvreg *)ui->ui_addr; 188 if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, 189 sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { 190 printf("vv%d: can't initialize, if_ubainit() failed\n", unit); 191 vs->vs_if.if_flags &= ~IFF_UP; 192 return; 193 } 194 /* 195 * Now that the uba is set up, figure out our address and 196 * update complete our host address. 197 */ 198 if ((vs->vs_if.if_host[0] = vvidentify(unit)) == 0) { 199 vs->vs_if.if_flags &= ~IFF_UP; 200 return; 201 } 202 printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); 203 sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); 204 /* 205 * Reset the interface, and join the ring 206 */ 207 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 208 addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ 209 DELAY(500000); /* let contacts settle */ 210 vs->vs_init = 0; 211 vs->vs_nottaken = 0; 212 vs->vs_timeouts = 0; 213 vs->vs_lastx = 256; /* an invalid address */ 214 vs->vs_lastr = 256; /* an invalid address */ 215 /* 216 * Hang a receive and start any 217 * pending writes by faking a transmit complete. 218 */ 219 s = splimp(); 220 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 221 addr->vviba = (u_short)ubainfo; 222 addr->vviea = (u_short)(ubainfo >> 16); 223 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 224 addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; 225 vs->vs_oactive = 1; 226 vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING; 227 vvxint(unit); 228 splx(s); 229 if_rtinit(&vs->vs_if, RTF_UP); 230 } 231 232 /* 233 * Return our host address. 234 */ 235 vvidentify(unit) 236 int unit; 237 { 238 register struct vv_softc *vs; 239 register struct uba_device *ui; 240 register struct vvreg *addr; 241 register struct mbuf *m; 242 register struct vv_header *v; 243 register int ubainfo, attempts, waitcount; 244 245 /* 246 * Build a multicast message to identify our address 247 */ 248 vs = &vv_softc[unit]; 249 ui = vvinfo[unit]; 250 addr = (struct vvreg *)ui->ui_addr; 251 attempts = 0; /* total attempts, including bad msg type */ 252 m = m_get(M_DONTWAIT, MT_HEADER); 253 if (m == NULL) { 254 printf("vv%d: can't initialize, m_get() failed\n", unit); 255 return (0); 256 } 257 m->m_next = 0; 258 m->m_off = MMINOFF; 259 m->m_len = sizeof(struct vv_header); 260 v = mtod(m, struct vv_header *); 261 v->vh_dhost = VV_BROADCAST; /* multicast destination address */ 262 v->vh_shost = 0; /* will be overwritten with ours */ 263 v->vh_version = RING_VERSION; 264 v->vh_type = RING_WHOAMI; 265 v->vh_info = 0; 266 /* map xmit message into uba */ 267 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 268 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 269 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 270 /* 271 * Reset interface, establish Digital Loopback Mode, and 272 * send the multicast (to myself) with Input Copy enabled. 273 */ 274 retry: 275 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 276 addr->vvicsr = VV_RST; 277 addr->vviba = (u_short) ubainfo; 278 addr->vviea = (u_short) (ubainfo >> 16); 279 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 280 addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; 281 282 /* let flag timers fire so ring will initialize */ 283 DELAY(2000000); /* about 2 SECONDS on a 780!! */ 284 285 addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ 286 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 287 addr->vvoba = (u_short) ubainfo; 288 addr->vvoea = (u_short) (ubainfo >> 16); 289 addr->vvowc = -((vs->vs_olen + 1) >> 1); 290 addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; 291 /* 292 * Wait for receive side to finish. 293 * Extract source address (which will be our own), 294 * and post to interface structure. 295 */ 296 DELAY(10000); 297 for (waitcount = 0; (addr->vvicsr & VV_RDY) == 0; waitcount++) { 298 if (waitcount < 10) { 299 DELAY(1000); 300 continue; 301 } 302 if (attempts++ < VVIDENTRETRY) 303 goto retry; 304 } 305 /* deallocate mbuf used for send packet */ 306 if (vs->vs_ifuba.ifu_xtofree) { 307 m_freem(vs->vs_ifuba.ifu_xtofree); 308 vs->vs_ifuba.ifu_xtofree = 0; 309 } 310 if (attempts >= VVIDENTRETRY) { 311 printf("vv%d: can't initialize after %d tries, icsr = %b\n", 312 unit, VVIDENTRETRY, 0xffff&(addr->vvicsr), VV_IBITS); 313 return (0); 314 } 315 /* Purge BDP before looking at packet we just received */ 316 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 317 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 318 m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); 319 if (m != NULL) 320 m_freem(m); 321 /* 322 * Check message type before we believe the source host address 323 */ 324 v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 325 if (v->vh_type != RING_WHOAMI) 326 goto retry; 327 return(v->vh_shost); 328 } 329 330 /* 331 * Start or restart output on interface. 332 * If interface is active, this is a retransmit, so just 333 * restuff registers and go. 334 * If interface is not already active, get another datagram 335 * to send off of the interface queue, and map it to the interface 336 * before starting the output. 337 */ 338 vvstart(dev) 339 dev_t dev; 340 { 341 register struct uba_device *ui; 342 register struct vv_softc *vs; 343 register struct vvreg *addr; 344 register struct mbuf *m; 345 register int unit, ubainfo, dest, s; 346 347 unit = VVUNIT(dev); 348 ui = vvinfo[unit]; 349 vs = &vv_softc[unit]; 350 if (vs->vs_oactive) 351 goto restart; 352 /* 353 * Not already active: dequeue another request 354 * and map it to the UNIBUS. If no more requests, 355 * just return. 356 */ 357 s = splimp(); 358 IF_DEQUEUE(&vs->vs_if.if_snd, m); 359 splx(s); 360 if (m == NULL) { 361 vs->vs_oactive = 0; 362 return; 363 } 364 dest = mtod(m, struct vv_header *)->vh_dhost; 365 vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); 366 vs->vs_lastx = dest; 367 restart: 368 /* 369 * Have request mapped to UNIBUS for transmission. 370 * Purge any stale data from this BDP, and start the output. 371 * 372 * Make sure this packet will fit in the interface. 373 */ 374 if (vs->vs_olen > VVMTU + sizeof (struct vv_header)) { 375 printf("vv%d vs_olen: %d > VVMTU\n", unit, vs->vs_olen); 376 panic("vvdriver vs_olen botch"); 377 } 378 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 379 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); 380 addr = (struct vvreg *)ui->ui_addr; 381 ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; 382 addr->vvoba = (u_short) ubainfo; 383 addr->vvoea = (u_short) (ubainfo >> 16); 384 addr->vvowc = -((vs->vs_olen + 1) >> 1); 385 addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; 386 vs->vs_if.if_timer = VVTIMEOUT; 387 vs->vs_oactive = 1; 388 } 389 390 /* 391 * VVLNI transmit interrupt 392 * Start another output if more data to send. 393 */ 394 vvxint(unit) 395 int unit; 396 { 397 register struct uba_device *ui; 398 register struct vv_softc *vs; 399 register struct vvreg *addr; 400 register int oc; 401 402 ui = vvinfo[unit]; 403 vs = &vv_softc[unit]; 404 vs->vs_if.if_timer = 0; 405 addr = (struct vvreg *)ui->ui_addr; 406 oc = 0xffff & (addr->vvocsr); 407 if (vs->vs_oactive == 0) { 408 printf("vv%d: stray interrupt vvocsr = %b\n", unit, 409 oc, VV_OBITS); 410 return; 411 } 412 if (oc & (VV_OPT | VV_RFS)) { 413 vs->vs_if.if_collisions++; 414 if (vs->vs_tries++ < VVRETRY) { 415 if (oc & VV_OPT) 416 vs->vs_init++; 417 if (oc & VV_RFS) 418 vs->vs_nottaken++; 419 vvstart(unit); /* restart this message */ 420 return; 421 } 422 if (oc & VV_OPT) 423 printf("vv%d: output timeout\n", unit); 424 } 425 vs->vs_if.if_opackets++; 426 vs->vs_oactive = 0; 427 vs->vs_tries = 0; 428 if (oc & VVXERR) { 429 vs->vs_if.if_oerrors++; 430 printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, 431 VV_OBITS); 432 } 433 if (vs->vs_ifuba.ifu_xtofree) { 434 m_freem(vs->vs_ifuba.ifu_xtofree); 435 vs->vs_ifuba.ifu_xtofree = 0; 436 } 437 vvstart(unit); 438 } 439 440 /* 441 * Transmit watchdog timer routine. 442 * This routine gets called when we lose a transmit interrupt. 443 * The best we can do is try to restart output. 444 */ 445 vvwatchdog(unit) 446 int unit; 447 { 448 register struct vv_softc *vs; 449 register int s; 450 451 vs = &vv_softc[unit]; 452 if (vs->vs_if.if_flags & IFF_DEBUG) 453 printf("vv%d: lost a transmit interrupt.\n", unit); 454 vs->vs_timeouts++; 455 s = splimp(); 456 vvstart(unit); 457 splx(s); 458 } 459 460 /* 461 * V2lni interface receiver interrupt. 462 * If input error just drop packet. 463 * Otherwise purge input buffered data path and examine 464 * packet to determine type. If can't determine length 465 * from type, then have to drop packet. Otherwise decapsulate 466 * packet based on type and pass to type specific higher-level 467 * input routine. 468 */ 469 vvrint(unit) 470 int unit; 471 { 472 register struct vv_softc *vs; 473 register struct vvreg *addr; 474 register struct vv_header *vv; 475 register struct ifqueue *inq; 476 register struct mbuf *m; 477 int ubainfo, len, off, s; 478 short resid; 479 480 vs = &vv_softc[unit]; 481 vs->vs_if.if_ipackets++; 482 addr = (struct vvreg *)vvinfo[unit]->ui_addr; 483 /* 484 * Purge BDP; drop if input error indicated. 485 */ 486 if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) 487 UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); 488 if (addr->vvicsr & VVRERR) { 489 if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 490 printf("vv%d: VVRERR, vvicsr = %b\n", unit, 491 0xffff&(addr->vvicsr), VV_IBITS); 492 goto dropit; 493 } 494 495 /* 496 * Get packet length from word count residue 497 * 498 * Compute header offset if trailer protocol 499 * 500 * Pull packet off interface. Off is nonzero if packet 501 * has trailing header; if_rubaget will then force this header 502 * information to be at the front. The vh_info field 503 * carries the offset to the trailer data in trailer 504 * format packets. 505 */ 506 vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); 507 vvtracehdr("vi", vv); 508 resid = addr->vviwc; 509 if (resid) 510 resid |= 0176000; /* ugly!!!! */ 511 len = (((sizeof (struct vv_header) + VVMRU) >> 1) + resid) << 1; 512 len -= sizeof(struct vv_header); 513 if (len > VVMRU || len <= 0) { 514 if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 515 printf("vv%d: len too big, len = %d, vvicsr = %b\n", 516 unit, len, 0xffff&(addr->vvicsr), VV_IBITS); 517 goto dropit; 518 } 519 #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) 520 if (vv->vh_type >= RING_IPTrailer && 521 vv->vh_type < RING_IPTrailer+RING_IPNTrailer) { 522 off = (vv->vh_type - RING_IPTrailer) * 512; 523 if (off > VVMTU) { 524 if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 525 printf("vv%d: VVMTU, off = %d, vvicsr = %b\n", 526 unit, off, 0xffff&(addr->vvicsr), VV_IBITS); 527 goto dropit; 528 } 529 vv->vh_type = *vvdataaddr(vv, off, u_short *); 530 resid = *(vvdataaddr(vv, off+2, u_short *)); 531 if (off + resid > len) { 532 if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 533 printf( 534 "vv%d: off = %d, resid = %d, vvicsr = %b\n", 535 unit, off, resid, 536 0xffff&(addr->vvicsr), VV_IBITS); 537 goto dropit; 538 } 539 len = off + resid; 540 } else 541 off = 0; 542 if (len == 0) { 543 if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 544 printf("vv%d: len is zero, vvicsr = %b\n", unit, 545 0xffff&(addr->vvicsr), VV_IBITS); 546 goto dropit; 547 } 548 m = if_rubaget(&vs->vs_ifuba, len, off); 549 if (m == NULL) { 550 if (vv_logreaderrors && vs->vs_if.if_flags & IFF_DEBUG) 551 printf("vv%d: if_rubaget failed, vvicsr = %b\n", unit, 552 0xffff&(addr->vvicsr), VV_IBITS); 553 goto dropit; 554 } 555 if (off) { 556 m->m_off += 2 * sizeof(u_short); 557 m->m_len -= 2 * sizeof(u_short); 558 } 559 560 /* Keep track of source address of this packet */ 561 vs->vs_lastr = vv->vh_shost; 562 /* 563 * Demultiplex on packet type 564 */ 565 switch (vv->vh_type) { 566 567 #ifdef INET 568 case RING_IP: 569 schednetisr(NETISR_IP); 570 inq = &ipintrq; 571 break; 572 #endif 573 default: 574 printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); 575 m_freem(m); 576 goto setup; 577 } 578 s = splimp(); 579 if (IF_QFULL(inq)) { 580 IF_DROP(inq); 581 m_freem(m); 582 } else 583 IF_ENQUEUE(inq, m); 584 585 splx(s); 586 /* 587 * Reset for the next packet. 588 */ 589 setup: 590 ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; 591 addr->vviba = (u_short) ubainfo; 592 addr->vviea = (u_short) (ubainfo >> 16); 593 addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; 594 addr->vvicsr = VV_RST | VV_CONF; 595 addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; 596 return; 597 598 /* 599 * Drop packet on floor -- count them!! 600 */ 601 dropit: 602 vs->vs_if.if_ierrors++; 603 goto setup; 604 } 605 606 /* 607 * V2lni output routine. 608 * Encapsulate a packet of type family for the local net. 609 * Use trailer local net encapsulation if enough data in first 610 * packet leaves a multiple of 512 bytes of data in remainder. 611 */ 612 vvoutput(ifp, m0, dst) 613 struct ifnet *ifp; 614 struct mbuf *m0; 615 struct sockaddr *dst; 616 { 617 register struct mbuf *m; 618 register struct vv_header *vv; 619 register int off; 620 register int unit; 621 register struct vvreg *addr; 622 register struct vv_softc *vs; 623 register int s; 624 int type, dest, error; 625 626 m = m0; 627 unit = ifp->if_unit; 628 addr = (struct vvreg *)vvinfo[unit]->ui_addr; 629 vs = &vv_softc[unit]; 630 /* 631 * Check to see if the input side has wedged. 632 * 633 * We are lower than device ipl when we enter this routine, 634 * so if the interface is ready with an input packet then 635 * an input interrupt must have slipped through the cracks. 636 * 637 * Avoid the race with an input interrupt by watching to see 638 * if any packets come in. 639 */ 640 s = vs->vs_if.if_ipackets; 641 if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { 642 if (vs->vs_if.if_flags & IFF_DEBUG) 643 printf("vv%d: lost a receive interrupt, icsr = %b\n", 644 unit, 0xffff&(addr->vvicsr), VV_IBITS); 645 s = splimp(); 646 vvrint(unit); 647 splx(s); 648 } 649 650 switch (dst->sa_family) { 651 652 #ifdef INET 653 case AF_INET: 654 dest = ((struct sockaddr_in *)dst)->sin_addr.s_addr; 655 if ((dest = in_lnaof(*((struct in_addr *)&dest))) >= 0x100) { 656 error = EPERM; 657 goto bad; 658 } 659 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 660 /* Need per host negotiation. */ 661 if ((ifp->if_flags & IFF_NOTRAILERS) == 0) 662 if (off > 0 && (off & 0x1ff) == 0 && 663 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 664 type = RING_IPTrailer + (off>>9); 665 m->m_off -= 2 * sizeof (u_short); 666 m->m_len += 2 * sizeof (u_short); 667 *mtod(m, u_short *) = RING_IP; 668 *(mtod(m, u_short *) + 1) = m->m_len; 669 goto gottrailertype; 670 } 671 type = RING_IP; 672 off = 0; 673 goto gottype; 674 #endif 675 default: 676 printf("vv%d: can't handle af%d\n", unit, dst->sa_family); 677 error = EAFNOSUPPORT; 678 goto bad; 679 } 680 681 gottrailertype: 682 /* 683 * Packet to be sent as trailer: move first packet 684 * (control information) to end of chain. 685 */ 686 while (m->m_next) 687 m = m->m_next; 688 m->m_next = m0; 689 m = m0->m_next; 690 m0->m_next = 0; 691 m0 = m; 692 gottype: 693 /* 694 * Add local net header. If no space in first mbuf, 695 * allocate another. 696 */ 697 if (m->m_off > MMAXOFF || 698 MMINOFF + sizeof (struct vv_header) > m->m_off) { 699 m = m_get(M_DONTWAIT, MT_HEADER); 700 if (m == NULL) { 701 error = ENOBUFS; 702 goto bad; 703 } 704 m->m_next = m0; 705 m->m_off = MMINOFF; 706 m->m_len = sizeof (struct vv_header); 707 } else { 708 m->m_off -= sizeof (struct vv_header); 709 m->m_len += sizeof (struct vv_header); 710 } 711 vv = mtod(m, struct vv_header *); 712 vv->vh_shost = ifp->if_host[0]; 713 /* Map the destination address if it's a broadcast */ 714 if ((vv->vh_dhost = dest) == INADDR_ANY) 715 vv->vh_dhost = VV_BROADCAST; 716 vv->vh_version = RING_VERSION; 717 vv->vh_type = type; 718 vv->vh_info = off; 719 vvtracehdr("vo", vv); 720 721 /* 722 * Queue message on interface, and start output if interface 723 * not yet active. 724 */ 725 s = splimp(); 726 if (IF_QFULL(&ifp->if_snd)) { 727 IF_DROP(&ifp->if_snd); 728 error = ENOBUFS; 729 goto qfull; 730 } 731 IF_ENQUEUE(&ifp->if_snd, m); 732 if (vs->vs_oactive == 0) 733 vvstart(unit); 734 splx(s); 735 return (0); 736 qfull: 737 m0 = m; 738 splx(s); 739 bad: 740 m_freem(m0); 741 return(error); 742 } 743 744 /* 745 * Process an ioctl request. 746 */ 747 vvioctl(ifp, cmd, data) 748 register struct ifnet *ifp; 749 int cmd; 750 caddr_t data; 751 { 752 register struct ifreq *ifr; 753 register int s; 754 int error; 755 756 ifr = (struct ifreq *)data; 757 error = 0; 758 s = splimp(); 759 switch (cmd) { 760 761 case SIOCSIFADDR: 762 if (ifp->if_flags & IFF_RUNNING) 763 if_rtinit(ifp, -1); /* delete previous route */ 764 vvsetaddr(ifp, (struct sockaddr_in *)&ifr->ifr_addr); 765 if (ifp->if_flags & IFF_RUNNING) 766 if_rtinit(ifp, RTF_UP); 767 else 768 vvinit(ifp->if_unit); 769 break; 770 771 default: 772 error = EINVAL; 773 } 774 splx(s); 775 return(error); 776 } 777 778 /* 779 * Set up the address for this interface. We use the network number 780 * from the passed address and an invalid host number; vvinit() will 781 * figure out the host number and insert it later. 782 */ 783 vvsetaddr(ifp, sin) 784 register struct ifnet *ifp; 785 register struct sockaddr_in *sin; 786 { 787 ifp->if_net = in_netof(sin->sin_addr); 788 ifp->if_host[0] = 256; /* an invalid host number */ 789 sin = (struct sockaddr_in *)&ifp->if_addr; 790 sin->sin_family = AF_INET; 791 sin->sin_addr = if_makeaddr(ifp->if_net, ifp->if_host[0]); 792 sin = (struct sockaddr_in *)&ifp->if_broadaddr; 793 sin->sin_family = AF_INET; 794 sin->sin_addr = if_makeaddr(ifp->if_net, INADDR_ANY); 795 ifp->if_flags |= IFF_BROADCAST; 796 } 797 798 /* 799 * vvprt_hdr(s, v) print the local net header in "v" 800 * with title is "s" 801 */ 802 vvprt_hdr(s, v) 803 char *s; 804 register struct vv_header *v; 805 { 806 printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", 807 s, 808 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), 809 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), 810 0xffff & (int)(v->vh_info)); 811 } 812 813 #ifdef notdef 814 /* 815 * print "l" hex bytes starting at "s" 816 */ 817 vvprt_hex(s, l) 818 char *s; 819 int l; 820 { 821 register int i; 822 register int z; 823 824 for (i=0 ; i < l; i++) { 825 z = 0xff & (int)(*(s + i)); 826 printf("%c%c ", 827 "0123456789abcdef"[(z >> 4) & 0x0f], 828 "0123456789abcdef"[z & 0x0f] 829 ); 830 } 831 } 832 #endif 833