Home | History | Annotate | Line # | Download | only in isa
if_el.c revision 1.2
      1 /*
      2  * Copyright (c) 1994, Matthew E. Kimmel.  Permission is hereby granted
      3  * to use, copy, modify and distribute this software provided that both
      4  * the copyright notice and this permission notice appear in all copies
      5  * of the software, derivative works or modified versions, and any
      6  * portions thereof.
      7  */
      8 
      9 /*
     10  * 3COM Etherlink 3C501 device driver
     11  *
     12  *	$Id: if_el.c,v 1.2 1994/03/01 04:12:25 cgd Exp $
     13  */
     14 
     15 /*
     16  * Bugs/possible improvements:
     17  *	- Does not currently support DMA
     18  *	- Does not currently support multicasts
     19  */
     20 
     21 #include "el.h"
     22 #if NEL > 0
     23 #include "bpfilter.h"
     24 
     25 #include <sys/param.h>
     26 #include <sys/errno.h>
     27 #include <sys/ioctl.h>
     28 #include <sys/mbuf.h>
     29 #include <sys/socket.h>
     30 #include <sys/syslog.h>
     31 
     32 #include <net/if.h>
     33 #include <net/if_dl.h>
     34 #include <net/if_types.h>
     35 
     36 #ifdef INET
     37 #include <netinet/in.h>
     38 #include <netinet/in_systm.h>
     39 #include <netinet/in_var.h>
     40 #include <netinet/ip.h>
     41 #include <netinet/if_ether.h>
     42 #endif
     43 
     44 #ifdef NS
     45 #include <netns/ns.h>
     46 #include <netns/ns_if.h>
     47 #endif
     48 
     49 #if NBPFILTER > 0
     50 #include <net/bpf.h>
     51 #include <net/bpfdesc.h>
     52 #endif
     53 
     54 #include <machine/pio.h>
     55 
     56 #include <i386/isa/isa.h>
     57 #include <i386/isa/isa_device.h>
     58 #include <i386/isa/icu.h>
     59 #include <i386/isa/if_elreg.h>
     60 
     61 #define ETHER_MIN_LEN	64
     62 #define ETHER_MAX_LEN	1518
     63 
     64 /* For debugging convenience */
     65 #ifdef EL_DEBUG
     66 #define dprintf(x) printf x
     67 #else
     68 #define dprintf(x)
     69 #endif
     70 
     71 /*
     72  * el_softc: per-line info and status
     73  */
     74 struct el_softc {
     75 	struct arpcom arpcom;		/* Ethernet common */
     76 	u_short el_base;		/* Base I/O addr */
     77 	caddr_t bpf;			/* BPF magic cookie */
     78 	char el_pktbuf[EL_BUFSIZ]; 	/* Frame buffer */
     79 } el_softc[NEL];
     80 
     81 /*
     82  * Prototypes
     83  */
     84 int elintr __P((int));
     85 static int el_attach __P((struct isa_device *));
     86 static int el_init __P((int));
     87 static int el_ioctl __P((struct ifnet *, int, caddr_t));
     88 static int el_probe __P((struct isa_device *));
     89 static int el_start __P((struct ifnet *));
     90 static int el_watchdog __P((int));
     91 
     92 static void el_reset __P((int, int));
     93 static void el_stop __P((int));
     94 static int el_xmit __P((struct el_softc *, int));
     95 static inline void elread __P((struct el_softc *, caddr_t, int));
     96 static struct mbuf *elget __P((caddr_t, int, int, struct ifnet *));
     97 
     98 /* isa_driver structure for autoconf */
     99 struct isa_driver eldriver = {
    100 	el_probe, el_attach, "el"
    101 };
    102 
    103 /*
    104  * Probe routine.
    105  *
    106  * See if the card is there and at the right place.
    107  * (XXX - cgd -- needs help)
    108  */
    109 static int
    110 el_probe(idev)
    111 	struct isa_device *idev;
    112 {
    113 	struct el_softc *sc;
    114 	u_short base; /* Just for convenience */
    115 	u_char station_addr[ETHER_ADDR_LEN];
    116 	int i;
    117 
    118 	/* Grab some info for our structure */
    119 	sc = &el_softc[idev->id_unit];
    120 	sc->el_base = idev->id_iobase;
    121 	base = sc->el_base;
    122 
    123 	/* First check the base */
    124 	if ((base < 0x280) || (base > 0x3f0))
    125 		return(0);
    126 
    127 	/*
    128 	 * Now attempt to grab the station address from the PROM
    129 	 * and see if it contains the 3com vendor code.
    130 	 */
    131 	dprintf(("Probing 3c501 at 0x%x...\n", base));
    132 	/* Reset the board */
    133 	dprintf(("Resetting board...\n"));
    134 	outb(base+EL_AC, EL_AC_RESET);
    135 	DELAY(5);
    136 	outb(base+EL_AC, 0);
    137 	dprintf(("Reading station address...\n"));
    138 	/* Now read the address */
    139 	for(i=0;i<ETHER_ADDR_LEN;i++) {
    140 		outb(base+EL_GPBL, i);
    141 		station_addr[i] = inb(base+EL_EAW);
    142 	}
    143 	dprintf(("Address is %s\n", ether_sprintf(station_addr)));
    144 
    145 	/*
    146 	 * If the vendor code is ok, return a 1.  We'll assume that
    147 	 * whoever configured this system is right about the IRQ.
    148 	 */
    149 	if ((station_addr[0] != 0x02) || (station_addr[1] != 0x60)
    150 	    || (station_addr[2] != 0x8c)) {
    151 		dprintf(("Bad vendor code.\n"));
    152 		return(0);
    153 	} else {
    154 		dprintf(("Vendor code ok.\n"));
    155 		/* Copy the station address into the arpcom structure */
    156 		bcopy(station_addr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
    157 		return(1);		/* XXX - cgd? */
    158 	}
    159 }
    160 
    161 /*
    162  * Attach the interface to the kernel data structures.  By the time
    163  * this is called, we know that the card exists at the given I/O address.
    164  * We still assume that the IRQ given is correct.
    165  */
    166 static int
    167 el_attach(idev)
    168 	struct isa_device *idev;
    169 {
    170 	struct el_softc *sc;
    171 	struct ifnet *ifp;
    172 	struct ifaddr *ifa;
    173 	struct sockaddr_dl *sdl;
    174 	u_short base;
    175 	int t;
    176 
    177 	dprintf(("Attaching el%d...\n", idev->id_unit));
    178 
    179 	/* Get things pointing to the right places. */
    180 	sc = &el_softc[idev->id_unit];
    181 	ifp = &sc->arpcom.ac_if;
    182 	base = sc->el_base;
    183 
    184 	/* Now reset the board */
    185 	dprintf(("Resetting board...\n"));
    186 	outb(base+EL_AC, EL_AC_RESET);
    187 	DELAY(5);
    188 	outb(base+EL_AC, 0);
    189 
    190 	/* Initialize ifnet structure */
    191 	ifp->if_unit = idev->id_unit;
    192 	ifp->if_name = "el";
    193 	ifp->if_mtu = ETHERMTU;
    194 	ifp->if_output = ether_output;
    195 	ifp->if_start = el_start;
    196 	ifp->if_ioctl = el_ioctl;
    197 	ifp->if_watchdog = el_watchdog;
    198 	ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS);
    199 
    200 	/* Now we can attach the interface */
    201 	dprintf(("Attaching interface...\n"));
    202 	if_attach(ifp);
    203 
    204 	/*
    205 	 * Put the station address in the ifa address list's AF_LINK
    206 	 * entry, if any.
    207 	 */
    208 	ifa = ifp->if_addrlist;
    209 	while ((ifa != NULL) && (ifa->ifa_addr != NULL) &&
    210 	    (ifa->ifa_addr->sa_family != AF_LINK))
    211 		ifa = ifa->ifa_next;
    212 	if ((ifa != NULL) && (ifa->ifa_addr != NULL)) {
    213 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
    214 		sdl->sdl_type = IFT_ETHER;
    215 		sdl->sdl_alen = ETHER_ADDR_LEN;
    216 		sdl->sdl_slen = 0;
    217 		bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN);
    218 	}
    219 
    220 	/* Print out some information for the user */
    221 	printf("el%d: address %s\n", idev->id_unit,
    222 	    ether_sprintf(sc->arpcom.ac_enaddr));
    223 
    224 	/* Finally, attach to bpf filter if it is present. */
    225 #if NBPFILTER > 0
    226 	dprintf(("Attaching to BPF...\n"));
    227 	bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
    228 #endif
    229 
    230 	dprintf(("el_attach() finished.\n"));
    231 	return(1);
    232 }
    233 
    234 /*
    235  * Reset interface.
    236  */
    237 static void
    238 el_reset(unit, uban)
    239 	int unit, uban;
    240 {
    241 	int s;
    242 
    243 	dprintf(("elreset()\n"));
    244 	s = splimp();
    245 	el_stop(unit);
    246 	el_init(unit);
    247 	splx(s);
    248 }
    249 
    250 /*
    251  * Stop interface.
    252  */
    253 static void
    254 el_stop(unit)
    255 	int unit;
    256 {
    257 	struct el_softc *sc;
    258 
    259 	sc = &el_softc[unit];
    260 	outb(sc->el_base+EL_AC, 0);
    261 }
    262 
    263 /*
    264  * Initialize interface.
    265  */
    266 static int
    267 el_init(unit)
    268 	int unit;
    269 {
    270 	struct el_softc *sc;
    271 	struct ifnet *ifp;
    272 	int s;
    273 	u_short base;
    274 
    275 	/* Set up pointers */
    276 	sc = &el_softc[unit];
    277 	ifp = &sc->arpcom.ac_if;
    278 	base = sc->el_base;
    279 
    280 	/* If address not known, do nothing. */
    281 	if (ifp->if_addrlist == (struct ifaddr *)0)
    282 		return;
    283 
    284 	s = splimp();
    285 
    286 	/* First, reset the board. */
    287 	dprintf(("Resetting board...\n"));
    288 	outb(base+EL_AC, EL_AC_RESET);
    289 	DELAY(5);
    290 	outb(base+EL_AC, 0);
    291 
    292 	/* Configure rx */
    293 	dprintf(("Configuring rx...\n"));
    294 	if (ifp->if_flags & IFF_PROMISC)
    295 		outb(base+EL_RXC, (EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
    296 	else
    297 		outb(base+EL_RXC, (EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
    298 	outb(base+EL_RBC, 0);
    299 
    300 	/* Configure TX */
    301 	dprintf(("Configuring tx...\n"));
    302 	outb(base+EL_TXC, 0);
    303 
    304 	/* Start reception */
    305 	dprintf(("Starting reception...\n"));
    306 	outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
    307 
    308 	/* Set flags appropriately */
    309 	ifp->if_flags |= IFF_RUNNING;
    310 	ifp->if_flags &= ~IFF_OACTIVE;
    311 
    312 	/* And start output. */
    313 	el_start(ifp);
    314 
    315 	splx(s);
    316 }
    317 
    318 /*
    319  * Start output on interface.  Get datagrams from the queue and output
    320  * them, giving the receiver a chance between datagrams.  Call only
    321  * from splimp or interrupt level!
    322  */
    323 static int
    324 el_start(ifp)
    325 	struct ifnet *ifp;
    326 {
    327 	struct el_softc *sc;
    328 	u_short base;
    329 	struct mbuf *m, *m0;
    330 	int s, i, len, retries, done;
    331 
    332 	/* Get things pointing in the right directions */
    333 	sc = &el_softc[ifp->if_unit];
    334 	base = sc->el_base;
    335 
    336 	dprintf(("el_start()...\n"));
    337 	s = splimp();
    338 
    339 	/* Don't do anything if output is active */
    340 	if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE)
    341 		return;
    342 	sc->arpcom.ac_if.if_flags |= IFF_OACTIVE;
    343 
    344 	/* The main loop.  They warned me against endless loops, but
    345 	 * would I listen?  NOOO....
    346 	 */
    347 	while(1) {
    348 		/* Dequeue the next datagram */
    349 		IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m0);
    350 
    351 		/* If there's nothing to send, return. */
    352 		if (m0 == NULL) {
    353 			sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE;
    354 			splx(s);
    355 			return;
    356 		}
    357 
    358 		/* Disable the receiver */
    359 		outb(base+EL_AC, EL_AC_HOST);
    360 		outb(base+EL_RBC, 0);
    361 
    362 		/* Copy the datagram to the buffer. */
    363 		len = 0;
    364 		for(m = m0; m != NULL; m = m->m_next) {
    365 			if (m->m_len == 0)
    366 				continue;
    367 			bcopy(mtod(m, caddr_t), sc->el_pktbuf+len, m->m_len);
    368 			len += m->m_len;
    369 		}
    370 		m_freem(m0);
    371 
    372 		len = MAX(len, ETHER_MIN_LEN);
    373 
    374 		/* Give the packet to the bpf, if any */
    375 #if NBPFILTER > 0
    376 		if (sc->bpf)
    377 			bpf_tap(sc->bpf, sc->el_pktbuf, len);
    378 #endif
    379 
    380 		/* Transfer datagram to board */
    381 		dprintf(("el: xfr pkt length=%d...\n", len));
    382 		i = EL_BUFSIZ - len;
    383 		outb(base+EL_GPBL, (i & 0xff));
    384 		outb(base+EL_GPBH, ((i>>8)&0xff));
    385 		outsb(base+EL_BUF, sc->el_pktbuf, len);
    386 
    387 		/* Now transmit the datagram */
    388 		retries=0;
    389 		done=0;
    390 		while(!done) {
    391 			if (el_xmit(sc, len)) { /* Something went wrong */
    392 				done = -1;
    393 				break;
    394 			}
    395 			/* Check out status */
    396 			i = inb(base+EL_TXS);
    397 			dprintf(("tx status=0x%x\n", i));
    398 			if (!(i & EL_TXS_READY)) {
    399 				dprintf(("el: err txs=%x\n", i));
    400 				sc->arpcom.ac_if.if_oerrors++;
    401 				if (i & (EL_TXS_COLL|EL_TXS_COLL16)) {
    402 					if ((!(i & EL_TXC_DCOLL16)) &&
    403 					    retries < 15) {
    404 						retries++;
    405 						outb(base+EL_AC, EL_AC_HOST);
    406 					}
    407 				} else
    408 					done = 1;
    409 			} else
    410 				done = 1;
    411 		}
    412 		if (done == -1)  /* Packet not transmitted */
    413 			continue;
    414 
    415 		/*
    416 		 * Now give the card a chance to receive.
    417 		 * Gotta love 3c501s...
    418 		 */
    419 		(void)inb(base+EL_AS);
    420 		outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
    421 		splx(s);
    422 		/* Interrupt here */
    423 		s = splimp();
    424 	}
    425 }
    426 
    427 /*
    428  * This function actually attempts to transmit a datagram downloaded
    429  * to the board.  Call at splimp or interrupt, after downloading data!
    430  * Returns 0 on success, non-0 on failure
    431  */
    432 static int
    433 el_xmit(sc, len)
    434 	struct el_softc *sc;
    435 	int len;
    436 {
    437 	int gpl;
    438 	int i;
    439 
    440 	gpl = EL_BUFSIZ - len;
    441 	dprintf(("el: xmit..."));
    442 	outb((sc->el_base)+EL_GPBL, (gpl & 0xff));
    443 	outb((sc->el_base)+EL_GPBH, ((gpl>>8)&0xff));
    444 	outb((sc->el_base)+EL_AC, EL_AC_TXFRX);
    445 	i = 20000;
    446 	while((inb((sc->el_base)+EL_AS) & EL_AS_TXBUSY) && (i>0))
    447 		i--;
    448 	if (i == 0) {
    449 		dprintf(("tx not ready\n"));
    450 		sc->arpcom.ac_if.if_oerrors++;
    451 		return(-1);
    452 	}
    453 	dprintf(("%d cycles.\n", (20000-i)));
    454 	return(0);
    455 }
    456 
    457 /* controller interrupt */
    458 int
    459 elintr(unit)
    460 	int unit;
    461 {
    462 	register struct el_softc *sc;
    463 	register base;
    464 	int stat, rxstat, len, done;
    465 
    466 	/* Get things pointing properly */
    467 	sc = &el_softc[unit];
    468 	base = sc->el_base;
    469 
    470 	dprintf(("elintr: "));
    471 
    472 	/* Check board status */
    473 	stat = inb(base+EL_AS);
    474 	if (stat & EL_AS_RXBUSY) {
    475 		(void)inb(base+EL_RXC);
    476 		outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
    477 		return;
    478 	}
    479 
    480 	done = 0;
    481 	while(!done) {
    482 		rxstat = inb(base+EL_RXS);
    483 		if (rxstat & EL_RXS_STALE) {
    484 			(void)inb(base+EL_RXC);
    485 			outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
    486 			return;
    487 		}
    488 
    489 		/* If there's an overflow, reinit the board. */
    490 		if (!(rxstat & EL_RXS_NOFLOW)) {
    491 			dprintf(("overflow.\n"));
    492 			outb(base+EL_AC, EL_AC_RESET);
    493 			DELAY(5);
    494 			outb(base+EL_AC, 0);
    495 			/* Put board back into receive mode */
    496 			if (sc->arpcom.ac_if.if_flags & IFF_PROMISC)
    497 				outb(base+EL_RXC, (EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
    498 			else
    499 				outb(base+EL_RXC, (EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
    500 			(void)inb(base+EL_AS);
    501 			outb(base+EL_RBC, 0);
    502 			(void)inb(base+EL_RXC);
    503 			outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
    504 			return;
    505 		}
    506 
    507 		/* Incoming packet */
    508 		len = inb(base+EL_RBL);
    509 		len |= inb(base+EL_RBH) << 8;
    510 		dprintf(("receive len=%d rxstat=%x ", len, rxstat));
    511 		outb(base+EL_AC, EL_AC_HOST);
    512 
    513 		/*
    514 		 * If packet too short or too long, restore rx mode and return
    515 		 */
    516 		if ((len <= sizeof(struct ether_header)) ||
    517 		    (len > ETHER_MAX_LEN)) {
    518 			if (sc->arpcom.ac_if.if_flags & IFF_PROMISC)
    519 				outb(base+EL_RXC, (EL_RXC_PROMISC|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
    520 			else
    521 				outb(base+EL_RXC, (EL_RXC_ABROAD|EL_RXC_AGF|EL_RXC_DSHORT|EL_RXC_DDRIB|EL_RXC_DOFLOW));
    522 			(void)inb(base+EL_AS);
    523 			outb(base+EL_RBC, 0);
    524 			(void)inb(base+EL_RXC);
    525 			outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
    526 			return;
    527 		}
    528 
    529 		sc->arpcom.ac_if.if_ipackets++;
    530 
    531 		/* Copy the data into our buffer */
    532 		outb(base+EL_GPBL, 0);
    533 		outb(base+EL_GPBH, 0);
    534 		insb(base+EL_BUF, sc->el_pktbuf, len);
    535 		outb(base+EL_RBC, 0);
    536 		outb(base+EL_AC, EL_AC_RX);
    537 		dprintf(("%s-->", ether_sprintf(sc->el_pktbuf+6)));
    538 		dprintf(("%s\n", ether_sprintf(sc->el_pktbuf)));
    539 
    540 		/* Pass data up to upper levels */
    541 		len -= sizeof(struct ether_header);
    542 		elread(sc, (caddr_t)(sc->el_pktbuf), len);
    543 
    544 		/* Is there another packet? */
    545 		stat = inb(base+EL_AS);
    546 
    547 		/* If so, do it all again (i.e. don't set done to 1) */
    548 		if (!(stat & EL_AS_RXBUSY))
    549 			dprintf(("<rescan> "));
    550 		else
    551 			done = 1;
    552 	}
    553 
    554 	(void)inb(base+EL_RXC);
    555 	outb(base+EL_AC, (EL_AC_IRQE|EL_AC_RX));
    556 	return;
    557 }
    558 
    559 /*
    560  * Pass a packet up to the higher levels.  Deal with trailer protocol.
    561  */
    562 static inline void
    563 elread(sc, buf, len)
    564 	struct el_softc *sc;
    565 	caddr_t buf;
    566 	int len;
    567 {
    568 	register struct ether_header *eh;
    569 	struct mbuf *m;
    570 	int off, resid;
    571 	u_short et;
    572 
    573 	/*
    574 	 * Deal with trailer protocol: if type is trailer type
    575 	 * get true type from first 16-bit word past data.
    576 	 * Remember that type was trailer by setting off.
    577 	 */
    578 	eh = (struct ether_header *)buf;
    579 	et = ntohs(eh->ether_type);
    580 #define eldataaddr(eh, off, type)	((type)(((caddr_t)((eh)+1)+(off))))
    581 	if (et >= ETHERTYPE_TRAIL && et < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
    582 		off = (et - ETHERTYPE_TRAIL) * 512;
    583 		if (off >= ETHERMTU)
    584 			return;
    585 		/* next few lines are rather icky.  XXX - cgd */
    586 		eh->ether_type = *eldataaddr(eh, off, u_short *);
    587 		resid = ntohs(*(eldataaddr(eh, off+2, u_short *)));
    588 		if ((off+resid) > len)
    589 			return;
    590 		len = off + resid;
    591 	} else
    592 		off = 0;
    593 
    594 	if (len <= 0)
    595 		return;
    596 
    597 #if NBPFILTER > 0
    598 	/*
    599 	 * Check if there's a bpf filter listening on this interface.
    600 	 * If so, hand off the raw packet to bpf, which must deal with
    601 	 * trailers in its own way.
    602 	 *
    603 	 * comparing to if_ed, this code does bpf on trailer
    604 	 * packets incorrectly -- the ether type's already
    605 	 * been copied over... XXX - cgd
    606 	 */
    607 	if (sc->bpf) {
    608 		bpf_tap(sc->bpf, buf, (len+sizeof(struct ether_header));
    609 
    610 		/*
    611 		 * Note that the interface cannot be in promiscuous mode if
    612 		 * there are no bpf listeners.  And if el are in promiscuous
    613 		 * mode, el have to check if this packet is really ours.
    614 		 *
    615 		 * This test does not support multicasts.
    616 		 */
    617 		if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC)
    618 		   && bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
    619 			   sizeof(eh->ether_dhost)) != 0
    620 		   && bcmp(eh->ether_dhost, etherbroadcastaddr,
    621 			   sizeof(eh->ether_dhost)) != 0)
    622 			return;
    623 	}
    624 #endif
    625 
    626 	/*
    627 	 * Pull packet off interface.  Off is nonzero if packet
    628 	 * has trailing header; neget will then force this header
    629 	 * information to be at the front, but we still have to drop
    630 	 * the type and length which are at the front of any trailer data.
    631 	 */
    632 	m = elget(buf, len, off, &sc->arpcom.ac_if);
    633 	if (m == 0)
    634 		return;
    635 
    636 	ether_input(&sc->arpcom.ac_if, eh, m);
    637 }
    638 
    639 /*
    640  * Pull read data off a interface.
    641  * Len is length of data, with local net header stripped.
    642  * Off is non-zero if a trailer protocol was used, and
    643  * gives the offset of the trailer information.
    644  * We copy the trailer information and then all the normal
    645  * data into mbufs.  When full cluster sized units are present
    646  * we copy into clusters.
    647  */
    648 struct mbuf *
    649 elget(buf, totlen, off0, ifp)
    650         caddr_t buf;
    651         int totlen, off0;
    652         struct ifnet *ifp;
    653 {
    654         struct mbuf *top, **mp, *m, *p;
    655         int off = off0, len;
    656         register caddr_t cp = buf;
    657         char *epkt;
    658 
    659         buf += sizeof(struct ether_header);
    660         cp = buf;
    661         epkt = cp + totlen;
    662 
    663         if (off) {
    664                 cp += off + 2 * sizeof(u_short);
    665                 totlen -= 2 * sizeof(u_short);
    666         }
    667 
    668         MGETHDR(m, M_DONTWAIT, MT_DATA);
    669         if (m == 0)
    670                 return (0);
    671         m->m_pkthdr.rcvif = ifp;
    672         m->m_pkthdr.len = totlen;
    673         m->m_len = MHLEN;
    674         top = 0;
    675         mp = &top;
    676         while (totlen > 0) {
    677                 if (top) {
    678                         MGET(m, M_DONTWAIT, MT_DATA);
    679                         if (m == 0) {
    680                                 m_freem(top);
    681                                 return (0);
    682                         }
    683                         m->m_len = MLEN;
    684                 }
    685                 len = min(totlen, epkt - cp);
    686                 if (len >= MINCLSIZE) {
    687                         MCLGET(m, M_DONTWAIT);
    688                         if (m->m_flags & M_EXT)
    689                                 m->m_len = len = min(len, MCLBYTES);
    690                         else
    691                                 len = m->m_len;
    692                 } else {
    693                         /*
    694                          * Place initial small packet/header at end of mbuf.
    695                          */
    696                         if (len < m->m_len) {
    697                                 if (top == 0 && len + max_linkhdr <= m->m_len)
    698                                         m->m_data += max_linkhdr;
    699                                 m->m_len = len;
    700                         } else
    701                                 len = m->m_len;
    702                 }
    703                 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
    704                 cp += len;
    705                 *mp = m;
    706                 mp = &m->m_next;
    707                 totlen -= len;
    708                 if (cp == epkt)
    709                         cp = buf;
    710         }
    711         return (top);
    712 }
    713 
    714 /*
    715  * Process an ioctl request. This code needs some work - it looks
    716  *	pretty ugly. (XXX? - cgd)
    717  */
    718 static int
    719 el_ioctl(ifp, command, data)
    720 	register struct ifnet *ifp;
    721 	int command;
    722 	caddr_t data;
    723 {
    724 	register struct ifaddr *ifa = (struct ifaddr *)data;
    725 	struct el_softc *sc = &el_softc[ifp->if_unit];
    726 	struct ifreq *ifr = (struct ifreq *)data;
    727 	int s, error = 0;
    728 
    729 	s = splimp();
    730 
    731 	switch (command) {
    732 
    733 	case SIOCSIFADDR:
    734 		ifp->if_flags |= IFF_UP;
    735 
    736 		switch (ifa->ifa_addr->sa_family) {
    737 #ifdef INET
    738 		case AF_INET:
    739 			el_init(ifp->if_unit);	/* before arpwhohas */
    740 			/*
    741 			 * See if another station has *our* IP address.
    742 			 * i.e.: There is an address conflict! If a
    743 			 * conflict exists, a message is sent to the
    744 			 * console.
    745 			 */
    746 			((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;
    747 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
    748 			break;
    749 #endif
    750 #ifdef NS
    751 		/*
    752 		 * XXX - This code is probably wrong (XXX? - cgd)
    753 		 */
    754 		case AF_NS:
    755 			{
    756 				register struct ns_addr *ina =
    757 				    &(IA_SNS(ifa)->sns_addr);
    758 
    759 				if (ns_nullhost(*ina))
    760 					ina->x_host = *(union ns_host *)
    761 							(sc->arpcom.ac_enaddr);
    762 				else {
    763 					/*
    764 					 *
    765 					 */
    766 					bcopy((caddr_t)ina->x_host.c_host,
    767 					      (caddr_t)sc->arpcom.ac_enaddr,
    768 					      sizeof(sc->arpcom.ac_enaddr));
    769 				}
    770 				/*
    771 				 * Set new address
    772 				 */
    773 				el_init(ifp->if_unit);
    774 				break;
    775 			}
    776 #endif
    777 		default:
    778 			el_init(ifp->if_unit);
    779 			break;
    780 		}
    781 		break;
    782 
    783 	case SIOCGIFADDR:
    784 		{
    785 			struct sockaddr *sa;
    786 			sa = (struct sockaddr *)&ifr->ifr_data;
    787 			bcopy((caddr_t)sc->arpcom.ac_enaddr,
    788 			    (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
    789 		}
    790 		break;
    791 
    792 	case SIOCSIFFLAGS:
    793 		/*
    794 		 * If interface is marked down and it is running, then stop it
    795 		 */
    796 		if (((ifp->if_flags & IFF_UP) == 0) &&
    797 		    (ifp->if_flags & IFF_RUNNING)) {
    798 			el_stop(ifp->if_unit);
    799 			ifp->if_flags &= ~IFF_RUNNING;
    800 		} else {
    801 		/*
    802 		 * If interface is marked up and it is stopped, then start it
    803 		 */
    804 			if ((ifp->if_flags & IFF_UP) &&
    805 		    	    ((ifp->if_flags & IFF_RUNNING) == 0))
    806 				el_init(ifp->if_unit);
    807 		}
    808 
    809 	default:
    810 		error = EINVAL;
    811 	}
    812 	(void) splx(s);
    813 	return (error);
    814 }
    815 
    816 /* Device timeout routine */
    817 static int
    818 el_watchdog(unit)
    819 	int unit;
    820 {
    821 	struct el_softc *sc;
    822 
    823 	sc = &el_softc[unit];
    824 
    825 	log(LOG_ERR,"el%d: device timeout\n", unit);
    826 	sc->arpcom.ac_if.if_oerrors++;
    827 	el_reset(unit, 0);
    828 }
    829 #endif
    830