1 /*- 2 * Copyright (c) 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Tim L. Tucker. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)if_we.c 7.3 (Berkeley) 05/21/91 11 */ 12 13 /* 14 * Modification history 15 * 16 * 8/28/89 - Initial version(if_wd.c), Tim L Tucker 17 */ 18 19 #include "we.h" 20 #if NWE > 0 21 /* 22 * Western Digital 8003 ethernet/starlan adapter 23 * 24 * Supports the following interface cards: 25 * WD8003E, WD8003EBT, WD8003S, WD8003SBT, WD8013EBT 26 * 27 * The Western Digital card is one of many AT/MCA ethernet interfaces 28 * based on the National DS8390 Network Interface chip set. 29 */ 30 #include "param.h" 31 #include "mbuf.h" 32 #include "socket.h" 33 #include "ioctl.h" 34 #include "errno.h" 35 #include "syslog.h" 36 37 #include "net/if.h" 38 #include "net/netisr.h" 39 40 #ifdef INET 41 #include "netinet/in.h" 42 #include "netinet/in_systm.h" 43 #include "netinet/in_var.h" 44 #include "netinet/ip.h" 45 #include "netinet/if_ether.h" 46 #endif 47 48 #ifdef NS 49 #include "netns/ns.h" 50 #include "netns/ns_if.h" 51 #endif 52 53 #include "i386/isa/if_wereg.h" 54 #include "i386/isa/isa_device.h" 55 56 /* 57 * This constant should really be 60 because the we adds 4 bytes of crc. 58 * However when set to 60 our packets are ignored by deuna's , 3coms are 59 * okay ?????????????????????????????????????????? 60 */ 61 #define ETHER_MIN_LEN 64 62 #define ETHER_ADDR_LEN 6 63 #define ETHER_HDR_SIZE 14 64 65 /* 66 * Ethernet software status per interface. 67 * 68 * Each interface is referenced by a network interface structure, 69 * qe_if, which the routing code uses to locate the interface. 70 * This structure contains the output queue for the interface, its address, ... 71 */ 72 struct we_softc { 73 struct arpcom we_ac; /* Ethernet common part */ 74 #define we_if we_ac.ac_if /* network-visible interface */ 75 #define we_addr we_ac.ac_enaddr /* hardware Ethernet address */ 76 77 u_char we_flags; /* software state */ 78 #define WDF_RUNNING 0x01 79 #define WDF_TXBUSY 0x02 80 81 u_char we_type; /* interface type code */ 82 u_short we_vector; /* interrupt vector */ 83 short we_io_ctl_addr; /* i/o bus address, control */ 84 short we_io_nic_addr; /* i/o bus address, DS8390 */ 85 86 caddr_t we_vmem_addr; /* card RAM virtual memory base */ 87 u_long we_vmem_size; /* card RAM bytes */ 88 caddr_t we_vmem_ring; /* receive ring RAM vaddress */ 89 caddr_t we_vmem_end; /* receive ring RAM end */ 90 } we_softc[NWE]; 91 92 int weprobe(), weattach(), weintr(), westart(); 93 int weinit(), ether_output(), weioctl(), wereset(), wewatchdog(); 94 95 struct isa_driver wedriver = { 96 weprobe, weattach, "we", 97 }; 98 99 /* 100 * Probe the WD8003 to see if it's there 101 */ 102 weprobe(is) 103 struct isa_device *is; 104 { 105 register int i; 106 register struct we_softc *sc = &we_softc[is->id_unit]; 107 union we_mem_sel wem; 108 u_char sum; 109 110 /* 111 * Here we check the card ROM, if the checksum passes, and the 112 * type code and ethernet address check out, then we know we have 113 * a wd8003 card. 114 * 115 * Autoconfiguration: No warning message is printed on error. 116 */ 117 for (sum = 0, i = 0; i < 8; ++i) 118 sum += inb(is->id_iobase + WD_ROM_OFFSET + i); 119 if (sum != WD_CHECKSUM) 120 return (0); 121 sc->we_type = inb(is->id_iobase + WD_ROM_OFFSET + 6); 122 if ((sc->we_type != WD_ETHER) && (sc->we_type != WD_STARLAN) 123 && (sc->we_type != WD_ETHER2)) 124 return (0); 125 126 /* 127 * Setup card RAM area and i/o addresses 128 * Kernel Virtual to segment C0000-DFFFF????? 129 */ 130 sc->we_io_ctl_addr = is->id_iobase; 131 sc->we_io_nic_addr = sc->we_io_ctl_addr + WD_NIC_OFFSET; 132 sc->we_vector = is->id_irq; 133 sc->we_vmem_addr = (caddr_t)is->id_maddr; 134 sc->we_vmem_size = is->id_msize; 135 sc->we_vmem_ring = sc->we_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE); 136 sc->we_vmem_end = sc->we_vmem_addr + is->id_msize; 137 138 /* 139 * Save board ROM station address 140 */ 141 for (i = 0; i < ETHER_ADDR_LEN; ++i) 142 sc->we_addr[i] = inb(sc->we_io_ctl_addr + WD_ROM_OFFSET + i); 143 144 /* 145 * Mapin interface memory, setup memory select register 146 */ 147 /* wem.ms_addr = (u_long)sc->we_vmem_addr >> 13; */ 148 wem.ms_addr = (u_long)(0xd0000)>> 13; 149 wem.ms_enable = 1; 150 wem.ms_reset = 0; 151 outb(sc->we_io_ctl_addr, wem.ms_byte); 152 153 /* 154 * clear interface memory, then sum to make sure its valid 155 */ 156 for (i = 0; i < sc->we_vmem_size; ++i) 157 sc->we_vmem_addr[i] = 0x0; 158 for (sum = 0, i = 0; i < sc->we_vmem_size; ++i) 159 sum += sc->we_vmem_addr[i]; 160 if (sum != 0x0) { 161 printf("we%d: wd8003 dual port RAM address error\n", is->id_unit); 162 return (0); 163 } 164 165 return (WD_IO_PORTS); 166 } 167 168 /* 169 * Interface exists: make available by filling in network interface 170 * record. System will initialize the interface when it is ready 171 * to accept packets. 172 */ 173 weattach(is) 174 struct isa_device *is; 175 { 176 register struct we_softc *sc = &we_softc[is->id_unit]; 177 register struct ifnet *ifp = &sc->we_if; 178 union we_command wecmd; 179 180 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 181 wecmd.cs_stp = 1; 182 wecmd.cs_sta = 0; 183 wecmd.cs_ps = 0; 184 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 185 /* 186 * Initialize ifnet structure 187 */ 188 ifp->if_unit = is->id_unit; 189 ifp->if_name = "we" ; 190 ifp->if_mtu = ETHERMTU; 191 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ; 192 ifp->if_init = weinit; 193 ifp->if_output = ether_output; 194 ifp->if_start = westart; 195 ifp->if_ioctl = weioctl; 196 ifp->if_reset = wereset; 197 ifp->if_watchdog = wewatchdog; 198 if_attach(ifp); 199 200 /* 201 * Banner... 202 */ 203 printf(" %s address %s", 204 ((sc->we_type != WD_STARLAN) ? "ethernet" : "starlan"), 205 ether_sprintf(sc->we_addr)); 206 } 207 208 /* 209 * Reset of interface. 210 */ 211 wereset(unit, uban) 212 int unit, uban; 213 { 214 if (unit >= NWE) 215 return; 216 printf("we%d: reset\n", unit); 217 /* we_softc[unit].we_flags &= ~WDF_RUNNING; */ 218 weinit(unit); 219 } 220 221 /* 222 * Take interface offline. 223 */ 224 westop(unit) 225 int unit; 226 { 227 register struct we_softc *sc = &we_softc[unit]; 228 union we_command wecmd; 229 int s; 230 231 /* 232 * Shutdown DS8390 233 */ 234 s = splimp(); 235 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 236 wecmd.cs_stp = 1; 237 wecmd.cs_sta = 0; 238 wecmd.cs_ps = 0; 239 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 240 (void) splx(s); 241 } 242 243 wewatchdog(unit) { 244 245 log(LOG_WARNING,"we%d: soft reset\n", unit); 246 westop(unit); 247 weinit(unit); 248 } 249 250 static Bdry; 251 /* 252 * Initialization of interface (really just DS8390). 253 */ 254 weinit(unit) 255 int unit; 256 { 257 register struct we_softc *sc = &we_softc[unit]; 258 register struct ifnet *ifp = &sc->we_if; 259 union we_command wecmd; 260 int i, s; 261 262 /* address not known */ 263 if (ifp->if_addrlist == (struct ifaddr *)0) 264 return; 265 266 /* already running */ 267 /*if (ifp->if_flags & IFF_RUNNING) return; */ 268 269 /* 270 * Initialize DS8390 in order given in NSC NIC manual. 271 * this is stock code...please see the National manual for details. 272 */ 273 s = splhigh(); 274 Bdry = 0; 275 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 276 wecmd.cs_stp = 1; 277 wecmd.cs_sta = 0; 278 wecmd.cs_ps = 0; 279 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 280 outb(sc->we_io_nic_addr + WD_P0_DCR, WD_D_CONFIG); 281 outb(sc->we_io_nic_addr + WD_P0_RBCR0, 0); 282 outb(sc->we_io_nic_addr + WD_P0_RBCR1, 0); 283 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_MON); 284 outb(sc->we_io_nic_addr + WD_P0_TCR, WD_T_CONFIG); 285 outb(sc->we_io_nic_addr + WD_P0_TPSR, 0); 286 outb(sc->we_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE); 287 outb(sc->we_io_nic_addr + WD_P0_PSTOP, 288 sc->we_vmem_size / WD_PAGE_SIZE); 289 outb(sc->we_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE); 290 outb(sc->we_io_nic_addr + WD_P0_ISR, 0xff); 291 outb(sc->we_io_nic_addr + WD_P0_IMR, WD_I_CONFIG); 292 wecmd.cs_ps = 1; 293 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 294 for (i = 0; i < ETHER_ADDR_LEN; ++i) 295 outb(sc->we_io_nic_addr + WD_P1_PAR0 + i, sc->we_addr[i]); 296 for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */ 297 outb(sc->we_io_nic_addr + WD_P1_MAR0 + i, 0xff); 298 outb(sc->we_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE); 299 wecmd.cs_ps = 0; 300 wecmd.cs_stp = 0; 301 wecmd.cs_sta = 1; 302 wecmd.cs_rd = 0x4; 303 outb(sc->we_io_nic_addr + WD_P1_COMMAND, wecmd.cs_byte); 304 outb(sc->we_io_nic_addr + WD_P0_RCR, WD_R_CONFIG); 305 306 /* 307 * Take the interface out of reset, program the vector, 308 * enable interrupts, and tell the world we are up. 309 */ 310 ifp->if_flags |= IFF_RUNNING; 311 sc->we_flags &= ~WDF_TXBUSY; 312 (void) splx(s); 313 westart(ifp); 314 } 315 316 /* 317 * Start output on interface. 318 */ 319 westart(ifp) 320 struct ifnet *ifp; 321 { 322 register struct we_softc *sc = &we_softc[ifp->if_unit]; 323 struct mbuf *m0, *m; 324 register caddr_t buffer; 325 int len, s; 326 union we_command wecmd; 327 328 /* 329 * The DS8390 has only one transmit buffer, if it is busy we 330 * must wait until the transmit interrupt completes. 331 */ 332 s = splhigh(); 333 if (sc->we_flags & WDF_TXBUSY) { 334 (void) splx(s); 335 return; 336 } 337 IF_DEQUEUE(&sc->we_if.if_snd, m); 338 if (m == 0) { 339 (void) splx(s); 340 return; 341 } 342 sc->we_flags |= WDF_TXBUSY; 343 (void) splx(s); 344 345 /* 346 * Copy the mbuf chain into the transmit buffer 347 */ 348 buffer = sc->we_vmem_addr; 349 len = 0; 350 for (m0 = m; m != 0; m = m->m_next) { 351 bcopy(mtod(m, caddr_t), buffer, m->m_len); 352 buffer += m->m_len; 353 len += m->m_len; 354 } 355 356 m_freem(m0); 357 358 /* 359 * Init transmit length registers, and set transmit start flag. 360 */ 361 s = splhigh(); 362 len = MAX(len, ETHER_MIN_LEN); 363 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 364 wecmd.cs_ps = 0; 365 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 366 outb(sc->we_io_nic_addr + WD_P0_TBCR0, len & 0xff); 367 outb(sc->we_io_nic_addr + WD_P0_TBCR1, len >> 8); 368 wecmd.cs_txp = 1; 369 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 370 (void) splx(s); 371 } 372 373 /* 374 * Ethernet interface interrupt processor 375 */ 376 weintr(unit) 377 int unit; 378 { 379 register struct we_softc *sc = &we_softc[unit]; 380 union we_command wecmd; 381 union we_interrupt weisr; 382 383 unit =0; 384 385 /* disable onboard interrupts, then get interrupt status */ 386 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 387 wecmd.cs_ps = 0; 388 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 389 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR); 390 loop: 391 outb(sc->we_io_nic_addr + WD_P0_ISR, weisr.is_byte); 392 393 /* transmit error */ 394 if (weisr.is_txe) { 395 /* need to read these registers to clear status */ 396 sc->we_if.if_collisions += 397 inb(sc->we_io_nic_addr + WD_P0_TBCR0); 398 ++sc->we_if.if_oerrors; 399 } 400 401 /* receiver error */ 402 if (weisr.is_rxe) { 403 /* need to read these registers to clear status */ 404 (void) inb(sc->we_io_nic_addr + 0xD); 405 (void) inb(sc->we_io_nic_addr + 0xE); 406 (void) inb(sc->we_io_nic_addr + 0xF); 407 ++sc->we_if.if_ierrors; 408 } 409 410 /* normal transmit complete */ 411 if (weisr.is_ptx || weisr.is_txe) 412 wetint (unit); 413 414 /* normal receive notification */ 415 if (weisr.is_prx || weisr.is_rxe) 416 werint (unit); 417 418 /* try to start transmit */ 419 westart(&sc->we_if); 420 421 /* re-enable onboard interrupts */ 422 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 423 wecmd.cs_ps = 0; 424 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 425 outb(sc->we_io_nic_addr + WD_P0_IMR, 0xff/*WD_I_CONFIG*/); 426 weisr.is_byte = inb(sc->we_io_nic_addr + WD_P0_ISR); 427 if (weisr.is_byte) goto loop; 428 } 429 430 /* 431 * Ethernet interface transmit interrupt. 432 */ 433 wetint(unit) 434 int unit; 435 { 436 register struct we_softc *sc = &we_softc[unit]; 437 438 /* 439 * Do some statistics (assume page zero of NIC mapped in) 440 */ 441 sc->we_flags &= ~WDF_TXBUSY; 442 sc->we_if.if_timer = 0; 443 ++sc->we_if.if_opackets; 444 sc->we_if.if_collisions += inb(sc->we_io_nic_addr + WD_P0_TBCR0); 445 } 446 447 /* 448 * Ethernet interface receiver interrupt. 449 */ 450 werint(unit) 451 int unit; 452 { 453 register struct we_softc *sc = &we_softc[unit]; 454 u_char bnry, curr; 455 long len; 456 union we_command wecmd; 457 struct we_ring *wer; 458 459 /* 460 * Traverse the receive ring looking for packets to pass back. 461 * The search is complete when we find a descriptor not in use. 462 */ 463 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 464 wecmd.cs_ps = 0; 465 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 466 bnry = inb(sc->we_io_nic_addr + WD_P0_BNRY); 467 wecmd.cs_ps = 1; 468 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 469 curr = inb(sc->we_io_nic_addr + WD_P1_CURR); 470 if(Bdry) 471 bnry =Bdry; 472 473 while (bnry != curr) 474 { 475 /* get pointer to this buffer header structure */ 476 wer = (struct we_ring *)(sc->we_vmem_addr + (bnry << 8)); 477 478 /* count includes CRC */ 479 len = wer->we_count - 4; 480 if (len > 30 && len <= ETHERMTU+100 481 /*&& (*(char *)wer == 1 || *(char *) wer == 0x21)*/) 482 weread(sc, (caddr_t)(wer + 1), len); 483 else printf("reject %d", len); 484 485 outofbufs: 486 wecmd.cs_byte = inb(sc->we_io_nic_addr + WD_P0_COMMAND); 487 wecmd.cs_ps = 0; 488 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 489 490 /* advance on chip Boundry register */ 491 if((caddr_t) wer + WD_PAGE_SIZE - 1 > sc->we_vmem_end) { 492 bnry = WD_TXBUF_SIZE; 493 outb(sc->we_io_nic_addr + WD_P0_BNRY, 494 sc->we_vmem_size / WD_PAGE_SIZE-1); 495 496 } else { 497 if (len > 30 && len <= ETHERMTU+100) 498 bnry = wer->we_next_packet; 499 else bnry = curr; 500 501 /* watch out for NIC overflow, reset Boundry if invalid */ 502 if ((bnry - 1) < WD_TXBUF_SIZE) { 503 outb(sc->we_io_nic_addr + WD_P0_BNRY, 504 (sc->we_vmem_size / WD_PAGE_SIZE) - 1); 505 bnry = WD_TXBUF_SIZE; 506 } else 507 outb(sc->we_io_nic_addr + WD_P0_BNRY, bnry-1); 508 } 509 510 /* refresh our copy of CURR */ 511 wecmd.cs_ps = 1; 512 outb(sc->we_io_nic_addr + WD_P0_COMMAND, wecmd.cs_byte); 513 curr = inb(sc->we_io_nic_addr + WD_P1_CURR); 514 } 515 Bdry = bnry; 516 } 517 518 #ifdef shit 519 /* 520 * Process an ioctl request. 521 */ 522 weioctl(ifp, cmd, data) 523 register struct ifnet *ifp; 524 int cmd; 525 caddr_t data; 526 { 527 struct we_softc *sc = &we_softc[ifp->if_unit]; 528 struct ifaddr *ifa = (struct ifaddr *)data; 529 int s = splimp(), error = 0; 530 531 switch (cmd) { 532 533 case SIOCSIFADDR: 534 ifp->if_flags |= IFF_UP; 535 weinit(ifp->if_unit); 536 switch(ifa->ifa_addr->sa_family) { 537 #ifdef INET 538 case AF_INET: 539 ((struct arpcom *)ifp)->ac_ipaddr = 540 IA_SIN(ifa)->sin_addr; 541 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 542 break; 543 #endif 544 #ifdef NS 545 case AF_NS: 546 { 547 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 548 549 if (ns_nullhost(*ina)) 550 ina->x_host = *(union ns_host *)(sc->we_addr); 551 else 552 wesetaddr(ina->x_host.c_host, ifp->if_unit); 553 break; 554 } 555 #endif 556 } 557 break; 558 559 case SIOCSIFFLAGS: 560 if (((ifp->if_flags & IFF_UP) == 0) && 561 (sc->we_flags & WDF_RUNNING)) { 562 westop(ifp->if_unit); 563 } else if (((ifp->if_flags & IFF_UP) == IFF_UP) && 564 ((sc->we_flags & WDF_RUNNING) == 0)) 565 weinit(ifp->if_unit); 566 break; 567 568 default: 569 error = EINVAL; 570 571 } 572 (void) splx(s); 573 return (error); 574 } 575 #endif 576 577 /* 578 * Process an ioctl request. 579 */ 580 weioctl(ifp, cmd, data) 581 register struct ifnet *ifp; 582 int cmd; 583 caddr_t data; 584 { 585 register struct ifaddr *ifa = (struct ifaddr *)data; 586 struct we_softc *sc = &we_softc[ifp->if_unit]; 587 struct ifreq *ifr = (struct ifreq *)data; 588 int s = splimp(), error = 0; 589 590 591 switch (cmd) { 592 593 case SIOCSIFADDR: 594 ifp->if_flags |= IFF_UP; 595 596 switch (ifa->ifa_addr->sa_family) { 597 #ifdef INET 598 case AF_INET: 599 weinit(ifp->if_unit); /* before arpwhohas */ 600 ((struct arpcom *)ifp)->ac_ipaddr = 601 IA_SIN(ifa)->sin_addr; 602 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 603 break; 604 #endif 605 #ifdef NS 606 case AF_NS: 607 { 608 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 609 610 if (ns_nullhost(*ina)) 611 ina->x_host = *(union ns_host *)(sc->ns_addr); 612 else { 613 /* 614 * The manual says we can't change the address 615 * while the receiver is armed, 616 * so reset everything 617 */ 618 ifp->if_flags &= ~IFF_RUNNING; 619 bcopy((caddr_t)ina->x_host.c_host, 620 (caddr_t)sc->ns_addr, sizeof(sc->ns_addr)); 621 } 622 weinit(ifp->if_unit); /* does ne_setaddr() */ 623 break; 624 } 625 #endif 626 default: 627 weinit(ifp->if_unit); 628 break; 629 } 630 break; 631 632 case SIOCSIFFLAGS: 633 if ((ifp->if_flags & IFF_UP) == 0 && 634 ifp->if_flags & IFF_RUNNING) { 635 ifp->if_flags &= ~IFF_RUNNING; 636 westop(ifp->if_unit); 637 } else if (ifp->if_flags & IFF_UP && 638 (ifp->if_flags & IFF_RUNNING) == 0) 639 weinit(ifp->if_unit); 640 break; 641 642 #ifdef notdef 643 case SIOCGHWADDR: 644 bcopy((caddr_t)sc->sc_addr, (caddr_t) &ifr->ifr_data, 645 sizeof(sc->sc_addr)); 646 break; 647 #endif 648 649 default: 650 error = EINVAL; 651 } 652 splx(s); 653 return (error); 654 } 655 /* 656 * set ethernet address for unit 657 */ 658 wesetaddr(physaddr, unit) 659 u_char *physaddr; 660 int unit; 661 { 662 register struct we_softc *sc = &we_softc[unit]; 663 register int i; 664 665 /* 666 * Rewrite ethernet address, and then force restart of NIC 667 */ 668 for (i = 0; i < ETHER_ADDR_LEN; i++) 669 sc->we_addr[i] = physaddr[i]; 670 sc->we_flags &= ~WDF_RUNNING; 671 weinit(unit); 672 } 673 674 #define wedataaddr(sc, eh, off, type) \ 675 ((type) ((caddr_t)((eh)+1)+(off) >= (sc)->we_vmem_end) ? \ 676 (((caddr_t)((eh)+1)+(off))) - (sc)->we_vmem_end \ 677 + (sc)->we_vmem_ring: \ 678 ((caddr_t)((eh)+1)+(off))) 679 /* 680 * Pass a packet to the higher levels. 681 * We deal with the trailer protocol here. 682 */ 683 weread(sc, buf, len) 684 register struct we_softc *sc; 685 char *buf; 686 int len; 687 { 688 register struct ether_header *eh; 689 struct mbuf *m, *weget(); 690 int off, resid; 691 692 /* 693 * Deal with trailer protocol: if type is trailer type 694 * get true type from first 16-bit word past data. 695 * Remember that type was trailer by setting off. 696 */ 697 eh = (struct ether_header *)buf; 698 eh->ether_type = ntohs((u_short)eh->ether_type); 699 if (eh->ether_type >= ETHERTYPE_TRAIL && 700 eh->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 701 off = (eh->ether_type - ETHERTYPE_TRAIL) * 512; 702 if (off >= ETHERMTU) return; /* sanity */ 703 eh->ether_type = ntohs(*wedataaddr(sc, eh, off, u_short *)); 704 resid = ntohs(*(wedataaddr(sc, eh, off+2, u_short *))); 705 if (off + resid > len) return; /* sanity */ 706 len = off + resid; 707 } else off = 0; 708 709 len -= sizeof(struct ether_header); 710 if (len <= 0) return; 711 712 /* 713 * Pull packet off interface. Off is nonzero if packet 714 * has trailing header; neget will then force this header 715 * information to be at the front, but we still have to drop 716 * the type and length which are at the front of any trailer data. 717 */ 718 m = weget(buf, len, off, &sc->we_if, sc); 719 if (m == 0) return; 720 ether_input(&sc->we_if, eh, m); 721 } 722 723 /* 724 * Supporting routines 725 */ 726 727 /* 728 * Pull read data off a interface. 729 * Len is length of data, with local net header stripped. 730 * Off is non-zero if a trailer protocol was used, and 731 * gives the offset of the trailer information. 732 * We copy the trailer information and then all the normal 733 * data into mbufs. When full cluster sized units are present 734 * we copy into clusters. 735 */ 736 struct mbuf * 737 weget(buf, totlen, off0, ifp, sc) 738 caddr_t buf; 739 int totlen, off0; 740 struct ifnet *ifp; 741 struct we_softc *sc; 742 { 743 struct mbuf *top, **mp, *m, *p; 744 int off = off0, len; 745 register caddr_t cp = buf; 746 char *epkt; 747 int tc =totlen; 748 749 buf += sizeof(struct ether_header); 750 cp = buf; 751 epkt = cp + totlen; 752 753 if (off) { 754 cp += off + 2 * sizeof(u_short); 755 totlen -= 2 * sizeof(u_short); 756 } 757 758 MGETHDR(m, M_DONTWAIT, MT_DATA); 759 if (m == 0) 760 return (0); 761 m->m_pkthdr.rcvif = ifp; 762 m->m_pkthdr.len = totlen; 763 m->m_len = MHLEN; 764 765 top = 0; 766 mp = ⊤ 767 while (totlen > 0) { 768 if (top) { 769 MGET(m, M_DONTWAIT, MT_DATA); 770 if (m == 0) { 771 m_freem(top); 772 return (0); 773 } 774 m->m_len = MLEN; 775 } 776 len = min(totlen, epkt - cp); 777 if (len >= MINCLSIZE) { 778 MCLGET(m, M_DONTWAIT); 779 if (m->m_flags & M_EXT) 780 m->m_len = len = min(len, MCLBYTES); 781 else 782 len = m->m_len; 783 } else { 784 /* 785 * Place initial small packet/header at end of mbuf. 786 */ 787 if (len < m->m_len) { 788 if (top == 0 && len + max_linkhdr <= m->m_len) 789 m->m_data += max_linkhdr; 790 m->m_len = len; 791 } else 792 len = m->m_len; 793 } 794 795 totlen -= len; 796 /* only do up to end of buffer */ 797 if (cp+len > sc->we_vmem_end) { 798 unsigned toend = sc->we_vmem_end - cp; 799 800 bcopy(cp, mtod(m, caddr_t), toend); 801 cp = sc->we_vmem_ring; 802 bcopy(cp, mtod(m, caddr_t)+toend, len - toend); 803 cp += len - toend; 804 epkt = cp + totlen; 805 } else { 806 bcopy(cp, mtod(m, caddr_t), (unsigned)len); 807 cp += len; 808 } 809 *mp = m; 810 mp = &m->m_next; 811 if (cp == epkt) { 812 cp = buf; 813 epkt = cp + tc; 814 } 815 } 816 return (top); 817 } 818 #endif 819