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

Cache object: 4d308fac430c4db4a2dbabefa4bd3fad


[ 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.