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

Cache object: b12c0e17eef8d9e87c4f6b12f8844845


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