| plan 9 kernel history: overview | file list | diff list |
2002/0502/pc/devether.c (diff list | history)
| 2002/0502/sys/src/9/pc/devether.c:1,523 – 2002/0703/sys/src/9/pc/devether.c:1,523 (short | long | prev | next) | ||
| 1992/0403 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" | |
| 1993/1113 | #include "ureg.h" #include "../port/error.h" #include "../port/netif.h" | |
| 1992/0403 | ||
| 1993/1113 | #include "etherif.h" | |
| 1992/1222 | ||
| 1997/0327 | static Ether *etherxx[MaxEther]; | |
| 1992/0403 | ||
| 1993/1113 | Chan* | |
| 1997/0327 | etherattach(char* spec) | |
| 1993/1113 | { ulong ctlrno; char *p; | |
| 1997/0327 | Chan *chan; | |
| 1992/0404 | ||
| 1993/1113 | ctlrno = 0; if(spec && *spec){ ctlrno = strtoul(spec, &p, 0); if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) error(Ebadarg); } | |
| 1997/0327 | if(etherxx[ctlrno] == 0) | |
| 1993/1113 | error(Enodev); | |
| 1992/0403 | ||
| 1997/0327 | chan = devattach('l', spec); chan->dev = ctlrno; if(etherxx[ctlrno]->attach) etherxx[ctlrno]->attach(etherxx[ctlrno]); return chan; | |
| 1993/1113 | } | |
| 1992/0922 | ||
| 2001/0527 | static Walkqid* etherwalk(Chan* chan, Chan* nchan, char** name, int nname) | |
| 1992/0411 | { | |
| 2001/0527 | return netifwalk(etherxx[chan->dev], chan, nchan, name, nname); | |
| 1992/0424 | } | |
| 1992/0411 | ||
| 2001/0527 | static int etherstat(Chan* chan, uchar* dp, int n) | |
| 1992/0424 | { | |
| 2001/0527 | return netifstat(etherxx[chan->dev], chan, dp, n); | |
| 1992/0424 | } | |
| 1997/0327 | static Chan* etheropen(Chan* chan, int omode) | |
| 1992/0424 | { | |
| 1997/0327 | return netifopen(etherxx[chan->dev], chan, omode); | |
| 1992/0424 | } | |
| 1997/0327 | static void | |
| 1995/0726 | ethercreate(Chan*, char*, int, ulong) | |
| 1992/0424 | { } | |
| 1997/0327 | static void etherclose(Chan* chan) | |
| 1992/0424 | { | |
| 1997/0327 | netifclose(etherxx[chan->dev], chan); | |
| 1992/0424 | } | |
| 1997/0327 | static long | |
| 1998/0319 | etherread(Chan* chan, void* buf, long n, vlong off) | |
| 1992/0424 | { | |
| 1997/0327 | Ether *ether; | |
| 1998/0319 | ulong offset = off; | |
| 1996/0607 | ||
| 1997/0327 | ether = etherxx[chan->dev]; | |
| 2001/0527 | if((chan->qid.type & QTDIR) == 0 && ether->ifstat){ | |
| 1996/0607 | /* * With some controllers it is necessary to reach * into the chip to extract statistics. */ | |
| 1997/0327 | if(NETTYPE(chan->qid.path) == Nifstatqid) return ether->ifstat(ether, buf, n, offset); else if(NETTYPE(chan->qid.path) == Nstatqid) ether->ifstat(ether, buf, 0, offset); | |
| 1996/0607 | } | |
| 1997/0327 | return netifread(ether, chan, buf, n, offset); | |
| 1992/0411 | } | |
| 1997/0327 | static Block* etherbread(Chan* chan, long n, ulong offset) | |
| 1995/0108 | { | |
| 1997/0327 | return netifbread(etherxx[chan->dev], chan, n, offset); | |
| 1995/0108 | } | |
| 2001/0527 | static int etherwstat(Chan* chan, uchar* dp, int n) | |
| 1992/0424 | { | |
| 2001/0527 | return netifwstat(etherxx[chan->dev], chan, dp, n); | |
| 1992/0424 | } | |
| 1997/0327 | static void etherrtrace(Netfile* f, Etherpkt* pkt, int len) | |
| 1993/1120 | { | |
| 2001/0527 | int i, n; | |
| 1995/0713 | Block *bp; | |
| 1997/0327 | if(qwindow(f->in) <= 0) return; | |
| 2000/0713 | if(len > 58) n = 58; | |
| 1997/0327 | else n = len; | |
| 2001/0527 | bp = iallocb(64); | |
| 2000/0713 | if(bp == nil) | |
| 1997/0327 | return; memmove(bp->wp, pkt->d, n); | |
| 2001/0527 | i = TK2MS(MACHP(0)->ticks); | |
| 1997/0327 | bp->wp[58] = len>>8; bp->wp[59] = len; | |
| 2001/0527 | bp->wp[60] = i>>24; bp->wp[61] = i>>16; bp->wp[62] = i>>8; bp->wp[63] = i; bp->wp += 64; | |
| 1997/0327 | qpass(f->in, bp); } Block* | |
| 1999/0625 | etheriq(Ether* ether, Block* bp, int fromwire) | |
| 1997/0327 | { Etherpkt *pkt; | |
| 1993/1120 | ushort type; | |
| 1999/0625 | int len, multi, tome, fromme; | |
| 1997/0327 | Netfile **ep, *f, **fp, *fx; Block *xbp; | |
| 1993/1120 | ||
| 1997/0327 | ether->inpackets++; pkt = (Etherpkt*)bp->rp; len = BLEN(bp); | |
| 1993/1120 | type = (pkt->type[0]<<8)|pkt->type[1]; | |
| 1997/0327 | fx = 0; ep = ðer->f[Ntypes]; | |
| 1999/0316 | multi = pkt->d[0] & 1; | |
| 1997/0404 | /* check for valid multcast addresses */ | |
| 1999/0316 | if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) && ether->prom == 0){ | |
| 1997/0404 | if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ | |
| 1999/0625 | if(fromwire){ | |
| 1997/0404 | freeb(bp); bp = 0; } return bp; } } | |
| 1999/0625 | /* is it for me? */ tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0; fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0; | |
| 1999/0316 | ||
| 1997/0327 | /* * Multiplex the packet to all the connections which want it. | |
| 1999/0625 | * If the packet is not to be used subsequently (fromwire != 0), | |
| 1997/0327 | * attempt to simply pass it into one of the connections, thereby * saving a copy of the data (usual case hopefully). */ for(fp = ether->f; fp < ep; fp++){ | |
| 1999/0625 | if(f = *fp) if(f->type == type || f->type < 0) if(tome || multi || f->prom){ /* Don't want to hear bridged packets */ if(f->bridge && !fromwire && !fromme) continue; if(!f->headersonly){ if(fromwire && fx == 0) | |
| 1997/0327 | fx = f; else if(xbp = iallocb(len)){ memmove(xbp->wp, pkt, len); xbp->wp += len; | |
| 2002/0314 | if(qpass(f->in, xbp) < 0) ether->soverflows++; | |
| 1997/0327 | } | |
| 1995/0801 | else | |
| 1997/0327 | ether->soverflows++; | |
| 1995/0713 | } | |
| 1997/0327 | else etherrtrace(f, pkt, len); | |
| 1995/0713 | } | |
| 1993/1120 | } | |
| 1997/0327 | if(fx){ | |
| 1998/1013 | if(qpass(fx->in, bp) < 0) ether->soverflows++; | |
| 1997/0327 | return 0; } | |
| 1999/0625 | if(fromwire){ | |
| 1997/0327 | freeb(bp); return 0; } return bp; | |
| 1993/1120 | } static int | |
| 1997/0327 | etheroq(Ether* ether, Block* bp) | |
| 1993/1120 | { | |
| 1999/0625 | int len, loopback, s; | |
| 1997/0327 | Etherpkt *pkt; | |
| 1993/1120 | ||
| 1997/0327 | ether->outpackets++; | |
| 1993/1120 | ||
| 1997/0327 | /* * Check if the packet has to be placed back onto the input queue, * i.e. if it's a loopback or broadcast packet or the interface is * in promiscuous mode. * If it's a loopback packet indicate to etheriq that the data isn't * needed and return, etheriq will pass-on or free the block. | |
| 1999/0316 | * To enable bridging to work, only packets that were originated | |
| 1999/0402 | * by this interface are fed back. | |
| 1997/0327 | */ pkt = (Etherpkt*)bp->rp; len = BLEN(bp); | |
| 1999/0625 | loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0; | |
| 1997/0808 | if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){ | |
| 1997/0327 | s = splhi(); | |
| 1999/0625 | etheriq(ether, bp, 0); | |
| 1997/0327 | splx(s); } | |
| 1994/0702 | ||
| 1997/0327 | if(!loopback){ qbwrite(ether->oq, bp); ether->transmit(ether); | |
| 1999/0625 | } else freeb(bp); | |
| 1997/0327 | return len; | |
| 1993/1120 | } | |
| 1997/0327 | static long | |
| 1998/0319 | etherwrite(Chan* chan, void* buf, long n, vlong) | |
| 1992/0407 | { | |
| 1997/0327 | Ether *ether; | |
| 2001/0527 | Block *bp; | |
| 2000/0817 | int nn; | |
| 1992/0407 | ||
| 1997/0327 | ether = etherxx[chan->dev]; | |
| 2000/0817 | if(NETTYPE(chan->qid.path) != Ndataqid) { nn = netifwrite(ether, chan, buf, n); if(nn >= 0) return nn; | |
| 1992/0403 | ||
| 2000/0817 | if(ether->ctl!=nil) return ether->ctl(ether,buf,n); error(Ebadctl); } | |
| 2000/0921 | if(n > ether->maxmtu) | |
| 1997/1101 | error(Etoobig); | |
| 2000/0921 | if(n < ether->minmtu) | |
| 1997/1101 | error(Etoosmall); | |
| 1997/0327 | bp = allocb(n); | |
| 2001/0504 | if(waserror()){ freeb(bp); nexterror(); } | |
| 1997/0327 | memmove(bp->rp, buf, n); memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen); | |
| 2001/0504 | poperror(); | |
| 1997/0327 | bp->wp += n; | |
| 1992/0403 | ||
| 1997/0327 | return etheroq(ether, bp); | |
| 1995/0108 | } | |
| 1997/0327 | static long etherbwrite(Chan* chan, Block* bp, ulong) | |
| 1995/0108 | { | |
| 1997/0327 | Ether *ether; long n; n = BLEN(bp); if(NETTYPE(chan->qid.path) != Ndataqid){ | |
| 2000/0817 | if(waserror()) { freeb(bp); nexterror(); } n = etherwrite(chan, bp->rp, n, 0); | |
| 2000/0921 | poperror(); | |
| 1997/0327 | freeb(bp); return n; } | |
| 2000/0817 | ether = etherxx[chan->dev]; | |
| 1997/0327 | ||
| 2000/0921 | if(n > ether->maxmtu){ | |
| 1997/1101 | freeb(bp); | |
| 2000/0921 | error(Etoobig); | |
| 1997/1101 | } | |
| 2000/0921 | if(n < ether->minmtu){ | |
| 1997/1101 | freeb(bp); error(Etoosmall); } | |
| 1997/0327 | return etheroq(ether, bp); | |
| 1992/0403 | } | |
| 1993/1113 | static struct { | |
| 1997/0327 | char* type; | |
| 1993/1113 | int (*reset)(Ether*); | |
| 1993/1119 | } cards[MaxEther+1]; | |
| 1992/0403 | ||
| 1993/1113 | void | |
| 1997/0327 | addethercard(char* t, int (*r)(Ether*)) | |
| 1992/0403 | { | |
| 1993/1113 | static int ncard; | |
| 1992/0403 | ||
| 1993/1119 | if(ncard == MaxEther) | |
| 1993/1113 | panic("too many ether cards"); cards[ncard].type = t; cards[ncard].reset = r; ncard++; | |
| 1992/0403 | } | |
| 1997/0327 | int parseether(uchar *to, char *from) { char nip[4]; char *p; int i; p = from; | |
| 2002/0703 | for(i = 0; i < Eaddrlen; i++){ | |
| 1997/0327 | if(*p == 0) return -1; nip[0] = *p++; if(*p == 0) return -1; nip[1] = *p++; nip[2] = 0; to[i] = strtoul(nip, 0, 16); if(*p == ':') p++; } return 0; } | |
| 2002/0403 | static Ether* etherprobe(int cardno, int ctlrno) | |
| 1992/0424 | { | |
| 2002/0403 | int i; | |
| 1997/0327 | Ether *ether; | |
| 2002/0403 | char buf[128], name[32]; | |
| 1992/0410 | ||
| 2002/0403 | ether = malloc(sizeof(Ether)); memset(ether, 0, sizeof(Ether)); ether->ctlrno = ctlrno; ether->tbdf = BUSUNKNOWN; ether->mbps = 10; ether->minmtu = ETHERMINTU; ether->maxmtu = ETHERMAXTU; if(cardno < 0){ if(isaconfig("ether", ctlrno, ether) == 0){ free(ether); return nil; } for(cardno = 0; cards[cardno].type; cardno++){ if(cistrcmp(cards[cardno].type, ether->type)) | |
| 1993/1113 | continue; | |
| 1997/0327 | for(i = 0; i < ether->nopt; i++){ if(strncmp(ether->opt[i], "ea=", 3)) continue; | |
| 2002/0403 | if(parseether(ether->ea, ðer->opt[i][3])) | |
| 1997/0327 | memset(ether->ea, 0, Eaddrlen); | |
| 2002/0403 | } break; } } | |
| 1992/1222 | ||
| 2002/0403 | if(cardno >= MaxEther || cards[cardno].type == nil){ free(ether); return nil; } if(cards[cardno].reset(ether) < 0){ free(ether); return nil; } | |
| 2000/0817 | ||
| 2002/0403 | /* * IRQ2 doesn't really exist, it's used to gang the interrupt * controllers together. A device set to IRQ2 will appear on * the second interrupt controller as IRQ9. */ if(ether->irq == 2) ether->irq = 9; snprint(name, sizeof(name), "ether%d", ctlrno); | |
| 1993/0212 | ||
| 2002/0403 | /* * If ether->irq is 0, it is a hack to indicate no interrupt * used by ethersink. */ if(ether->irq > 0) intrenable(ether->irq, ether->interrupt, ether, ether->tbdf, name); | |
| 1993/0212 | ||
| 2002/0403 | i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud", ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq); if(ether->mem) i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); if(ether->size) i += sprint(buf+i, " size 0x%luX", ether->size); i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX", ether->ea[0], ether->ea[1], ether->ea[2], ether->ea[3], ether->ea[4], ether->ea[5]); sprint(buf+i, "\n"); print(buf); | |
| 1992/0410 | ||
| 2002/0403 | if(ether->mbps >= 100){ netifinit(ether, name, Ntypes, 256*1024); if(ether->oq == 0) ether->oq = qopen(256*1024, 1, 0, 0); } else{ netifinit(ether, name, Ntypes, 65*1024); if(ether->oq == 0) ether->oq = qopen(65*1024, 1, 0, 0); } if(ether->oq == 0) panic("etherreset %s", name); ether->alen = Eaddrlen; memmove(ether->addr, ether->ea, Eaddrlen); memset(ether->bcast, 0xFF, Eaddrlen); return ether; } static void etherreset(void) { Ether *ether; int cardno, ctlrno; for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ if((ether = etherprobe(-1, ctlrno)) == nil) continue; etherxx[ctlrno] = ether; } | |
| 2002/0502 | if(getconf("*noetherprobe")) return; | |
| 2002/0403 | cardno = ctlrno = 0; while(cards[cardno].type != nil && ctlrno < MaxEther){ if(etherxx[ctlrno] != nil){ ctlrno++; continue; | |
| 1993/1113 | } | |
| 2002/0403 | if((ether = etherprobe(cardno, ctlrno)) == nil){ cardno++; continue; } etherxx[ctlrno] = ether; ctlrno++; | |
| 1992/0403 | } } | |
| 1997/0327 | ||
| 2002/0109 | static void ethershutdown(void) { Ether *ether; int i; for(i = 0; i < MaxEther; i++){ ether = etherxx[i]; if(ether == nil) continue; if(ether->shutdown == nil) { print("#l%d: no shutdown fuction\n", i); continue; } (*ether->shutdown)(ether); } } | |
| 1997/0415 | #define POLY 0xedb88320 /* really slow 32 bit crc for ethers */ ulong ethercrc(uchar *p, int len) { int i, j; ulong crc, b; crc = 0xffffffff; for(i = 0; i < len; i++){ b = *p++; for(j = 0; j < 8; j++){ | |
| 1997/0418 | crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0); | |
| 1997/0415 | b >>= 1; } } return crc; } | |
| 1997/0327 | Dev etherdevtab = { | |
| 1997/0408 | 'l', "ether", | |
| 1997/0327 | etherreset, devinit, | |
| 2002/0109 | ethershutdown, | |
| 1997/0327 | etherattach, etherwalk, etherstat, etheropen, ethercreate, etherclose, etherread, etherbread, etherwrite, etherbwrite, | |
| 2001/1204 | devremove, | |
| 1997/0327 | etherwstat, }; | |