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/mtx/devether.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 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "io.h"
    7 #include "ureg.h"
    8 #include "../port/error.h"
    9 #include "../port/netif.h"
   10 
   11 #include "etherif.h"
   12 
   13 static Ether *etherxx[MaxEther];
   14 
   15 Chan*
   16 etherattach(char* spec)
   17 {
   18         ulong ctlrno;
   19         char *p;
   20         Chan *chan;
   21 
   22         ctlrno = 0;
   23         if(spec && *spec){
   24                 ctlrno = strtoul(spec, &p, 0);
   25                 if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
   26                         error(Ebadarg);
   27         }
   28         if(etherxx[ctlrno] == 0)
   29                 error(Enodev);
   30 
   31         chan = devattach('l', spec);
   32         chan->dev = ctlrno;
   33         if(etherxx[ctlrno]->attach)
   34                 etherxx[ctlrno]->attach(etherxx[ctlrno]);
   35         return chan;
   36 }
   37 
   38 static Walkqid*
   39 etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
   40 {
   41         return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
   42 }
   43 
   44 static int
   45 etherstat(Chan* chan, uchar* dp, int n)
   46 {
   47         return netifstat(etherxx[chan->dev], chan, dp, n);
   48 }
   49 
   50 static Chan*
   51 etheropen(Chan* chan, int omode)
   52 {
   53         return netifopen(etherxx[chan->dev], chan, omode);
   54 }
   55 
   56 static void
   57 ethercreate(Chan*, char*, int, ulong)
   58 {
   59 }
   60 
   61 static void
   62 etherclose(Chan* chan)
   63 {
   64         netifclose(etherxx[chan->dev], chan);
   65 }
   66 
   67 static long
   68 etherread(Chan* chan, void* buf, long n, vlong off)
   69 {
   70         Ether *ether;
   71         ulong offset = off;
   72 
   73         ether = etherxx[chan->dev];
   74         if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
   75                 /*
   76                  * With some controllers it is necessary to reach
   77                  * into the chip to extract statistics.
   78                  */
   79                 if(NETTYPE(chan->qid.path) == Nifstatqid)
   80                         return ether->ifstat(ether, buf, n, offset);
   81                 else if(NETTYPE(chan->qid.path) == Nstatqid)
   82                         ether->ifstat(ether, buf, 0, offset);
   83         }
   84 
   85         return netifread(ether, chan, buf, n, offset);
   86 }
   87 
   88 static Block*
   89 etherbread(Chan* chan, long n, ulong offset)
   90 {
   91         return netifbread(etherxx[chan->dev], chan, n, offset);
   92 }
   93 
   94 static int
   95 etherwstat(Chan* chan, uchar* dp, int n)
   96 {
   97         return netifwstat(etherxx[chan->dev], chan, dp, n);
   98 }
   99 
  100 static void
  101 etherrtrace(Netfile* f, Etherpkt* pkt, int len)
  102 {
  103         int i, n;
  104         Block *bp;
  105 
  106         if(qwindow(f->in) <= 0)
  107                 return;
  108         if(len > 58)
  109                 n = 58;
  110         else
  111                 n = len;
  112         bp = iallocb(64);
  113         if(bp == nil)
  114                 return;
  115         memmove(bp->wp, pkt->d, n);
  116         i = TK2MS(MACHP(0)->ticks);
  117         bp->wp[58] = len>>8;
  118         bp->wp[59] = len;
  119         bp->wp[60] = i>>24;
  120         bp->wp[61] = i>>16;
  121         bp->wp[62] = i>>8;
  122         bp->wp[63] = i;
  123         bp->wp += 64;
  124         qpass(f->in, bp);
  125 }
  126 
  127 Block*
  128 etheriq(Ether* ether, Block* bp, int fromwire)
  129 {
  130         Etherpkt *pkt;
  131         ushort type;
  132         int len, multi, tome, fromme;
  133         Netfile **ep, *f, **fp, *fx;
  134         Block *xbp;
  135 
  136         ether->inpackets++;
  137 
  138         pkt = (Etherpkt*)bp->rp;
  139         len = BLEN(bp);
  140         type = (pkt->type[0]<<8)|pkt->type[1];
  141         fx = 0;
  142         ep = &ether->f[Ntypes];
  143 
  144         multi = pkt->d[0] & 1;
  145         /* check for valid multicast addresses */
  146         if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){
  147                 if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
  148                         if(fromwire){
  149                                 freeb(bp);
  150                                 bp = 0;
  151                         }
  152                         return bp;
  153                 }
  154         }
  155 
  156         /* is it for me? */
  157         tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
  158         fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
  159 
  160         /*
  161          * Multiplex the packet to all the connections which want it.
  162          * If the packet is not to be used subsequently (fromwire != 0),
  163          * attempt to simply pass it into one of the connections, thereby
  164          * saving a copy of the data (usual case hopefully).
  165          */
  166         for(fp = ether->f; fp < ep; fp++){
  167                 if(f = *fp)
  168                 if(f->type == type || f->type < 0)
  169                 if(tome || multi || f->prom){
  170                         /* Don't want to hear bridged packets */
  171                         if(f->bridge && !fromwire && !fromme)
  172                                 continue;
  173                         if(!f->headersonly){
  174                                 if(fromwire && fx == 0)
  175                                         fx = f;
  176                                 else if(xbp = iallocb(len)){
  177                                         memmove(xbp->wp, pkt, len);
  178                                         xbp->wp += len;
  179                                         qpass(f->in, xbp);
  180                                 }
  181                                 else
  182                                         ether->soverflows++;
  183                         }
  184                         else
  185                                 etherrtrace(f, pkt, len);
  186                 }
  187         }
  188 
  189         if(fx){
  190                 if(qpass(fx->in, bp) < 0)
  191                         ether->soverflows++;
  192                 return 0;
  193         }
  194         if(fromwire){
  195                 freeb(bp);
  196                 return 0;
  197         }
  198 
  199         return bp;
  200 }
  201 
  202 static int
  203 etheroq(Ether* ether, Block* bp)
  204 {
  205         int len, loopback, s;
  206         Etherpkt *pkt;
  207 
  208         ether->outpackets++;
  209 
  210         /*
  211          * Check if the packet has to be placed back onto the input queue,
  212          * i.e. if it's a loopback or broadcast packet or the interface is
  213          * in promiscuous mode.
  214          * If it's a loopback packet indicate to etheriq that the data isn't
  215          * needed and return, etheriq will pass-on or free the block.
  216          * To enable bridging to work, only packets that were originated
  217          * by this interface are fed back.
  218          */
  219         pkt = (Etherpkt*)bp->rp;
  220         len = BLEN(bp);
  221         loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
  222         if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
  223                 s = splhi();
  224                 etheriq(ether, bp, 0);
  225                 splx(s);
  226         }
  227 
  228         if(!loopback){
  229                 qbwrite(ether->oq, bp);
  230                 ether->transmit(ether);
  231         } else
  232                 freeb(bp);
  233 
  234         return len;
  235 }
  236 
  237 static long
  238 etherwrite(Chan* chan, void* buf, long n, vlong)
  239 {
  240         Ether *ether;
  241         Block *bp;
  242         int nn;
  243 
  244         ether = etherxx[chan->dev];
  245         if(NETTYPE(chan->qid.path) != Ndataqid) {
  246                 nn = netifwrite(ether, chan, buf, n);
  247                 if(nn >= 0)
  248                         return nn;
  249 
  250                 if(n == sizeof("nonblocking")-1 && strncmp((char*)buf, "nonblocking", n) == 0){
  251                         qnoblock(ether->oq, 1);
  252                         return n;
  253                 }
  254 
  255                 if(ether->ctl!=nil)
  256                         return ether->ctl(ether,buf,n);
  257                         
  258                 error(Ebadctl);
  259         }
  260 
  261         if(n > ether->maxmtu)
  262                 error(Etoobig);
  263         if(n < ether->minmtu)
  264                 error(Etoosmall);
  265 
  266         bp = allocb(n);
  267         if(waserror()){
  268                 freeb(bp);
  269                 nexterror();
  270         }
  271         memmove(bp->rp, buf, n);
  272         memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
  273         poperror();
  274         bp->wp += n;
  275 
  276         return etheroq(ether, bp);
  277 }
  278 
  279 static long
  280 etherbwrite(Chan* chan, Block* bp, ulong)
  281 {
  282         Ether *ether;
  283         long n;
  284 
  285         n = BLEN(bp);
  286         if(NETTYPE(chan->qid.path) != Ndataqid){
  287                 if(waserror()) {
  288                         freeb(bp);
  289                         nexterror();
  290                 }
  291                 n = etherwrite(chan, bp->rp, n, 0);
  292                 poperror();
  293                 freeb(bp);
  294                 return n;
  295         }
  296         ether = etherxx[chan->dev];
  297 
  298         if(n > ether->maxmtu){
  299                 freeb(bp);
  300                 error(Etoobig);
  301         }
  302         if(n < ether->minmtu){
  303                 freeb(bp);
  304                 error(Etoosmall);
  305         }
  306 
  307         return etheroq(ether, bp);
  308 }
  309 
  310 static struct {
  311         char*   type;
  312         int     (*reset)(Ether*);
  313 } cards[MaxEther+1];
  314 
  315 void
  316 addethercard(char* t, int (*r)(Ether*))
  317 {
  318         static int ncard;
  319 
  320         if(ncard == MaxEther)
  321                 panic("too many ether cards");
  322         cards[ncard].type = t;
  323         cards[ncard].reset = r;
  324         ncard++;
  325 }
  326 
  327 int
  328 parseether(uchar *to, char *from)
  329 {
  330         char nip[4];
  331         char *p;
  332         int i;
  333 
  334         p = from;
  335         for(i = 0; i < 6; i++){
  336                 if(*p == 0)
  337                         return -1;
  338                 nip[0] = *p++;
  339                 if(*p == 0)
  340                         return -1;
  341                 nip[1] = *p++;
  342                 nip[2] = 0;
  343                 to[i] = strtoul(nip, 0, 16);
  344                 if(*p == ':')
  345                         p++;
  346         }
  347         return 0;
  348 }
  349 
  350 static void
  351 etherreset(void)
  352 {
  353         Ether *ether;
  354         int i, n, ctlrno;
  355         char name[32], buf[128];
  356 
  357         for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
  358                 if(ether == 0)
  359                         ether = malloc(sizeof(Ether));
  360                 memset(ether, 0, sizeof(Ether));
  361                 ether->ctlrno = ctlrno;
  362                 ether->tbdf = BUSUNKNOWN;
  363                 ether->mbps = 10;
  364                 ether->minmtu = ETHERMINTU;
  365                 ether->maxmtu = ETHERMAXTU;
  366                 if(isaconfig("ether", ctlrno, ether) == 0)
  367                         continue;
  368                 for(n = 0; cards[n].type; n++){
  369                         if(cistrcmp(cards[n].type, ether->type))
  370                                 continue;
  371                         for(i = 0; i < ether->nopt; i++){
  372                                 if(strncmp(ether->opt[i], "ea=", 3))
  373                                         continue;
  374                                 if(parseether(ether->ea, &ether->opt[i][3]) == -1)
  375                                         memset(ether->ea, 0, Eaddrlen);
  376                         }       
  377                         if(cards[n].reset(ether))
  378                                 break;
  379 
  380                         /*
  381                          * IRQ2 doesn't really exist, it's used to gang the interrupt
  382                          * controllers together. A device set to IRQ2 will appear on
  383                          * the second interrupt controller as IRQ9.
  384                          */
  385                         if(ether->irq == 2 && BUSTYPE(ether->tbdf) != BusPCI)
  386                                 ether->irq = 9;
  387                         snprint(name, sizeof(name), "ether%d", ctlrno);
  388 
  389                         /*
  390                          * If ether->irq is <0, it is a hack to indicate no interrupt
  391                          * used by ethersink.
  392                          */
  393                         if(ether->irq >= 0)
  394                                 intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name);
  395 
  396                         i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
  397                                 ctlrno, ether->type, ether->mbps, ether->port, ether->irq);
  398                         if(ether->mem)
  399                                 i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem));
  400                         if(ether->size)
  401                                 i += sprint(buf+i, " size 0x%luX", ether->size);
  402                         i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
  403                                 ether->ea[0], ether->ea[1], ether->ea[2],
  404                                 ether->ea[3], ether->ea[4], ether->ea[5]);
  405                         sprint(buf+i, "\n");
  406                         print(buf);
  407 
  408                         if(ether->mbps >= 100){
  409                                 netifinit(ether, name, Ntypes, 256*1024);
  410                                 if(ether->oq == 0)
  411                                         ether->oq = qopen(256*1024, Qmsg, 0, 0);
  412                         }
  413                         else{
  414                                 netifinit(ether, name, Ntypes, 65*1024);
  415                                 if(ether->oq == 0)
  416                                         ether->oq = qopen(65*1024, Qmsg, 0, 0);
  417                         }
  418                         if(ether->oq == 0)
  419                                 panic("etherreset %s", name);
  420                         ether->alen = Eaddrlen;
  421                         memmove(ether->addr, ether->ea, Eaddrlen);
  422                         memset(ether->bcast, 0xFF, Eaddrlen);
  423 
  424                         etherxx[ctlrno] = ether;
  425                         ether = 0;
  426                         break;
  427                 }
  428         }
  429         if(ether)
  430                 free(ether);
  431 }
  432 
  433 #define POLY 0xedb88320
  434 
  435 /* really slow 32 bit crc for ethers */
  436 ulong
  437 ethercrc(uchar *p, int len)
  438 {
  439         int i, j;
  440         ulong crc, b;
  441 
  442         crc = 0xffffffff;
  443         for(i = 0; i < len; i++){
  444                 b = *p++;
  445                 for(j = 0; j < 8; j++){
  446                         crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
  447                         b >>= 1;
  448                 }
  449         }
  450         return crc;
  451 }
  452 
  453 Dev etherdevtab = {
  454         'l',
  455         "ether",
  456 
  457         etherreset,
  458         devinit,
  459         devshutdown,
  460         etherattach,
  461         etherwalk,
  462         etherstat,
  463         etheropen,
  464         ethercreate,
  465         etherclose,
  466         etherread,
  467         etherbread,
  468         etherwrite,
  469         etherbwrite,
  470         devremove,
  471         etherwstat,
  472 };

Cache object: ca233f4ab9294f17f8153ae68e3f9934


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