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