devether.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       devether.c (10561B)
       ---
            1 #include "u.h"
            2 #include "lib.h"
            3 #include "mem.h"
            4 #include "dat.h"
            5 #include "fns.h"
            6 #include "io.h"
            7 #include "ureg.h"
            8 #include "error.h"
            9 #include "netif.h"
           10 
           11 #include "etherif.h"
           12 
           13 extern int memsize;
           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]->ni, chan, nchan, name, nname);
           48 }
           49 
           50 static int
           51 etherstat(Chan* chan, uchar* dp, int n)
           52 {
           53         return netifstat(&etherxx[chan->dev]->ni, chan, dp, n);
           54 }
           55 
           56 static Chan*
           57 etheropen(Chan* chan, int omode)
           58 {
           59         return netifopen(&etherxx[chan->dev]->ni, chan, omode);
           60 }
           61 
           62 static void
           63 ethercreate(Chan* ch, char* c, int i, ulong ul)
           64 {
           65 }
           66 
           67 static void
           68 etherclose(Chan* chan)
           69 {
           70         netifclose(&etherxx[chan->dev]->ni, 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->ni, chan, buf, n, offset);
           92 }
           93 
           94 static Block*
           95 etherbread(Chan* chan, long n, ulong offset)
           96 {
           97         return netifbread(&etherxx[chan->dev]->ni, chan, n, offset);
           98 }
           99 
          100 static int
          101 etherwstat(Chan* chan, uchar* dp, int n)
          102 {
          103         return netifwstat(&etherxx[chan->dev]->ni, 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)->tscticks);
          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->ni.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->ni.f[Ntypes];
          149 
          150         multi = pkt->d[0] & 1;
          151         /* check for valid multicast addresses */
          152         if(multi && memcmp(pkt->d, ether->ni.bcast, sizeof(pkt->d)) != 0 && ether->ni.prom == 0){
          153                 if(!activemulti(&ether->ni, 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->ni.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->ni.soverflows++;
          188                                         }
          189                                 }
          190                                 else {
          191                                         print("soverflow iallocb\n");
          192                                         ether->ni.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->ni.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->ni.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->ni.bcast, sizeof(pkt->d)) == 0 || ether->ni.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 v)
          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->ni, 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 u)
          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->ni.mbps = 10;
          385         ether->minmtu = ETHERMINTU;
          386         ether->maxmtu = ETHERMAXTU;
          387 
          388         if(cardno < 0){
          389                 for(cardno = 0; cards[cardno].type; cardno++){
          390                         for(i = 0; i < ether->isac.nopt; i++){
          391                                 if(strncmp(ether->isac.opt[i], "ea=", 3))
          392                                         continue;
          393                                 if(parseether(ether->ea, &ether->isac.opt[i][3]))
          394                                         memset(ether->ea, 0, Eaddrlen);
          395                         }
          396                         break;
          397                 }
          398         }
          399 
          400         if(cardno >= MaxEther || cards[cardno].type == nil){
          401                 free(ether);
          402                 return nil;
          403         }
          404         if(cards[cardno].reset(ether) < 0){
          405                 free(ether);
          406                 return nil;
          407         }
          408 
          409         /*
          410          * IRQ2 doesn't really exist, it's used to gang the interrupt
          411          * controllers together. A device set to IRQ2 will appear on
          412          * the second interrupt controller as IRQ9.
          413          */
          414         if(ether->isac.irq == 2)
          415                 ether->isac.irq = 9;
          416         snprint(name, sizeof(name), "ether%d", ctlrno);
          417 
          418         i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
          419                 ctlrno, cards[cardno].type, ether->ni.mbps, ether->isac.port, ether->isac.irq);
          420         if(ether->isac.mem)
          421                 i += sprint(buf+i, " addr 0x%luX", ether->isac.mem);
          422         if(ether->isac.size)
          423                 i += sprint(buf+i, " size 0x%luX", ether->isac.size);
          424         i += sprint(buf+i, ": %2.2ux%2.2ux%2.2ux%2.2ux%2.2ux%2.2ux",
          425                 ether->ea[0], ether->ea[1], ether->ea[2],
          426                 ether->ea[3], ether->ea[4], ether->ea[5]);
          427         sprint(buf+i, "\n");
          428         print(buf);
          429 
          430         /* compute log10(ether->ni.mbps) into lg */
          431         for(lg = 0, mb = ether->ni.mbps; mb >= 10; lg++)
          432                 mb /= 10;
          433         if (lg > 0)
          434                 lg--;
          435         if (lg > 14)                        /* 2^(14+17) = 2⁳ⁱ */
          436                 lg = 14;
          437         /* allocate larger output queues for higher-speed interfaces */
          438         bsz = 1UL << (lg + 17);                /* 2ⁱ⁷ = 128K, bsz = 2ⁿ × 128K */
          439         while (bsz > memsize && bsz > 128*1024)
          440                 bsz /= 2;
          441 
          442         netifinit(&ether->ni, name, Ntypes, bsz);
          443         if(ether->oq == nil) {
          444                 ether->oq = qopen(bsz, Qmsg, 0, 0);
          445                 ether->ni.limit = bsz;
          446         }
          447         if(ether->oq == nil)
          448                 panic("etherreset %s: can't allocate output queue of %ld bytes",
          449                         name, bsz);
          450         ether->ni.alen = Eaddrlen;
          451         memmove(ether->ni.addr, ether->ea, Eaddrlen);
          452         memset(ether->ni.bcast, 0xFF, Eaddrlen);
          453 
          454         return ether;
          455 }
          456 
          457 static void
          458 etherreset(void)
          459 {
          460         Ether *ether;
          461         int cardno, ctlrno;
          462 
          463         for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){
          464                 if((ether = etherprobe(-1, ctlrno)) == nil)
          465                         continue;
          466                 etherxx[ctlrno] = ether;
          467         }
          468 
          469         cardno = ctlrno = 0;
          470         while(cards[cardno].type != nil && ctlrno < MaxEther){
          471                 if(etherxx[ctlrno] != nil){
          472                         ctlrno++;
          473                         continue;
          474                 }
          475                 if((ether = etherprobe(cardno, ctlrno)) == nil){
          476                         cardno++;
          477                         continue;
          478                 }
          479                 etherxx[ctlrno] = ether;
          480                 ctlrno++;
          481         }
          482 }
          483 
          484 static void
          485 ethershutdown(void)
          486 {
          487         Ether *ether;
          488         int i;
          489 
          490         for(i = 0; i < MaxEther; i++){
          491                 ether = etherxx[i];
          492                 if(ether == nil)
          493                         continue;
          494                 if(ether->shutdown == nil) {
          495                         print("#l%d: no shutdown fuction\n", i);
          496                         continue;
          497                 }
          498                 (*ether->shutdown)(ether);
          499         }
          500 }
          501 
          502 
          503 #define POLY 0xedb88320
          504 
          505 /* really slow 32 bit crc for ethers */
          506 ulong
          507 ethercrc(uchar *p, int len)
          508 {
          509         int i, j;
          510         ulong crc, b;
          511 
          512         crc = 0xffffffff;
          513         for(i = 0; i < len; i++){
          514                 b = *p++;
          515                 for(j = 0; j < 8; j++){
          516                         crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
          517                         b >>= 1;
          518                 }
          519         }
          520         return crc;
          521 }
          522 
          523 Dev etherdevtab = {
          524         'l',
          525         "ether",
          526 
          527         etherreset,
          528         devinit,
          529         ethershutdown,
          530         etherattach,
          531         etherwalk,
          532         etherstat,
          533         etheropen,
          534         ethercreate,
          535         etherclose,
          536         etherread,
          537         etherbread,
          538         etherwrite,
          539         etherbwrite,
          540         devremove,
          541         etherwstat,
          542 };