1 /* 2 * Copyright (c) 1982, 1990 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * from: @(#)if_le.c 7.6 (Berkeley) 5/8/91 34 * $Id: if_le.c,v 1.2 1993/10/30 23:41:14 mw Exp $ 35 */ 36 37 #include "le.h" 38 #if NLE > 0 39 40 #include "bpfilter.h" 41 42 /* 43 * AMD 7990 LANCE 44 * 45 * This driver will generate and accept tailer encapsulated packets even 46 * though it buys us nothing. The motivation was to avoid incompatibilities 47 * with VAXen, SUNs, and others that handle and benefit from them. 48 * This reasoning is dubious. 49 */ 50 #include "sys/param.h" 51 #include "sys/systm.h" 52 #include "sys/mbuf.h" 53 #include "sys/buf.h" 54 #include "sys/protosw.h" 55 #include "sys/socket.h" 56 #include "sys/syslog.h" 57 #include "sys/ioctl.h" 58 #include "sys/errno.h" 59 60 #include "net/if.h" 61 #include "net/netisr.h" 62 #include "net/route.h" 63 64 #ifdef INET 65 #include "netinet/in.h" 66 #include "netinet/in_systm.h" 67 #include "netinet/in_var.h" 68 #include "netinet/ip.h" 69 #include "netinet/if_ether.h" 70 #endif 71 72 #ifdef NS 73 #include "netns/ns.h" 74 #include "netns/ns_if.h" 75 #endif 76 77 #ifdef RMP 78 #include "netrmp/rmp.h" 79 #include "netrmp/rmp_var.h" 80 #endif 81 82 #include "../include/cpu.h" 83 #include "../include/mtpr.h" 84 #include "device.h" 85 #include "if_lereg.h" 86 87 #if NBPFILTER > 0 88 #include "../net/bpf.h" 89 #include "../net/bpfdesc.h" 90 #endif 91 92 #if 0 93 /* offsets for: ID, REGS, MEM, NVRAM */ 94 int lestd[] = { 0, 0x4000, 0x8000, 0xC008 }; 95 #else 96 /* offsets for: ID, REGS, MEM */ 97 int lestd[] = { 0, 0x4000, 0x8000 }; 98 #endif 99 100 int leattach(); 101 struct driver ledriver = { 102 leattach, "le", 103 }; 104 105 #if 0 106 struct isr le_isr[NLE]; 107 #endif 108 int ledebug = 0; /* console error messages */ 109 110 int leintr(), leinit(), leioctl(), lestart(), ether_output(); 111 struct mbuf *leget(); 112 extern struct ifnet loif; 113 114 /* 115 * Ethernet software status per interface. 116 * 117 * Each interface is referenced by a network interface structure, 118 * le_if, which the routing code uses to locate the interface. 119 * This structure contains the output queue for the interface, its address, ... 120 */ 121 struct le_softc { 122 struct arpcom sc_ac; /* common Ethernet structures */ 123 #define sc_if sc_ac.ac_if /* network-visible interface */ 124 #define sc_addr sc_ac.ac_enaddr /* hardware Ethernet address */ 125 void *sc_base; /* base address of board */ 126 struct lereg1 *sc_r1; /* LANCE registers */ 127 struct lereg2 *sc_r2; /* dual-port RAM */ 128 int sc_rmd; /* predicted next rmd to process */ 129 int sc_runt; 130 int sc_jab; 131 int sc_merr; 132 int sc_babl; 133 int sc_cerr; 134 int sc_miss; 135 int sc_xint; 136 int sc_xown; 137 int sc_uflo; 138 int sc_rxlen; 139 int sc_rxoff; 140 int sc_txoff; 141 int sc_busy; 142 short sc_iflags; 143 #if NBPFILTER > 0 144 caddr_t sc_bpf; 145 #endif 146 } le_softc[NLE]; 147 148 149 /* 150 * Interface exists: make available by filling in network interface 151 * record. System will initialize the interface when it is ready 152 * to accept packets. 153 */ 154 leattach(ad) 155 struct amiga_device *ad; 156 { 157 register struct lereg0 *ler0; 158 register struct lereg2 *ler2; 159 struct lereg2 *lemem = (struct lereg2 *) 0x8000; 160 struct le_softc *le = &le_softc[ad->amiga_unit]; 161 struct ifnet *ifp = &le->sc_if; 162 char *cp; 163 int i; 164 unsigned long ser; 165 int s = splhigh (); 166 167 ler0 = le->sc_base = ad->amiga_addr; 168 le->sc_r1 = (struct lereg1 *)(lestd[1] + (int)ad->amiga_addr); 169 ler2 = le->sc_r2 = (struct lereg2 *)(lestd[2] + (int)ad->amiga_addr); 170 171 #if 0 172 if (ler0->ler0_id == 0xff) 173 goto noreset; 174 if (ler0->ler0_id != LEID) 175 { 176 le->sc_base = 0; 177 splx (s); 178 printf ("le%d: ler0_id[%d] != LEID[%d], board ignored.\n", 179 ad->amiga_unit, ler0->ler0_id, LEID); 180 return(0); 181 } 182 le_isr[ad->amiga_unit].isr_intr = leintr; 183 ad->amiga_ipl = le_isr[ad->amiga_unit].isr_ipl = LE_IPL(ler0->ler0_status); 184 le_isr[ad->amiga_unit].isr_arg = ad->amiga_unit; 185 ler0->ler0_id = 0xFF; 186 DELAY(100); 187 noreset: 188 189 /* 190 * Read the ethernet address off the board, one nibble at a time. 191 */ 192 cp = (char *)(lestd[3] + (int)ad->amiga_addr); 193 for (i = 0; i < sizeof(le->sc_addr); i++) { 194 le->sc_addr[i] = (*++cp & 0xF) << 4; 195 cp++; 196 le->sc_addr[i] |= *++cp & 0xF; 197 cp++; 198 } 199 #else 200 /* serial number contains this information. Manufacturer decides 201 the 3 first bytes. */ 202 ser = (unsigned long) ad->amiga_serno; 203 if ((ser >> 24) == 1) 204 { 205 /* Commodore */ 206 le->sc_addr[0] = 0x00; 207 le->sc_addr[1] = 0x80; 208 le->sc_addr[2] = 0x10; 209 } 210 else if ((ser >> 24) == 2) 211 { 212 le->sc_addr[0] = 0x00; 213 le->sc_addr[1] = 0x00; 214 le->sc_addr[2] = 0x9f; 215 } 216 le->sc_addr[3] = (ser >> 16) & 0xff; 217 le->sc_addr[4] = (ser >> 8) & 0xff; 218 le->sc_addr[5] = (ser ) & 0xff; 219 #endif 220 printf("le%d: hardware address %s\n", ad->amiga_unit, 221 ether_sprintf(le->sc_addr)); 222 223 /* 224 * Setup for transmit/receive 225 */ 226 ler2->ler2_mode = LE_MODE; 227 ler2->ler2_padr[0] = le->sc_addr[1]; 228 ler2->ler2_padr[1] = le->sc_addr[0]; 229 ler2->ler2_padr[2] = le->sc_addr[3]; 230 ler2->ler2_padr[3] = le->sc_addr[2]; 231 ler2->ler2_padr[4] = le->sc_addr[5]; 232 ler2->ler2_padr[5] = le->sc_addr[4]; 233 #ifdef RMP 234 /* 235 * Set up logical addr filter to accept multicast 9:0:9:0:0:4 236 * This should be an ioctl() to the driver. (XXX) 237 */ 238 ler2->ler2_ladrf0 = 0x00100000; 239 ler2->ler2_ladrf1 = 0x0; 240 #else 241 ler2->ler2_ladrf0 = 0; 242 ler2->ler2_ladrf1 = 0; 243 #endif 244 ler2->ler2_rlen = LE_RLEN; 245 ler2->ler2_rdra = (int)lemem->ler2_rmd; 246 ler2->ler2_tlen = LE_TLEN; 247 ler2->ler2_tdra = (int)lemem->ler2_tmd; 248 #if 0 249 isrlink(&le_isr[ad->amiga_unit]); 250 #endif 251 splx (s); 252 253 ifp->if_unit = ad->amiga_unit; 254 ifp->if_name = "le"; 255 ifp->if_mtu = ETHERMTU; 256 ifp->if_init = leinit; 257 ifp->if_ioctl = leioctl; 258 ifp->if_output = ether_output; 259 ifp->if_start = lestart; 260 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX; 261 #if NBPFILTER > 0 262 bpfattach(&le->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); 263 #endif 264 if_attach(ifp); 265 return (1); 266 } 267 268 ledrinit(ler2) 269 register struct lereg2 *ler2; 270 { 271 register struct lereg2 *lemem = (struct lereg2 *) 0x8000; 272 register int i; 273 274 for (i = 0; i < LERBUF; i++) { 275 ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i]; 276 ler2->ler2_rmd[i].rmd1 = LE_OWN; 277 ler2->ler2_rmd[i].rmd2 = -LEMTU; 278 ler2->ler2_rmd[i].rmd3 = 0; 279 } 280 for (i = 0; i < LETBUF; i++) { 281 ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i]; 282 ler2->ler2_tmd[i].tmd1 = 0; 283 ler2->ler2_tmd[i].tmd2 = 0; 284 ler2->ler2_tmd[i].tmd3 = 0; 285 } 286 } 287 288 lereset(unit) 289 register int unit; 290 { 291 register struct le_softc *le = &le_softc[unit]; 292 register struct lereg1 *ler1 = le->sc_r1; 293 register struct lereg2 *lemem = (struct lereg2 *) 0x8000; 294 register int timo = 100000; 295 register int stat; 296 297 #ifdef lint 298 stat = unit; 299 #endif 300 #if NBPFILTER > 0 301 if (le->sc_if.if_flags & IFF_PROMISC) 302 /* set the promiscuous bit */ 303 le->sc_r2->ler2_mode = LE_MODE|0x8000; 304 else 305 le->sc_r2->ler2_mode = LE_MODE; 306 #endif 307 ler1->ler1_rap = LE_CSR0; 308 ler1->ler1_rdp = LE_STOP; 309 ledrinit(le->sc_r2); 310 le->sc_rmd = 0; 311 ler1->ler1_rap = LE_CSR1; 312 ler1->ler1_rdp = (int)&lemem->ler2_mode; 313 ler1->ler1_rap = LE_CSR2; 314 ler1->ler1_rdp = 0; 315 ler1->ler1_rap = LE_CSR0; 316 ler1->ler1_rdp = LE_INIT; 317 do { 318 if (--timo == 0) { 319 printf("le%d: init timeout, stat = 0x%x\n", 320 unit, stat); 321 break; 322 } 323 stat = ler1->ler1_rdp; 324 } while ((stat & LE_IDON) == 0); 325 ler1->ler1_rdp = LE_STOP; 326 ler1->ler1_rap = LE_CSR3; 327 ler1->ler1_rdp = LE_BSWP; 328 ler1->ler1_rap = LE_CSR0; 329 ler1->ler1_rdp = LE_STRT | LE_INEA; 330 le->sc_if.if_flags &= ~IFF_OACTIVE; 331 } 332 333 /* 334 * Initialization of interface 335 */ 336 leinit(unit) 337 int unit; 338 { 339 struct le_softc *le = &le_softc[unit]; 340 register struct ifnet *ifp = &le->sc_if; 341 int s; 342 343 /* not yet, if address still unknown */ 344 if (ifp->if_addrlist == (struct ifaddr *)0) 345 return; 346 if ((ifp->if_flags & IFF_RUNNING) == 0) { 347 s = splimp(); 348 ifp->if_flags |= IFF_RUNNING; 349 lereset(unit); 350 (void) lestart(ifp); 351 splx(s); 352 } 353 } 354 355 /* 356 * Start output on interface. Get another datagram to send 357 * off of the interface queue, and copy it to the interface 358 * before starting the output. 359 */ 360 lestart(ifp) 361 struct ifnet *ifp; 362 { 363 register struct le_softc *le = &le_softc[ifp->if_unit]; 364 register struct letmd *tmd; 365 register struct mbuf *m; 366 int len; 367 368 if ((le->sc_if.if_flags & IFF_RUNNING) == 0) 369 return (0); 370 IF_DEQUEUE(&le->sc_if.if_snd, m); 371 if (m == 0) 372 return (0); 373 len = leput(le->sc_r2->ler2_tbuf[0], m); 374 #if NBPFILTER > 0 375 /* 376 * If bpf is listening on this interface, let it 377 * see the packet before we commit it to the wire. 378 */ 379 if (le->sc_bpf) 380 bpf_tap(le->sc_bpf, le->sc_r2->ler2_tbuf[0], len); 381 #endif 382 tmd = le->sc_r2->ler2_tmd; 383 tmd->tmd3 = 0; 384 tmd->tmd2 = -len; 385 tmd->tmd1 = LE_OWN | LE_STP | LE_ENP; 386 le->sc_if.if_flags |= IFF_OACTIVE; 387 return (0); 388 } 389 390 leintr(unit) 391 register int unit; 392 { 393 register struct le_softc *le = &le_softc[unit]; 394 register struct lereg1 *ler1; 395 register int stat; 396 397 /* if not even initialized, don't do anything further.. */ 398 if (! le->sc_base) 399 return 0; 400 401 ler1 = le->sc_r1; 402 stat = ler1->ler1_rdp; 403 404 if (! (stat & LE_INTR)) 405 return 0; 406 407 if (stat & LE_SERR) { 408 leerror(unit, stat); 409 if (stat & LE_MERR) { 410 le->sc_merr++; 411 lereset(unit); 412 return(1); 413 } 414 if (stat & LE_BABL) 415 le->sc_babl++; 416 if (stat & LE_CERR) 417 le->sc_cerr++; 418 if (stat & LE_MISS) 419 le->sc_miss++; 420 ler1->ler1_rdp = LE_BABL|LE_CERR|LE_MISS|LE_INEA; 421 } 422 if ((stat & LE_RXON) == 0) { 423 le->sc_rxoff++; 424 lereset(unit); 425 return(1); 426 } 427 if ((stat & LE_TXON) == 0) { 428 le->sc_txoff++; 429 lereset(unit); 430 return(1); 431 } 432 if (stat & LE_RINT) { 433 /* interrupt is cleared in lerint */ 434 lerint(unit); 435 } 436 if (stat & LE_TINT) { 437 ler1->ler1_rdp = LE_TINT|LE_INEA; 438 lexint(unit); 439 } 440 return(1); 441 } 442 443 /* 444 * Ethernet interface transmitter interrupt. 445 * Start another output if more data to send. 446 */ 447 lexint(unit) 448 register int unit; 449 { 450 register struct le_softc *le = &le_softc[unit]; 451 register struct letmd *tmd = le->sc_r2->ler2_tmd; 452 453 if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) { 454 le->sc_xint++; 455 return; 456 } 457 if (tmd->tmd1 & LE_OWN) { 458 le->sc_xown++; 459 return; 460 } 461 if (tmd->tmd1 & LE_ERR) { 462 err: 463 lexerror(unit); 464 le->sc_if.if_oerrors++; 465 if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) { 466 le->sc_uflo++; 467 lereset(unit); 468 } 469 else if (tmd->tmd3 & LE_LCOL) 470 le->sc_if.if_collisions++; 471 else if (tmd->tmd3 & LE_RTRY) 472 le->sc_if.if_collisions += 16; 473 } 474 else if (tmd->tmd3 & LE_TBUFF) 475 /* XXX documentation says BUFF not included in ERR */ 476 goto err; 477 else if (tmd->tmd1 & LE_ONE) 478 le->sc_if.if_collisions++; 479 else if (tmd->tmd1 & LE_MORE) 480 /* what is the real number? */ 481 le->sc_if.if_collisions += 2; 482 else 483 le->sc_if.if_opackets++; 484 le->sc_if.if_flags &= ~IFF_OACTIVE; 485 (void) lestart(&le->sc_if); 486 } 487 488 #define LENEXTRMP \ 489 if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd 490 491 /* 492 * Ethernet interface receiver interrupt. 493 * If input error just drop packet. 494 * Decapsulate packet based on type and pass to type specific 495 * higher-level input routine. 496 */ 497 lerint(unit) 498 int unit; 499 { 500 register struct le_softc *le = &le_softc[unit]; 501 register int bix = le->sc_rmd; 502 register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix]; 503 504 /* 505 * Out of sync with hardware, should never happen? 506 */ 507 if (rmd->rmd1 & LE_OWN) { 508 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA; 509 return; 510 } 511 512 /* 513 * Process all buffers with valid data 514 */ 515 while ((rmd->rmd1 & LE_OWN) == 0) { 516 int len = rmd->rmd3; 517 518 /* Clear interrupt to avoid race condition */ 519 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA; 520 521 if (rmd->rmd1 & LE_ERR) { 522 le->sc_rmd = bix; 523 lererror(unit, "bad packet"); 524 le->sc_if.if_ierrors++; 525 } else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) { 526 /* 527 * Find the end of the packet so we can see how long 528 * it was. We still throw it away. 529 */ 530 do { 531 le->sc_r1->ler1_rdp = LE_RINT|LE_INEA; 532 rmd->rmd3 = 0; 533 rmd->rmd1 = LE_OWN; 534 LENEXTRMP; 535 } while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP))); 536 le->sc_rmd = bix; 537 lererror(unit, "chained buffer"); 538 le->sc_rxlen++; 539 /* 540 * If search terminated without successful completion 541 * we reset the hardware (conservative). 542 */ 543 if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) != 544 LE_ENP) { 545 lereset(unit); 546 return; 547 } 548 } else 549 leread(unit, le->sc_r2->ler2_rbuf[bix], len); 550 rmd->rmd3 = 0; 551 rmd->rmd1 = LE_OWN; 552 LENEXTRMP; 553 } 554 le->sc_rmd = bix; 555 } 556 557 leread(unit, buf, len) 558 int unit; 559 char *buf; 560 int len; 561 { 562 register struct le_softc *le = &le_softc[unit]; 563 register struct ether_header *et; 564 struct mbuf *m; 565 int off, resid; 566 567 le->sc_if.if_ipackets++; 568 et = (struct ether_header *)buf; 569 et->ether_type = ntohs((u_short)et->ether_type); 570 /* adjust input length to account for header and CRC */ 571 len = len - sizeof(struct ether_header) - 4; 572 573 #ifdef RMP 574 /* (XXX) 575 * 576 * If Ethernet Type field is < MaxPacketSize, we probably have 577 * a IEEE802 packet here. Make sure that the size is at least 578 * that of the HP LLC. Also do sanity checks on length of LLC 579 * (old Ethernet Type field) and packet length. 580 * 581 * Provided the above checks succeed, change `len' to reflect 582 * the length of the LLC (i.e. et->ether_type) and change the 583 * type field to ETHERTYPE_IEEE so we can switch() on it later. 584 * Yes, this is a hack and will eventually be done "right". 585 */ 586 if (et->ether_type <= IEEE802LEN_MAX && len >= sizeof(struct amiga_llc) && 587 len >= et->ether_type && len >= IEEE802LEN_MIN) { 588 len = et->ether_type; 589 et->ether_type = ETHERTYPE_IEEE; /* hack! */ 590 } 591 #endif 592 593 #define ledataaddr(et, off, type) ((type)(((caddr_t)((et)+1)+(off)))) 594 if (et->ether_type >= ETHERTYPE_TRAIL && 595 et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { 596 off = (et->ether_type - ETHERTYPE_TRAIL) * 512; 597 if (off >= ETHERMTU) 598 return; /* sanity */ 599 et->ether_type = ntohs(*ledataaddr(et, off, u_short *)); 600 resid = ntohs(*(ledataaddr(et, off+2, u_short *))); 601 if (off + resid > len) 602 return; /* sanity */ 603 len = off + resid; 604 } else 605 off = 0; 606 607 if (len <= 0) { 608 if (ledebug) 609 log(LOG_WARNING, 610 "le%d: ierror(runt packet): from %s: len=%d\n", 611 unit, ether_sprintf(et->ether_shost), len); 612 le->sc_runt++; 613 le->sc_if.if_ierrors++; 614 return; 615 } 616 #if NBPFILTER > 0 617 /* 618 * Check if there's a bpf filter listening on this interface. 619 * If so, hand off the raw packet to bpf, which must deal with 620 * trailers in its own way. 621 */ 622 if (le->sc_bpf) { 623 bpf_tap(le->sc_bpf, buf, len + sizeof(struct ether_header)); 624 625 /* 626 * Note that the interface cannot be in promiscuous mode if 627 * there are no bpf listeners. And if we are in promiscuous 628 * mode, we have to check if this packet is really ours. 629 * 630 * XXX This test does not support multicasts. 631 */ 632 if ((le->sc_if.if_flags & IFF_PROMISC) 633 && bcmp(et->ether_dhost, le->sc_addr, 634 sizeof(et->ether_dhost)) != 0 635 && bcmp(et->ether_dhost, etherbroadcastaddr, 636 sizeof(et->ether_dhost)) != 0) 637 return; 638 } 639 #endif 640 /* 641 * Pull packet off interface. Off is nonzero if packet 642 * has trailing header; leget will then force this header 643 * information to be at the front, but we still have to drop 644 * the type and length which are at the front of any trailer data. 645 */ 646 m = leget(buf, len, off, &le->sc_if); 647 if (m == 0) 648 return; 649 #ifdef RMP 650 /* 651 * (XXX) 652 * This needs to be integrated with the ISO stuff in ether_input() 653 */ 654 if (et->ether_type == ETHERTYPE_IEEE) { 655 /* 656 * Snag the Logical Link Control header (IEEE 802.2). 657 */ 658 struct amiga_llc *llc = &(mtod(m, struct rmp_packet *)->amiga_llc); 659 660 /* 661 * If the DSAP (and HP's extended DXSAP) indicate this 662 * is an RMP packet, hand it to the raw input routine. 663 */ 664 if (llc->dsap == IEEE_DSAP_HP && llc->dxsap == HPEXT_DXSAP) { 665 static struct sockproto rmp_sp = {AF_RMP,RMPPROTO_BOOT}; 666 static struct sockaddr rmp_src = {AF_RMP}; 667 static struct sockaddr rmp_dst = {AF_RMP}; 668 669 bcopy(et->ether_shost, rmp_src.sa_data, 670 sizeof(et->ether_shost)); 671 bcopy(et->ether_dhost, rmp_dst.sa_data, 672 sizeof(et->ether_dhost)); 673 674 raw_input(m, &rmp_sp, &rmp_src, &rmp_dst); 675 return; 676 } 677 } 678 #endif 679 ether_input(&le->sc_if, et, m); 680 } 681 682 /* 683 * Routine to copy from mbuf chain to transmit 684 * buffer in board local memory. 685 */ 686 leput(lebuf, m) 687 register char *lebuf; 688 register struct mbuf *m; 689 { 690 register struct mbuf *mp; 691 register int len, tlen = 0; 692 693 for (mp = m; mp; mp = mp->m_next) { 694 len = mp->m_len; 695 if (len == 0) 696 continue; 697 tlen += len; 698 bcopy(mtod(mp, char *), lebuf, len); 699 lebuf += len; 700 } 701 m_freem(m); 702 if (tlen < LEMINSIZE) { 703 bzero(lebuf, LEMINSIZE - tlen); 704 tlen = LEMINSIZE; 705 } 706 return(tlen); 707 } 708 709 /* 710 * Routine to copy from board local memory into mbufs. 711 */ 712 struct mbuf * 713 leget(lebuf, totlen, off0, ifp) 714 char *lebuf; 715 int totlen, off0; 716 struct ifnet *ifp; 717 { 718 register struct mbuf *m; 719 struct mbuf *top = 0, **mp = ⊤ 720 register int off = off0, len; 721 register char *cp; 722 char *epkt; 723 724 lebuf += sizeof (struct ether_header); 725 cp = lebuf; 726 epkt = cp + totlen; 727 if (off) { 728 cp += off + 2 * sizeof(u_short); 729 totlen -= 2 * sizeof(u_short); 730 } 731 732 MGETHDR(m, M_DONTWAIT, MT_DATA); 733 if (m == 0) 734 return (0); 735 m->m_pkthdr.rcvif = ifp; 736 m->m_pkthdr.len = totlen; 737 m->m_len = MHLEN; 738 739 while (totlen > 0) { 740 if (top) { 741 MGET(m, M_DONTWAIT, MT_DATA); 742 if (m == 0) { 743 m_freem(top); 744 return (0); 745 } 746 m->m_len = MLEN; 747 } 748 len = min(totlen, epkt - cp); 749 if (len >= MINCLSIZE) { 750 MCLGET(m, M_DONTWAIT); 751 if (m->m_flags & M_EXT) 752 m->m_len = len = min(len, MCLBYTES); 753 else 754 len = m->m_len; 755 } else { 756 /* 757 * Place initial small packet/header at end of mbuf. 758 */ 759 if (len < m->m_len) { 760 if (top == 0 && len + max_linkhdr <= m->m_len) 761 m->m_data += max_linkhdr; 762 m->m_len = len; 763 } else 764 len = m->m_len; 765 } 766 bcopy(cp, mtod(m, caddr_t), (unsigned)len); 767 cp += len; 768 *mp = m; 769 mp = &m->m_next; 770 totlen -= len; 771 if (cp == epkt) 772 cp = lebuf; 773 } 774 return (top); 775 } 776 777 /* 778 * Process an ioctl request. 779 */ 780 leioctl(ifp, cmd, data) 781 register struct ifnet *ifp; 782 int cmd; 783 caddr_t data; 784 { 785 register struct ifaddr *ifa = (struct ifaddr *)data; 786 struct le_softc *le = &le_softc[ifp->if_unit]; 787 struct lereg1 *ler1 = le->sc_r1; 788 int s = splimp(), error = 0; 789 790 switch (cmd) { 791 792 case SIOCSIFADDR: 793 ifp->if_flags |= IFF_UP; 794 switch (ifa->ifa_addr->sa_family) { 795 #ifdef INET 796 case AF_INET: 797 leinit(ifp->if_unit); /* before arpwhohas */ 798 ((struct arpcom *)ifp)->ac_ipaddr = 799 IA_SIN(ifa)->sin_addr; 800 arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); 801 break; 802 #endif 803 #ifdef NS 804 case AF_NS: 805 { 806 register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); 807 808 if (ns_nullhost(*ina)) 809 ina->x_host = *(union ns_host *)(le->sc_addr); 810 else { 811 /* 812 * The manual says we can't change the address 813 * while the receiver is armed, 814 * so reset everything 815 */ 816 ifp->if_flags &= ~IFF_RUNNING; 817 bcopy((caddr_t)ina->x_host.c_host, 818 (caddr_t)le->sc_addr, sizeof(le->sc_addr)); 819 } 820 leinit(ifp->if_unit); /* does le_setaddr() */ 821 break; 822 } 823 #endif 824 default: 825 leinit(ifp->if_unit); 826 break; 827 } 828 break; 829 830 case SIOCSIFFLAGS: 831 if ((ifp->if_flags & IFF_UP) == 0 && 832 ifp->if_flags & IFF_RUNNING) { 833 ler1->ler1_rdp = LE_STOP; 834 ifp->if_flags &= ~IFF_RUNNING; 835 } else if (ifp->if_flags & IFF_UP && 836 (ifp->if_flags & IFF_RUNNING) == 0) 837 leinit(ifp->if_unit); 838 /* 839 * If the state of the promiscuous bit changes, the interface 840 * must be reset to effect the change. 841 */ 842 if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) && 843 (ifp->if_flags & IFF_RUNNING)) { 844 le->sc_iflags = ifp->if_flags; 845 lereset(ifp->if_unit); 846 lestart(ifp); 847 } 848 break; 849 850 default: 851 error = EINVAL; 852 } 853 splx(s); 854 return (error); 855 } 856 857 leerror(unit, stat) 858 int unit; 859 int stat; 860 { 861 if (!ledebug) 862 return; 863 864 /* 865 * Not all transceivers implement heartbeat 866 * so we only log CERR once. 867 */ 868 if ((stat & LE_CERR) && le_softc[unit].sc_cerr) 869 return; 870 log(LOG_WARNING, 871 "le%d: error: stat=%b\n", unit, 872 stat, 873 "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT"); 874 } 875 876 lererror(unit, msg) 877 int unit; 878 char *msg; 879 { 880 register struct le_softc *le = &le_softc[unit]; 881 register struct lermd *rmd; 882 int len; 883 884 if (!ledebug) 885 return; 886 887 rmd = &le->sc_r2->ler2_rmd[le->sc_rmd]; 888 len = rmd->rmd3; 889 log(LOG_WARNING, 890 "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n", 891 unit, msg, 892 len > 11 ? ether_sprintf(&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) : "unknown", 893 le->sc_rmd, len, 894 rmd->rmd1, 895 "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP"); 896 } 897 898 lexerror(unit) 899 int unit; 900 { 901 register struct le_softc *le = &le_softc[unit]; 902 register struct letmd *tmd; 903 int len; 904 905 if (!ledebug) 906 return; 907 908 tmd = le->sc_r2->ler2_tmd; 909 len = -tmd->tmd2; 910 log(LOG_WARNING, 911 "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n", 912 unit, 913 len > 5 ? ether_sprintf(&le->sc_r2->ler2_tbuf[0][0]) : "unknown", 914 0, len, 915 tmd->tmd1, 916 "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP", 917 tmd->tmd3, 918 "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY"); 919 } 920 #endif 921