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