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

Cache object: 2ef5a84fb57f0f23ebc183498434e61a


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