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.noredist.c% 9 * 10 * @(#)if_we.c 5.1 (Berkeley) 04/22/90 11 */ 12 13 /* 14 * Modification history 15 * 16 * 8/28/89 - Initial version, Tim L Tucker 17 */ 18 19 #include "wd.h" 20 #if NWD > 0 21 /* 22 * Western Digital 8003 ethernet/starlan adapter 23 * 24 * Supports the following interface cards: 25 * WD8003E, WD8003EBT, WD8003S, WD8003SBT 26 * 27 * The Western Digital card is one of many AT/MCA ethernet interfaces 28 * based on the National N8390/NS32490 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 "if_wdreg.h" 54 #include "../isa/isavar.h" 55 56 /* 57 * This constant should really be 60 because the wd 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 wd_softc { 73 struct arpcom wd_ac; /* Ethernet common part */ 74 #define wd_if wd_ac.ac_if /* network-visible interface */ 75 #define wd_addr wd_ac.ac_enaddr /* hardware Ethernet address */ 76 77 u_char wd_flags; /* software state */ 78 #define WDF_RUNNING 0x01 79 #define WDF_TXBUSY 0x02 80 81 u_char wd_type; /* interface type code */ 82 u_short wd_vector; /* interrupt vector */ 83 caddr_t wd_io_ctl_addr; /* i/o bus address, control */ 84 caddr_t wd_io_nic_addr; /* i/o bus address, NS32490 */ 85 86 caddr_t wd_vmem_addr; /* card RAM virtual memory base */ 87 u_long wd_vmem_size; /* card RAM bytes */ 88 caddr_t wd_vmem_ring; /* receive ring RAM vaddress */ 89 } wd_softc[NWD]; 90 91 int wdprobe(), wdattach(), wdintr(); 92 int wdinit(), wdoutput(), wdioctl(), wdreset(); 93 94 /* 95 * Probe the WD8003 to see if it's there 96 */ 97 wdprobe(reg, is) 98 caddr_t reg; 99 struct isa_device *is; 100 { 101 register int i; 102 register struct wd_softc *sc = &wd_softc[is->is_unit]; 103 union wd_mem_sel wdm; 104 u_char sum; 105 106 /* 107 * Here we check the card ROM, if the checksum passes, and the 108 * type code and ethernet address check out, then we know we have 109 * a wd8003 card. 110 * 111 * Autoconfiguration: No warning message is printed on error. 112 */ 113 for (sum = 0, i = 0; i < 8; ++i) 114 sum += INB(reg + WD_ROM_OFFSET + i); 115 if (sum != WD_CHECKSUM) 116 return (0); 117 sc->wd_type = INB(reg + WD_ROM_OFFSET + 6); 118 if ((sc->wd_type != WD_ETHER) && (sc->wd_type != WD_STARLAN)) 119 return (0); 120 121 /* 122 * Setup card RAM area and i/o addresses 123 * Kernel Virtual to segment C0000-DFFFF????? 124 */ 125 sc->wd_io_ctl_addr = reg; 126 sc->wd_io_nic_addr = sc->wd_io_ctl_addr + WD_NIC_OFFSET; 127 sc->wd_vector = is->is_vector; 128 sc->wd_vmem_addr = (caddr_t)is->is_mem; 129 sc->wd_vmem_size = is->is_memsize; 130 sc->wd_vmem_ring = sc->wd_vmem_addr + (WD_PAGE_SIZE * WD_TXBUF_SIZE); 131 132 /* 133 * Save board ROM station address 134 */ 135 for (i = 0; i < ETHER_ADDR_LEN; ++i) 136 sc->wd_addr[i] = INB(sc->wd_io_ctl_addr + WD_ROM_OFFSET + i); 137 138 /* 139 * Mapin interface memory, setup memory select register 140 */ 141 wdm.ms_addr = (u_long)sc->wd_vmem_addr >> 13; 142 wdm.ms_enable = 1; 143 wdm.ms_reset = 0; 144 OUTB(sc->wd_io_ctl_addr, wdm.ms_byte); 145 146 /* 147 * clear interface memory, then sum to make sure its valid 148 */ 149 for (i = 0; i < sc->wd_vmem_size; ++i) 150 sc->wd_vmem_addr[i] = 0x0; 151 for (sum = 0, i = 0; i < sc->wd_vmem_size; ++i) 152 sum += sc->wd_vmem_addr[i]; 153 if (sum != 0x0) { 154 printf("wd%d: wd8003 dual port RAM address error\n", is->is_unit); 155 return (0); 156 } 157 158 return (WD_IO_PORTS); 159 } 160 161 /* 162 * Interface exists: make available by filling in network interface 163 * record. System will initialize the interface when it is ready 164 * to accept packets. 165 */ 166 wdattach(is) 167 struct isa_device *is; 168 { 169 register struct wd_softc *sc = &wd_softc[is->is_unit]; 170 register struct ifnet *ifp = &sc->wd_if; 171 172 /* 173 * Initialize ifnet structure 174 */ 175 ifp->if_unit = is->is_unit; 176 ifp->if_name = "wd"; 177 ifp->if_mtu = ETHERMTU; 178 ifp->if_flags = IFF_BROADCAST|IFF_NOTRAILERS; 179 ifp->if_init = wdinit; 180 ifp->if_output = wdoutput; 181 ifp->if_ioctl = wdioctl; 182 ifp->if_reset = wdreset; 183 ifp->if_watchdog = 0; 184 if_attach(ifp); 185 186 /* 187 * Banner... 188 */ 189 printf("wd%d: %s, hardware address %s\n", is->is_unit, 190 ((sc->wd_type == WD_ETHER) ? "ethernet" : "starlan"), 191 ether_sprintf(sc->wd_addr)); 192 } 193 194 /* 195 * Reset of interface. 196 */ 197 wdreset(unit, uban) 198 int unit, uban; 199 { 200 if (unit >= NWD) 201 return; 202 printf("wd%d: reset\n", unit); 203 wd_softc[unit].wd_flags &= ~WDF_RUNNING; 204 wdinit(unit); 205 } 206 207 /* 208 * Take interface offline. 209 */ 210 wdstop(unit) 211 int unit; 212 { 213 register struct wd_softc *sc = &wd_softc[unit]; 214 union wd_command wdcmd; 215 int s; 216 217 /* 218 * Shutdown NS32490 219 */ 220 s = splimp(); 221 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND); 222 wdcmd.cs_stp = 1; 223 wdcmd.cs_sta = 0; 224 wdcmd.cs_ps = 0; 225 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 226 (void) splx(s); 227 } 228 229 /* 230 * Initialization of interface (really just NS32490). 231 */ 232 wdinit(unit) 233 int unit; 234 { 235 register struct wd_softc *sc = &wd_softc[unit]; 236 register struct ifnet *ifp = &sc->wd_if; 237 union wd_command wdcmd; 238 int i, s; 239 240 /* address not known */ 241 if (ifp->if_addrlist == (struct ifaddr *)0) 242 return; 243 244 /* already running */ 245 if (sc->wd_flags & WDF_RUNNING) 246 return; 247 248 /* 249 * Initialize NS32490 in order given in NSC NIC manual. 250 * this is stock code...please see the National manual for details. 251 */ 252 s = splhi(); 253 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND); 254 wdcmd.cs_stp = 1; 255 wdcmd.cs_sta = 0; 256 wdcmd.cs_ps = 0; 257 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 258 OUTB(sc->wd_io_nic_addr + WD_P0_DCR, WD_D_CONFIG); 259 OUTB(sc->wd_io_nic_addr + WD_P0_RBCR0, 0); 260 OUTB(sc->wd_io_nic_addr + WD_P0_RBCR1, 0); 261 OUTB(sc->wd_io_nic_addr + WD_P0_RCR, WD_R_MON); 262 OUTB(sc->wd_io_nic_addr + WD_P0_TCR, WD_T_CONFIG); 263 OUTB(sc->wd_io_nic_addr + WD_P0_TPSR, 0); 264 OUTB(sc->wd_io_nic_addr + WD_P0_PSTART, WD_TXBUF_SIZE); 265 OUTB(sc->wd_io_nic_addr + WD_P0_PSTOP, 266 sc->wd_vmem_size / WD_PAGE_SIZE); 267 OUTB(sc->wd_io_nic_addr + WD_P0_BNRY, WD_TXBUF_SIZE); 268 OUTB(sc->wd_io_nic_addr + WD_P0_ISR, 0xff); 269 OUTB(sc->wd_io_nic_addr + WD_P0_IMR, WD_I_CONFIG); 270 wdcmd.cs_ps = 1; 271 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 272 for (i = 0; i < ETHER_ADDR_LEN; ++i) 273 OUTB(sc->wd_io_nic_addr + WD_P1_PAR0 + i, sc->wd_addr[i]); 274 for (i = 0; i < ETHER_ADDR_LEN; ++i) /* == broadcast addr */ 275 OUTB(sc->wd_io_nic_addr + WD_P1_MAR0 + i, 0xff); 276 OUTB(sc->wd_io_nic_addr + WD_P1_CURR, WD_TXBUF_SIZE); 277 wdcmd.cs_ps = 0; 278 wdcmd.cs_stp = 0; 279 wdcmd.cs_sta = 1; 280 wdcmd.cs_rd = 0x4; 281 OUTB(sc->wd_io_nic_addr + WD_P1_COMMAND, wdcmd.cs_byte); 282 OUTB(sc->wd_io_nic_addr + WD_P0_RCR, WD_R_CONFIG); 283 284 /* 285 * Take the interface out of reset, program the vector, 286 * enable interrupts, and tell the world we are up. 287 */ 288 ifp->if_flags |= IFF_UP | IFF_RUNNING; 289 sc->wd_flags |= WDF_RUNNING; 290 sc->wd_flags &= ~WDF_TXBUSY; 291 (void) splx(s); 292 wdstart(unit); 293 } 294 295 /* 296 * Start output on interface. 297 */ 298 wdstart(unit) 299 int unit; 300 { 301 register struct wd_softc *sc = &wd_softc[unit]; 302 struct mbuf *m0, *m; 303 register caddr_t buffer; 304 int len = 0, s; 305 union wd_command wdcmd; 306 307 /* 308 * The NS32490 has only one transmit buffer, if it is busy we 309 * must wait until the transmit interrupt completes. 310 */ 311 s = splhi(); 312 if (sc->wd_flags & WDF_TXBUSY) { 313 (void) splx(s); 314 return; 315 } 316 IF_DEQUEUE(&sc->wd_if.if_snd, m); 317 if (m == 0) { 318 (void) splx(s); 319 return; 320 } 321 sc->wd_flags |= WDF_TXBUSY; 322 (void) splx(s); 323 324 /* 325 * Copy the mbuf chain into the transmit buffer 326 */ 327 buffer = sc->wd_vmem_addr; 328 for (m0 = m; m != 0; m = m->m_next) { 329 bcopy(mtod(m, caddr_t), buffer, m->m_len); 330 buffer += m->m_len; 331 len += m->m_len; 332 } 333 334 /* 335 * If this was a broadcast packet loop it 336 * back because the hardware can't hear its own 337 * transmits. 338 */ 339 if (bcmp((caddr_t)(mtod(m0, struct ether_header *)->ether_dhost), 340 (caddr_t)etherbroadcastaddr, 341 sizeof(etherbroadcastaddr)) == 0) { 342 wdread(sc, m0); 343 } else { 344 m_freem(m0); 345 } 346 347 /* 348 * Init transmit length registers, and set transmit start flag. 349 */ 350 s = splhi(); 351 len = MAX(len, ETHER_MIN_LEN); 352 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND); 353 wdcmd.cs_ps = 0; 354 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 355 OUTB(sc->wd_io_nic_addr + WD_P0_TBCR0, len & 0xff); 356 OUTB(sc->wd_io_nic_addr + WD_P0_TBCR1, len >> 8); 357 wdcmd.cs_txp = 1; 358 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 359 (void) splx(s); 360 } 361 362 /* 363 * Ethernet interface interrupt processor 364 */ 365 wdintr(unit) 366 int unit; 367 { 368 register struct wd_softc *sc = &wd_softc[unit]; 369 union wd_command wdcmd; 370 union wd_interrupt wdisr; 371 int s; 372 373 /* disable onboard interrupts, then get interrupt status */ 374 s = splhi(); 375 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND); 376 wdcmd.cs_ps = 0; 377 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 378 OUTB(sc->wd_io_nic_addr + WD_P0_IMR, 0); 379 wdisr.is_byte = INB(sc->wd_io_nic_addr + WD_P0_ISR); 380 OUTB(sc->wd_io_nic_addr + WD_P0_ISR, 0xff); 381 (void) splx(s); 382 383 /* transmit error */ 384 if (wdisr.is_txe) { 385 /* need to read these registers to clear status */ 386 sc->wd_if.if_collisions += 387 INB(sc->wd_io_nic_addr + WD_P0_TBCR0); 388 ++sc->wd_if.if_oerrors; 389 } 390 391 /* receiver error */ 392 if (wdisr.is_rxe) { 393 /* need to read these registers to clear status */ 394 (void) INB(sc->wd_io_nic_addr + 0xD); 395 (void) INB(sc->wd_io_nic_addr + 0xE); 396 (void) INB(sc->wd_io_nic_addr + 0xF); 397 ++sc->wd_if.if_ierrors; 398 } 399 400 /* normal transmit complete */ 401 if (wdisr.is_ptx) 402 wdtint (unit); 403 404 /* normal receive notification */ 405 if (wdisr.is_prx) 406 wdrint (unit); 407 408 /* try to start transmit */ 409 wdstart(unit); 410 411 /* re-enable onboard interrupts */ 412 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND); 413 wdcmd.cs_ps = 0; 414 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 415 OUTB(sc->wd_io_nic_addr + WD_P0_IMR, WD_I_CONFIG); 416 } 417 418 /* 419 * Ethernet interface transmit interrupt. 420 */ 421 wdtint(unit) 422 int unit; 423 { 424 register struct wd_softc *sc = &wd_softc[unit]; 425 426 /* 427 * Do some statistics (assume page zero of NIC mapped in) 428 */ 429 sc->wd_flags &= ~WDF_TXBUSY; 430 sc->wd_if.if_timer = 0; 431 ++sc->wd_if.if_opackets; 432 sc->wd_if.if_collisions += INB(sc->wd_io_nic_addr + WD_P0_TBCR0); 433 } 434 435 /* 436 * Ethernet interface receiver interrupt. 437 */ 438 wdrint(unit) 439 int unit; 440 { 441 register struct wd_softc *sc = &wd_softc[unit]; 442 register struct mbuf **m; 443 int mlen, len, count; 444 u_char bnry, curr; 445 union wd_command wdcmd; 446 struct wd_ring *wdr; 447 struct mbuf *m0; 448 caddr_t pkt, endp; 449 450 /* 451 * Traverse the receive ring looking for packets to pass back. 452 * The search is complete when we find a descriptor not in use. 453 */ 454 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND); 455 wdcmd.cs_ps = 0; 456 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 457 bnry = INB(sc->wd_io_nic_addr + WD_P0_BNRY); 458 wdcmd.cs_ps = 1; 459 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 460 curr = INB(sc->wd_io_nic_addr + WD_P1_CURR); 461 while (bnry != curr) 462 { 463 /* get pointer to this buffer header structure */ 464 wdr = (struct wd_ring *)(sc->wd_vmem_addr + (bnry << 8)); 465 len = wdr->wd_count - 4; /* count includes CRC */ 466 pkt = (caddr_t)(wdr + 1) - 2; /* 2 - word align pkt data */ 467 count = len + 2; /* copy two extra bytes */ 468 endp = (caddr_t)(sc->wd_vmem_addr + sc->wd_vmem_size); 469 ++sc->wd_if.if_ipackets; 470 471 /* pull packet out of dual ported RAM */ 472 m = &m0; m0 = 0; 473 while (count > 0) 474 { 475 /* drop chain if can't get another buffer */ 476 MGET(*m, M_DONTWAIT, MT_DATA); 477 if (*m == 0) 478 { 479 m_freem(m0); 480 goto outofbufs; 481 } 482 483 /* fill mbuf and attach to packet list */ 484 mlen = MIN(MLEN, count); 485 mlen = MIN(mlen, endp - pkt); 486 bcopy(pkt, mtod(*m, caddr_t), mlen); 487 (*m)->m_len = mlen; 488 m = &((*m)->m_next); 489 pkt += mlen; 490 count -= mlen; 491 492 /* wrap memory pointer around circ buffer */ 493 if (pkt == endp) 494 pkt = (caddr_t)sc->wd_vmem_ring; 495 } 496 497 /* skip aligment bytes, send packet up to higher levels */ 498 if (m0 != 0) 499 { 500 m0->m_off += 2; 501 wdread(sc, m0); 502 } 503 504 outofbufs: 505 /* advance on chip Boundry register */ 506 bnry = wdr->wd_next_packet; 507 wdcmd.cs_byte = INB(sc->wd_io_nic_addr + WD_P0_COMMAND); 508 wdcmd.cs_ps = 0; 509 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 510 511 /* watch out for NIC overflow, reset Boundry if invalid */ 512 if ((bnry - 1) < WD_TXBUF_SIZE) { 513 #ifdef notdef 514 wdreset(unit, 0); 515 break; 516 #else 517 OUTB(sc->wd_io_nic_addr + WD_P0_BNRY, 518 (sc->wd_vmem_size / WD_PAGE_SIZE) - 1); 519 #endif 520 } 521 OUTB(sc->wd_io_nic_addr + WD_P0_BNRY, bnry - 1); 522 523 /* refresh our copy of CURR */ 524 wdcmd.cs_ps = 1; 525 OUTB(sc->wd_io_nic_addr + WD_P0_COMMAND, wdcmd.cs_byte); 526 curr = INB(sc->wd_io_nic_addr + WD_P1_CURR); 527 } 528 } 529 530 /* 531 * Ethernet output routine. 532 * Encapsulate a packet of type family for the local net. 533 */ 534 wdoutput(ifp, m0, dst) 535 struct ifnet *ifp; 536 struct mbuf *m0; 537 struct sockaddr *dst; 538 { 539 int type, s, error; 540 u_char edst[6]; 541 struct in_addr idst; 542 register struct wd_softc *sc = &wd_softc[ifp->if_unit]; 543 register struct mbuf *m = m0; 544 register struct ether_header *eh; 545 int usetrailers; 546 547 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { 548 error = ENETDOWN; 549 goto bad; 550 } 551 552 switch (dst->sa_family) { 553 554 #ifdef INET 555 case AF_INET: 556 /* Note: we ignore usetrailers */ 557 idst = ((struct sockaddr_in *)dst)->sin_addr; 558 if (!arpresolve(&sc->wd_ac, m, &idst, edst, &usetrailers)) 559 return (0); /* if not yet resolved */ 560 type = ETHERTYPE_IP; 561 break; 562 #endif 563 #ifdef NS 564 case AF_NS: 565 type = ETHERTYPE_NS; 566 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 567 (caddr_t)edst, sizeof (edst)); 568 break; 569 #endif 570 571 572 case AF_UNSPEC: 573 eh = (struct ether_header *)dst->sa_data; 574 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst)); 575 type = eh->ether_type; 576 break; 577 578 default: 579 printf("wd%d: can't handle af%d\n", ifp->if_unit, 580 dst->sa_family); 581 error = EAFNOSUPPORT; 582 goto bad; 583 } 584 585 /* 586 * Add local net header. If no space in first mbuf, 587 * allocate another. 588 */ 589 if (m->m_off > MMAXOFF || MMINOFF + ETHER_HDR_SIZE > m->m_off) { 590 m = m_get(M_DONTWAIT, MT_HEADER); 591 if (m == 0) { 592 error = ENOBUFS; 593 goto bad; 594 } 595 m->m_next = m0; 596 m->m_off = MMINOFF; 597 m->m_len = ETHER_HDR_SIZE; 598 } else { 599 m->m_off -= ETHER_HDR_SIZE; 600 m->m_len += ETHER_HDR_SIZE; 601 } 602 eh = mtod(m, struct ether_header *); 603 eh->ether_type = htons((u_short)type); 604 bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst)); 605 bcopy((caddr_t)sc->wd_addr, (caddr_t)eh->ether_shost, 606 sizeof (sc->wd_addr)); 607 608 /* 609 * Queue message on interface, and start output if interface 610 * not yet active. 611 */ 612 s = splimp(); 613 if (IF_QFULL(&ifp->if_snd)) { 614 IF_DROP(&ifp->if_snd); 615 (void) splx(s); 616 m_freem(m); 617 return (ENOBUFS); 618 } 619 IF_ENQUEUE(&ifp->if_snd, m); 620 (void) splx(s); 621 wdstart(ifp->if_unit); 622 return (0); 623 624 bad: 625 m_freem(m0); 626 return (error); 627 } 628 629 /* 630 * Process an ioctl request. 631 */ 632 wdioctl(ifp, cmd, data) 633 register struct ifnet *ifp; 634 int cmd; 635 caddr_t data; 636 { 637 struct wd_softc *sc = &wd_softc[ifp->if_unit]; 638 struct ifaddr *ifa = (struct ifaddr *)data; 639 int s = splimp(), error = 0; 640 641 switch (cmd) { 642 643 case SIOCSIFADDR: 644 ifp->if_flags |= IFF_UP; 645 wdinit(ifp->if_unit); 646 switch(ifa->ifa_addr.sa_family) { 647 #ifdef INET 648 case AF_INET: 649 ((struct arpcom *)ifp)->ac_ipaddr = 650 IA_SIN(ifa)->sin_addr; 651 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 652 break; 653 #endif 654 #ifdef NS 655 case AF_NS: 656 { 657 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 658 659 if (ns_nullhost(*ina)) 660 ina->x_host = *(union ns_host *)(sc->wd_addr); 661 else 662 wdsetaddr(ina->x_host.c_host, ifp->if_unit); 663 break; 664 } 665 #endif 666 } 667 break; 668 669 case SIOCSIFFLAGS: 670 if (((ifp->if_flags & IFF_UP) == 0) && 671 (sc->wd_flags & WDF_RUNNING)) { 672 wdstop(ifp->if_unit); 673 } else if (((ifp->if_flags & IFF_UP) == IFF_UP) && 674 ((sc->wd_flags & WDF_RUNNING) == 0)) 675 wdinit(ifp->if_unit); 676 break; 677 678 default: 679 error = EINVAL; 680 681 } 682 (void) splx(s); 683 return (error); 684 } 685 686 /* 687 * set ethernet address for unit 688 */ 689 wdsetaddr(physaddr, unit) 690 u_char *physaddr; 691 int unit; 692 { 693 register struct wd_softc *sc = &wd_softc[unit]; 694 register int i; 695 696 /* 697 * Rewrite ethernet address, and then force restart of NIC 698 */ 699 for (i = 0; i < ETHER_ADDR_LEN; i++) 700 sc->wd_addr[i] = physaddr[i]; 701 sc->wd_flags &= ~WDF_RUNNING; 702 wdinit(unit); 703 } 704 705 /* 706 * Pass a packet to the higher levels. 707 * NO TRAILER PROTOCOL! 708 */ 709 wdread(sc, m) 710 register struct wd_softc *sc; 711 struct mbuf *m; 712 { 713 struct ether_header *eh; 714 int scn, type, s; 715 struct ifqueue *inq; 716 717 /* 718 * Get ethernet protocol type out of ether header 719 */ 720 eh = mtod(m, struct ether_header *); 721 type = ntohs((u_short)eh->ether_type); 722 723 /* 724 * Drop ethernet header 725 */ 726 m->m_off += ETHER_HDR_SIZE; 727 m->m_len -= ETHER_HDR_SIZE; 728 729 /* 730 * Insert ifp pointer at start of packet 731 */ 732 m->m_off -= sizeof (struct ifnet *); 733 m->m_len += sizeof (struct ifnet *); 734 *(mtod(m, struct ifnet **)) = &sc->wd_if; 735 736 switch (type) { 737 738 #ifdef INET 739 case ETHERTYPE_IP: 740 scn = NETISR_IP; 741 inq = &ipintrq; 742 break; 743 744 case ETHERTYPE_ARP: 745 arpinput(&sc->wd_ac, m); 746 return; 747 #endif 748 #ifdef NS 749 case ETHERTYPE_NS: 750 scn = NETISR_NS; 751 inq = &nsintrq; 752 break; 753 754 #endif 755 756 default: 757 m_freem(m); 758 return; 759 } 760 761 s = splimp(); 762 if (IF_QFULL(inq)) { 763 IF_DROP(inq); 764 m_freem(m); 765 } else 766 IF_ENQUEUE(inq, m); 767 schednetisr(scn); 768 (void) splx(s); 769 } 770 771 #endif 772