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