The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/if_el.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 0320ae298361cc04c6bfd46ab50f5951


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.