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