1 /* 2 * Copyright (c) 1982 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)if_il.c 6.13 (Berkeley) 02/12/86 7 */ 8 9 #include "il.h" 10 #if NIL > 0 11 12 /* 13 * Interlan Ethernet Communications Controller interface 14 */ 15 #include "../machine/pte.h" 16 17 #include "param.h" 18 #include "systm.h" 19 #include "mbuf.h" 20 #include "buf.h" 21 #include "protosw.h" 22 #include "socket.h" 23 #include "vmmac.h" 24 #include "ioctl.h" 25 #include "errno.h" 26 27 #include "../net/if.h" 28 #include "../net/netisr.h" 29 #include "../net/route.h" 30 31 #ifdef INET 32 #include "../netinet/in.h" 33 #include "../netinet/in_systm.h" 34 #include "../netinet/in_var.h" 35 #include "../netinet/ip.h" 36 #include "../netinet/if_ether.h" 37 #endif 38 39 #ifdef NS 40 #include "../netns/ns.h" 41 #include "../netns/ns_if.h" 42 #endif 43 44 #include "../vax/cpu.h" 45 #include "../vax/mtpr.h" 46 #include "if_il.h" 47 #include "if_ilreg.h" 48 #include "if_uba.h" 49 #include "../vaxuba/ubareg.h" 50 #include "../vaxuba/ubavar.h" 51 52 int ilprobe(), ilattach(), ilrint(), ilcint(); 53 struct uba_device *ilinfo[NIL]; 54 u_short ilstd[] = { 0 }; 55 struct uba_driver ildriver = 56 { ilprobe, 0, ilattach, 0, ilstd, "il", ilinfo }; 57 #define ILUNIT(x) minor(x) 58 int ilinit(),iloutput(),ilioctl(),ilreset(),ilwatch(); 59 60 /* 61 * Ethernet software status per interface. 62 * 63 * Each interface is referenced by a network interface structure, 64 * is_if, which the routing code uses to locate the interface. 65 * This structure contains the output queue for the interface, its address, ... 66 * We also have, for each interface, a UBA interface structure, which 67 * contains information about the UNIBUS resources held by the interface: 68 * map registers, buffered data paths, etc. Information is cached in this 69 * structure for use by the if_uba.c routines in running the interface 70 * efficiently. 71 */ 72 struct il_softc { 73 struct arpcom is_ac; /* Ethernet common part */ 74 #define is_if is_ac.ac_if /* network-visible interface */ 75 #define is_addr is_ac.ac_enaddr /* hardware Ethernet address */ 76 struct ifuba is_ifuba; /* UNIBUS resources */ 77 int is_flags; 78 #define ILF_OACTIVE 0x1 /* output is active */ 79 #define ILF_RCVPENDING 0x2 /* start rcv in ilcint */ 80 #define ILF_STATPENDING 0x4 /* stat cmd pending */ 81 #define ILF_RUNNING 0x8 /* board is running */ 82 #define ILF_SETADDR 0x10 /* physical address is changed */ 83 short is_lastcmd; /* can't read csr, so must save it */ 84 short is_scaninterval; /* interval of stat collection */ 85 #define ILWATCHINTERVAL 60 /* once every 60 seconds */ 86 struct il_stats is_stats; /* holds on-board statistics */ 87 struct il_stats is_sum; /* summation over time */ 88 int is_ubaddr; /* mapping registers of is_stats */ 89 } il_softc[NIL]; 90 91 ilprobe(reg) 92 caddr_t reg; 93 { 94 register int br, cvec; /* r11, r10 value-result */ 95 register struct ildevice *addr = (struct ildevice *)reg; 96 register i; 97 98 #ifdef lint 99 br = 0; cvec = br; br = cvec; 100 i = 0; ilrint(i); ilcint(i); ilwatch(i); 101 #endif 102 103 addr->il_csr = ILC_OFFLINE|IL_CIE; 104 DELAY(100000); 105 i = addr->il_csr; /* clear CDONE */ 106 if (cvec > 0 && cvec != 0x200) 107 cvec -= 4; 108 return (1); 109 } 110 111 /* 112 * Interface exists: make available by filling in network interface 113 * record. System will initialize the interface when it is ready 114 * to accept packets. A STATUS command is done to get the ethernet 115 * address and other interesting data. 116 */ 117 ilattach(ui) 118 struct uba_device *ui; 119 { 120 register struct il_softc *is = &il_softc[ui->ui_unit]; 121 register struct ifnet *ifp = &is->is_if; 122 register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 123 124 ifp->if_unit = ui->ui_unit; 125 ifp->if_name = "il"; 126 ifp->if_mtu = ETHERMTU; 127 ifp->if_flags = IFF_BROADCAST; 128 129 /* 130 * Reset the board and map the statistics 131 * buffer onto the Unibus. 132 */ 133 addr->il_csr = ILC_RESET; 134 (void)ilwait(ui, "reset"); 135 136 is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats, 137 sizeof (struct il_stats), 0); 138 addr->il_bar = is->is_ubaddr & 0xffff; 139 addr->il_bcr = sizeof (struct il_stats); 140 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; 141 (void)ilwait(ui, "status"); 142 ubarelse(ui->ui_ubanum, &is->is_ubaddr); 143 #ifdef notdef 144 printf("il%d: module=%s firmware=%s\n", ui->ui_unit, 145 is->is_stats.ils_module, is->is_stats.ils_firmware); 146 #endif 147 bcopy((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 148 sizeof (is->is_addr)); 149 printf("il%d: hardware address %s\n", ui->ui_unit, 150 ether_sprintf(is->is_addr)); 151 ifp->if_init = ilinit; 152 ifp->if_output = iloutput; 153 ifp->if_ioctl = ilioctl; 154 ifp->if_reset = ilreset; 155 is->is_ifuba.ifu_flags = UBA_CANTWAIT; 156 #ifdef notdef 157 is->is_ifuba.ifu_flags |= UBA_NEEDBDP; 158 #endif 159 if_attach(ifp); 160 } 161 162 ilwait(ui, op) 163 struct uba_device *ui; 164 char *op; 165 { 166 register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 167 168 while ((addr->il_csr&IL_CDONE) == 0) 169 ; 170 if (addr->il_csr&IL_STATUS) { 171 printf("il%d: %s failed, csr=%b\n", ui->ui_unit, op, 172 addr->il_csr, IL_BITS); 173 return (-1); 174 } 175 return (0); 176 } 177 178 /* 179 * Reset of interface after UNIBUS reset. 180 * If interface is on specified uba, reset its state. 181 */ 182 ilreset(unit, uban) 183 int unit, uban; 184 { 185 register struct uba_device *ui; 186 187 if (unit >= NIL || (ui = ilinfo[unit]) == 0 || ui->ui_alive == 0 || 188 ui->ui_ubanum != uban) 189 return; 190 printf(" il%d", unit); 191 il_softc[unit].is_if.if_flags &= ~IFF_RUNNING; 192 il_softc[unit].is_flags &= ~ILF_RUNNING; 193 ilinit(unit); 194 } 195 196 /* 197 * Initialization of interface; clear recorded pending 198 * operations, and reinitialize UNIBUS usage. 199 */ 200 ilinit(unit) 201 int unit; 202 { 203 register struct il_softc *is = &il_softc[unit]; 204 register struct uba_device *ui = ilinfo[unit]; 205 register struct ildevice *addr; 206 register struct ifnet *ifp = &is->is_if; 207 int s; 208 209 /* not yet, if address still unknown */ 210 if (ifp->if_addrlist == (struct ifaddr *)0) 211 return; 212 if (is->is_flags & ILF_RUNNING) 213 return; 214 215 if ((ifp->if_flags & IFF_RUNNING) == 0) { 216 if (if_ubainit(&is->is_ifuba, ui->ui_ubanum, 217 sizeof (struct il_rheader), (int)btoc(ETHERMTU)) == 0) { 218 printf("il%d: can't initialize\n", unit); 219 is->is_if.if_flags &= ~IFF_UP; 220 return; 221 } 222 is->is_ubaddr = uballoc(ui->ui_ubanum, (caddr_t)&is->is_stats, 223 sizeof (struct il_stats), 0); 224 } 225 ifp->if_watchdog = ilwatch; 226 is->is_scaninterval = ILWATCHINTERVAL; 227 ifp->if_timer = is->is_scaninterval; 228 addr = (struct ildevice *)ui->ui_addr; 229 230 /* 231 * Turn off source address insertion (it's faster this way), 232 * and set board online. Former doesn't work if board is 233 * already online (happens on ubareset), so we put it offline 234 * first. 235 */ 236 s = splimp(); 237 addr->il_csr = ILC_RESET; 238 if (ilwait(ui, "hardware diag")) { 239 is->is_if.if_flags &= ~IFF_UP; 240 splx(s); 241 return; 242 } 243 addr->il_csr = ILC_CISA; 244 while ((addr->il_csr & IL_CDONE) == 0) 245 ; 246 /* 247 * If we must reprogram this board's physical ethernet 248 * address (as for secondary XNS interfaces), we do so 249 * before putting it on line, and starting receive requests. 250 * If you try this on an older 1010 board, it will total 251 * wedge the board. 252 */ 253 if (is->is_flags & ILF_SETADDR) { 254 bcopy((caddr_t)is->is_addr, (caddr_t)&is->is_stats, 255 sizeof is->is_addr); 256 addr->il_bar = is->is_ubaddr & 0xffff; 257 addr->il_bcr = sizeof is->is_addr; 258 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_LDPA; 259 if (ilwait(ui, "setaddr")) 260 return; 261 addr->il_bar = is->is_ubaddr & 0xffff; 262 addr->il_bcr = sizeof (struct il_stats); 263 addr->il_csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT; 264 if (ilwait(ui, "verifying setaddr")) 265 return; 266 if (bcmp((caddr_t)is->is_stats.ils_addr, (caddr_t)is->is_addr, 267 sizeof (is->is_addr)) != 0) { 268 printf("il%d: setaddr didn't work\n", ui->ui_unit); 269 return; 270 } 271 } 272 /* 273 * Set board online. 274 * Hang receive buffer and start any pending 275 * writes by faking a transmit complete. 276 * Receive bcr is not a multiple of 8 so buffer 277 * chaining can't happen. 278 */ 279 addr->il_csr = ILC_ONLINE; 280 while ((addr->il_csr & IL_CDONE) == 0) 281 ; 282 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 283 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 284 addr->il_csr = 285 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 286 while ((addr->il_csr & IL_CDONE) == 0) 287 ; 288 is->is_flags = ILF_OACTIVE; 289 is->is_if.if_flags |= IFF_RUNNING; 290 is->is_flags |= ILF_RUNNING; 291 is->is_lastcmd = 0; 292 ilcint(unit); 293 splx(s); 294 } 295 296 /* 297 * Start output on interface. 298 * Get another datagram to send off of the interface queue, 299 * and map it to the interface before starting the output. 300 */ 301 ilstart(dev) 302 dev_t dev; 303 { 304 int unit = ILUNIT(dev), len; 305 struct uba_device *ui = ilinfo[unit]; 306 register struct il_softc *is = &il_softc[unit]; 307 register struct ildevice *addr; 308 struct mbuf *m; 309 short csr; 310 311 IF_DEQUEUE(&is->is_if.if_snd, m); 312 addr = (struct ildevice *)ui->ui_addr; 313 if (m == 0) { 314 if ((is->is_flags & ILF_STATPENDING) == 0) 315 return; 316 addr->il_bar = is->is_ubaddr & 0xffff; 317 addr->il_bcr = sizeof (struct il_stats); 318 csr = ((is->is_ubaddr >> 2) & IL_EUA)|ILC_STAT|IL_RIE|IL_CIE; 319 is->is_flags &= ~ILF_STATPENDING; 320 goto startcmd; 321 } 322 len = if_wubaput(&is->is_ifuba, m); 323 /* 324 * Ensure minimum packet length. 325 * This makes the safe assumtion that there are no virtual holes 326 * after the data. 327 * For security, it might be wise to zero out the added bytes, 328 * but we're mainly interested in speed at the moment. 329 */ 330 if (len - sizeof(struct ether_header) < ETHERMIN) 331 len = ETHERMIN + sizeof(struct ether_header); 332 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 333 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_w.ifrw_bdp); 334 addr->il_bar = is->is_ifuba.ifu_w.ifrw_info & 0xffff; 335 addr->il_bcr = len; 336 csr = 337 ((is->is_ifuba.ifu_w.ifrw_info >> 2) & IL_EUA)|ILC_XMIT|IL_CIE|IL_RIE; 338 339 startcmd: 340 is->is_lastcmd = csr & IL_CMD; 341 addr->il_csr = csr; 342 is->is_flags |= ILF_OACTIVE; 343 } 344 345 /* 346 * Command done interrupt. 347 */ 348 ilcint(unit) 349 int unit; 350 { 351 register struct il_softc *is = &il_softc[unit]; 352 struct uba_device *ui = ilinfo[unit]; 353 register struct ildevice *addr = (struct ildevice *)ui->ui_addr; 354 short csr; 355 356 if ((is->is_flags & ILF_OACTIVE) == 0) { 357 printf("il%d: stray xmit interrupt, csr=%b\n", unit, 358 addr->il_csr, IL_BITS); 359 return; 360 } 361 362 csr = addr->il_csr; 363 /* 364 * Hang receive buffer if it couldn't 365 * be done earlier (in ilrint). 366 */ 367 if (is->is_flags & ILF_RCVPENDING) { 368 int s; 369 370 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 371 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 372 addr->il_csr = 373 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 374 s = splhigh(); 375 while ((addr->il_csr & IL_CDONE) == 0) 376 ; 377 splx(s); 378 is->is_flags &= ~ILF_RCVPENDING; 379 } 380 is->is_flags &= ~ILF_OACTIVE; 381 csr &= IL_STATUS; 382 switch (is->is_lastcmd) { 383 384 case ILC_XMIT: 385 is->is_if.if_opackets++; 386 if (csr > ILERR_RETRIES) 387 is->is_if.if_oerrors++; 388 break; 389 390 case ILC_STAT: 391 if (csr == ILERR_SUCCESS) 392 iltotal(is); 393 break; 394 } 395 if (is->is_ifuba.ifu_xtofree) { 396 m_freem(is->is_ifuba.ifu_xtofree); 397 is->is_ifuba.ifu_xtofree = 0; 398 } 399 ilstart(unit); 400 } 401 402 /* 403 * Ethernet interface receiver interrupt. 404 * If input error just drop packet. 405 * Otherwise purge input buffered data path and examine 406 * packet to determine type. If can't determine length 407 * from type, then have to drop packet. Othewise decapsulate 408 * packet based on type and pass to type specific higher-level 409 * input routine. 410 */ 411 ilrint(unit) 412 int unit; 413 { 414 register struct il_softc *is = &il_softc[unit]; 415 struct ildevice *addr = (struct ildevice *)ilinfo[unit]->ui_addr; 416 register struct il_rheader *il; 417 struct mbuf *m; 418 int len, off, resid, s; 419 register struct ifqueue *inq; 420 421 is->is_if.if_ipackets++; 422 if (is->is_ifuba.ifu_flags & UBA_NEEDBDP) 423 UBAPURGE(is->is_ifuba.ifu_uba, is->is_ifuba.ifu_r.ifrw_bdp); 424 il = (struct il_rheader *)(is->is_ifuba.ifu_r.ifrw_addr); 425 len = il->ilr_length - sizeof(struct il_rheader); 426 if ((il->ilr_status&(ILFSTAT_A|ILFSTAT_C)) || len < 46 || 427 len > ETHERMTU) { 428 is->is_if.if_ierrors++; 429 #ifdef notdef 430 if (is->is_if.if_ierrors % 100 == 0) 431 printf("il%d: += 100 input errors\n", unit); 432 #endif 433 goto setup; 434 } 435 436 /* 437 * Deal with trailer protocol: if type is trailer type 438 * get true type from first 16-bit word past data. 439 * Remember that type was trailer by setting off. 440 */ 441 il->ilr_type = ntohs((u_short)il->ilr_type); 442 #define ildataaddr(il, off, type) ((type)(((caddr_t)((il)+1)+(off)))) 443 if (il->ilr_type >= ETHERTYPE_TRAIL && 444 il->ilr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 445 off = (il->ilr_type - ETHERTYPE_TRAIL) * 512; 446 if (off >= ETHERMTU) 447 goto setup; /* sanity */ 448 il->ilr_type = ntohs(*ildataaddr(il, off, u_short *)); 449 resid = ntohs(*(ildataaddr(il, off+2, u_short *))); 450 if (off + resid > len) 451 goto setup; /* sanity */ 452 len = off + resid; 453 } else 454 off = 0; 455 if (len == 0) 456 goto setup; 457 458 /* 459 * Pull packet off interface. Off is nonzero if packet 460 * has trailing header; ilget will then force this header 461 * information to be at the front, but we still have to drop 462 * the type and length which are at the front of any trailer data. 463 */ 464 m = if_rubaget(&is->is_ifuba, len, off, &is->is_if); 465 if (m == 0) 466 goto setup; 467 if (off) { 468 struct ifnet *ifp; 469 470 ifp = *(mtod(m, struct ifnet **)); 471 m->m_off += 2 * sizeof (u_short); 472 m->m_len -= 2 * sizeof (u_short); 473 *(mtod(m, struct ifnet **)) = ifp; 474 } 475 switch (il->ilr_type) { 476 477 #ifdef INET 478 case ETHERTYPE_IP: 479 schednetisr(NETISR_IP); 480 inq = &ipintrq; 481 break; 482 483 case ETHERTYPE_ARP: 484 arpinput(&is->is_ac, m); 485 goto setup; 486 #endif 487 #ifdef NS 488 case ETHERTYPE_NS: 489 schednetisr(NETISR_NS); 490 inq = &nsintrq; 491 break; 492 493 #endif 494 default: 495 m_freem(m); 496 goto setup; 497 } 498 499 s = splimp(); 500 if (IF_QFULL(inq)) { 501 IF_DROP(inq); 502 m_freem(m); 503 } else 504 IF_ENQUEUE(inq, m); 505 splx(s); 506 507 setup: 508 /* 509 * Reset for next packet if possible. 510 * If waiting for transmit command completion, set flag 511 * and wait until command completes. 512 */ 513 if (is->is_flags & ILF_OACTIVE) { 514 is->is_flags |= ILF_RCVPENDING; 515 return; 516 } 517 addr->il_bar = is->is_ifuba.ifu_r.ifrw_info & 0xffff; 518 addr->il_bcr = sizeof(struct il_rheader) + ETHERMTU + 6; 519 addr->il_csr = 520 ((is->is_ifuba.ifu_r.ifrw_info >> 2) & IL_EUA)|ILC_RCV|IL_RIE; 521 s = splhigh(); 522 while ((addr->il_csr & IL_CDONE) == 0) 523 ; 524 splx(s); 525 } 526 527 /* 528 * Ethernet output routine. 529 * Encapsulate a packet of type family for the local net. 530 * Use trailer local net encapsulation if enough data in first 531 * packet leaves a multiple of 512 bytes of data in remainder. 532 */ 533 iloutput(ifp, m0, dst) 534 struct ifnet *ifp; 535 struct mbuf *m0; 536 struct sockaddr *dst; 537 { 538 int type, s, error; 539 u_char edst[6]; 540 struct in_addr idst; 541 register struct il_softc *is = &il_softc[ifp->if_unit]; 542 register struct mbuf *m = m0; 543 register struct ether_header *il; 544 register int off; 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 switch (dst->sa_family) { 552 553 #ifdef INET 554 case AF_INET: 555 idst = ((struct sockaddr_in *)dst)->sin_addr; 556 if (!arpresolve(&is->is_ac, m, &idst, edst, &usetrailers)) 557 return (0); /* if not yet resolved */ 558 off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; 559 if (usetrailers && off > 0 && (off & 0x1ff) == 0 && 560 m->m_off >= MMINOFF + 2 * sizeof (u_short)) { 561 type = ETHERTYPE_TRAIL + (off>>9); 562 m->m_off -= 2 * sizeof (u_short); 563 m->m_len += 2 * sizeof (u_short); 564 *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); 565 *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); 566 goto gottrailertype; 567 } 568 type = ETHERTYPE_IP; 569 off = 0; 570 goto gottype; 571 #endif 572 #ifdef NS 573 case AF_NS: 574 type = ETHERTYPE_NS; 575 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 576 (caddr_t)edst, sizeof (edst)); 577 off = 0; 578 goto gottype; 579 #endif 580 581 case AF_UNSPEC: 582 il = (struct ether_header *)dst->sa_data; 583 bcopy((caddr_t)il->ether_dhost, (caddr_t)edst, sizeof (edst)); 584 type = il->ether_type; 585 goto gottype; 586 587 default: 588 printf("il%d: can't handle af%d\n", ifp->if_unit, 589 dst->sa_family); 590 error = EAFNOSUPPORT; 591 goto bad; 592 } 593 594 gottrailertype: 595 /* 596 * Packet to be sent as trailer: move first packet 597 * (control information) to end of chain. 598 */ 599 while (m->m_next) 600 m = m->m_next; 601 m->m_next = m0; 602 m = m0->m_next; 603 m0->m_next = 0; 604 m0 = m; 605 606 gottype: 607 /* 608 * Add local net header. If no space in first mbuf, 609 * allocate another. 610 */ 611 if (m->m_off > MMAXOFF || 612 MMINOFF + sizeof (struct ether_header) > m->m_off) { 613 m = m_get(M_DONTWAIT, MT_HEADER); 614 if (m == 0) { 615 error = ENOBUFS; 616 goto bad; 617 } 618 m->m_next = m0; 619 m->m_off = MMINOFF; 620 m->m_len = sizeof (struct ether_header); 621 } else { 622 m->m_off -= sizeof (struct ether_header); 623 m->m_len += sizeof (struct ether_header); 624 } 625 il = mtod(m, struct ether_header *); 626 il->ether_type = htons((u_short)type); 627 bcopy((caddr_t)edst, (caddr_t)il->ether_dhost, sizeof (edst)); 628 bcopy((caddr_t)is->is_addr, (caddr_t)il->ether_shost, 629 sizeof(il->ether_shost)); 630 631 /* 632 * Queue message on interface, and start output if interface 633 * not yet active. 634 */ 635 s = splimp(); 636 if (IF_QFULL(&ifp->if_snd)) { 637 IF_DROP(&ifp->if_snd); 638 splx(s); 639 m_freem(m); 640 return (ENOBUFS); 641 } 642 IF_ENQUEUE(&ifp->if_snd, m); 643 if ((is->is_flags & ILF_OACTIVE) == 0) 644 ilstart(ifp->if_unit); 645 splx(s); 646 return (0); 647 648 bad: 649 m_freem(m0); 650 return (error); 651 } 652 653 /* 654 * Watchdog routine, request statistics from board. 655 */ 656 ilwatch(unit) 657 int unit; 658 { 659 register struct il_softc *is = &il_softc[unit]; 660 register struct ifnet *ifp = &is->is_if; 661 int s; 662 663 if (is->is_flags & ILF_STATPENDING) { 664 ifp->if_timer = is->is_scaninterval; 665 return; 666 } 667 s = splimp(); 668 is->is_flags |= ILF_STATPENDING; 669 if ((is->is_flags & ILF_OACTIVE) == 0) 670 ilstart(ifp->if_unit); 671 splx(s); 672 ifp->if_timer = is->is_scaninterval; 673 } 674 675 /* 676 * Total up the on-board statistics. 677 */ 678 iltotal(is) 679 register struct il_softc *is; 680 { 681 register u_short *interval, *sum, *end; 682 683 interval = &is->is_stats.ils_frames; 684 sum = &is->is_sum.ils_frames; 685 end = is->is_sum.ils_fill2; 686 while (sum < end) 687 *sum++ += *interval++; 688 is->is_if.if_collisions = is->is_sum.ils_collis; 689 } 690 691 /* 692 * Process an ioctl request. 693 */ 694 ilioctl(ifp, cmd, data) 695 register struct ifnet *ifp; 696 int cmd; 697 caddr_t data; 698 { 699 register struct ifaddr *ifa = (struct ifaddr *)data; 700 register struct il_softc *is = &il_softc[ifp->if_unit]; 701 int s = splimp(), error = 0; 702 703 switch (cmd) { 704 705 case SIOCSIFADDR: 706 ifp->if_flags |= IFF_UP; 707 ilinit(ifp->if_unit); 708 709 switch (ifa->ifa_addr.sa_family) { 710 #ifdef INET 711 case AF_INET: 712 ((struct arpcom *)ifp)->ac_ipaddr = 713 IA_SIN(ifa)->sin_addr; 714 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 715 break; 716 #endif 717 #ifdef NS 718 case AF_NS: 719 { 720 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 721 722 if (ns_nullhost(*ina)) { 723 ina->x_host = * (union ns_host *) 724 (il_softc[ifp->if_unit].is_addr); 725 } else { 726 il_setaddr(ina->x_host.c_host, ifp->if_unit); 727 return (0); 728 } 729 break; 730 } 731 #endif 732 } 733 break; 734 735 case SIOCSIFFLAGS: 736 if ((ifp->if_flags & IFF_UP) == 0 && 737 is->is_flags & ILF_RUNNING) { 738 ((struct ildevice *) 739 (ilinfo[ifp->if_unit]->ui_addr))->il_csr = ILC_RESET; 740 is->is_flags &= ~ILF_RUNNING; 741 } else if (ifp->if_flags & IFF_UP && 742 (is->is_flags & ILF_RUNNING) == 0) 743 ilinit(ifp->if_unit); 744 break; 745 746 default: 747 error = EINVAL; 748 } 749 splx(s); 750 return (error); 751 } 752 753 /* 754 * set ethernet address for unit 755 */ 756 il_setaddr(physaddr, unit) 757 u_char *physaddr; 758 int unit; 759 { 760 register struct il_softc *is = &il_softc[unit]; 761 762 if (! (is->is_flags & ILF_RUNNING)) 763 return; 764 765 bcopy((caddr_t)physaddr, (caddr_t)is->is_addr, sizeof is->is_addr); 766 is->is_flags &= ~ILF_RUNNING; 767 is->is_flags |= ILF_SETADDR; 768 ilinit(unit); 769 } 770 #endif 771