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

Cache object: 5f57c4b41deb9bca67176e9c8531ff8d


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