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