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