123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "pool.h"
- #include "ureg.h"
- #include "../port/error.h"
- #include "../port/netif.h"
- #include "etherif.h"
- static Ether *etherxx[MaxEther];
- Chan*
- etherattach(char* spec)
- {
- ulong ctlrno;
- char *p;
- Chan *chan;
- ctlrno = 0;
- if(spec && *spec){
- ctlrno = strtoul(spec, &p, 0);
- if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther))
- error(Ebadarg);
- }
- if(etherxx[ctlrno] == 0)
- error(Enodev);
- chan = devattach('l', spec);
- if(waserror()){
- chanfree(chan);
- nexterror();
- }
- chan->dev = ctlrno;
- if(etherxx[ctlrno]->attach)
- etherxx[ctlrno]->attach(etherxx[ctlrno]);
- poperror();
- return chan;
- }
- static Walkqid*
- etherwalk(Chan* chan, Chan* nchan, char** name, int nname)
- {
- return netifwalk(etherxx[chan->dev], chan, nchan, name, nname);
- }
- static int
- etherstat(Chan* chan, uchar* dp, int n)
- {
- return netifstat(etherxx[chan->dev], chan, dp, n);
- }
- static Chan*
- etheropen(Chan* chan, int omode)
- {
- return netifopen(etherxx[chan->dev], chan, omode);
- }
- static void
- ethercreate(Chan*, char*, int, ulong)
- {
- }
- static void
- etherclose(Chan* chan)
- {
- netifclose(etherxx[chan->dev], chan);
- }
- static long
- etherread(Chan* chan, void* buf, long n, vlong off)
- {
- Ether *ether;
- ulong offset = off;
- ether = etherxx[chan->dev];
- if((chan->qid.type & QTDIR) == 0 && ether->ifstat){
- /*
- * With some controllers it is necessary to reach
- * into the chip to extract statistics.
- */
- 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);
- }
- return netifread(ether, chan, buf, n, offset);
- }
- static Block*
- etherbread(Chan* chan, long n, ulong offset)
- {
- return netifbread(etherxx[chan->dev], chan, n, offset);
- }
- static int
- etherwstat(Chan* chan, uchar* dp, int n)
- {
- return netifwstat(etherxx[chan->dev], chan, dp, n);
- }
- static void
- etherrtrace(Netfile* f, Etherpkt* pkt, int len)
- {
- int i, n;
- Block *bp;
- if(qwindow(f->in) <= 0)
- return;
- if(len > 58)
- n = 58;
- else
- n = len;
- bp = iallocb(64);
- if(bp == nil)
- return;
- memmove(bp->wp, pkt->d, n);
- i = TK2MS(MACHP(0)->ticks);
- bp->wp[58] = len>>8;
- bp->wp[59] = len;
- bp->wp[60] = i>>24;
- bp->wp[61] = i>>16;
- bp->wp[62] = i>>8;
- bp->wp[63] = i;
- bp->wp += 64;
- qpass(f->in, bp);
- }
- Block*
- etheriq(Ether* ether, Block* bp, int fromwire)
- {
- Etherpkt *pkt;
- ushort type;
- int len, multi, tome, fromme;
- Netfile **ep, *f, **fp, *fx;
- Block *xbp;
- ether->inpackets++;
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- type = (pkt->type[0]<<8)|pkt->type[1];
- fx = 0;
- ep = ðer->f[Ntypes];
- multi = pkt->d[0] & 1;
- /* check for valid multicast addresses */
- if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){
- if(!activemulti(ether, pkt->d, sizeof(pkt->d))){
- if(fromwire){
- freeb(bp);
- bp = 0;
- }
- return bp;
- }
- }
- /* is it for me? */
- tome = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- fromme = memcmp(pkt->s, ether->ea, sizeof(pkt->s)) == 0;
- /*
- * Multiplex the packet to all the connections which want it.
- * If the packet is not to be used subsequently (fromwire != 0),
- * 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++){
- 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)
- fx = f;
- else if(xbp = iallocb(len)){
- memmove(xbp->wp, pkt, len);
- xbp->wp += len;
- if(qpass(f->in, xbp) < 0) {
- print("soverflow for f->in\n");
- ether->soverflows++;
- }
- }
- else {
- print("soverflow iallocb\n");
- ether->soverflows++;
- }
- }
- else
- etherrtrace(f, pkt, len);
- }
- }
- if(fx){
- if(qpass(fx->in, bp) < 0) {
- print("soverflow for fx->in\n");
- ether->soverflows++;
- }
- return 0;
- }
- if(fromwire){
- freeb(bp);
- return 0;
- }
- return bp;
- }
- static int
- etheroq(Ether* ether, Block* bp)
- {
- int len, loopback, s;
- Etherpkt *pkt;
- ether->outpackets++;
- /*
- * 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.
- * To enable bridging to work, only packets that were originated
- * by this interface are fed back.
- */
- pkt = (Etherpkt*)bp->rp;
- len = BLEN(bp);
- loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
- if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){
- s = splhi();
- etheriq(ether, bp, 0);
- splx(s);
- }
- if(!loopback){
- if(qfull(ether->oq))
- print("etheroq: WARNING: ether->oq full!\n");
- qbwrite(ether->oq, bp);
- if(ether->transmit != nil)
- ether->transmit(ether);
- } else
- freeb(bp);
- return len;
- }
- static long
- etherwrite(Chan* chan, void* buf, long n, vlong)
- {
- Ether *ether;
- Block *bp;
- int nn, onoff;
- Cmdbuf *cb;
- ether = etherxx[chan->dev];
- if(NETTYPE(chan->qid.path) != Ndataqid) {
- nn = netifwrite(ether, chan, buf, n);
- if(nn >= 0)
- return nn;
- cb = parsecmd(buf, n);
- if(cb->f[0] && strcmp(cb->f[0], "nonblocking") == 0){
- if(cb->nf <= 1)
- onoff = 1;
- else
- onoff = atoi(cb->f[1]);
- qnoblock(ether->oq, onoff);
- free(cb);
- return n;
- }
- free(cb);
- if(ether->ctl!=nil)
- return ether->ctl(ether,buf,n);
- error(Ebadctl);
- }
- if(n > ether->maxmtu)
- error(Etoobig);
- if(n < ether->minmtu)
- error(Etoosmall);
- bp = allocb(n);
- if(waserror()){
- freeb(bp);
- nexterror();
- }
- memmove(bp->rp, buf, n);
- memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen);
- poperror();
- bp->wp += n;
- return etheroq(ether, bp);
- }
- static long
- etherbwrite(Chan* chan, Block* bp, ulong)
- {
- Ether *ether;
- long n;
- n = BLEN(bp);
- if(NETTYPE(chan->qid.path) != Ndataqid){
- if(waserror()) {
- freeb(bp);
- nexterror();
- }
- n = etherwrite(chan, bp->rp, n, 0);
- poperror();
- freeb(bp);
- return n;
- }
- ether = etherxx[chan->dev];
- if(n > ether->maxmtu){
- freeb(bp);
- error(Etoobig);
- }
- if(n < ether->minmtu){
- freeb(bp);
- error(Etoosmall);
- }
- return etheroq(ether, bp);
- }
- static struct {
- char* type;
- int (*reset)(Ether*);
- } cards[MaxEther+1];
- void
- addethercard(char* t, int (*r)(Ether*))
- {
- static int ncard;
- if(ncard == MaxEther)
- panic("too many ether cards");
- cards[ncard].type = t;
- cards[ncard].reset = r;
- ncard++;
- }
- int
- parseether(uchar *to, char *from)
- {
- char nip[4];
- char *p;
- int i;
- p = from;
- for(i = 0; i < Eaddrlen; i++){
- 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;
- }
- static Ether*
- etherprobe(int cardno, int ctlrno)
- {
- int i, lg;
- ulong mb, bsz;
- Ether *ether;
- char buf[128], name[32];
- 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))
- continue;
- for(i = 0; i < ether->nopt; i++){
- if(strncmp(ether->opt[i], "ea=", 3))
- continue;
- if(parseether(ether->ea, ðer->opt[i][3]))
- memset(ether->ea, 0, Eaddrlen);
- }
- break;
- }
- }
- if(cardno >= MaxEther || cards[cardno].type == nil){
- free(ether);
- return nil;
- }
- if(cards[cardno].reset(ether) < 0){
- free(ether);
- return nil;
- }
- /*
- * 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);
- /*
- * 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);
- i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d",
- ctlrno, cards[cardno].type, ether->mbps, ether->port, ether->irq);
- if(ether->mem)
- i += sprint(buf+i, " addr 0x%luX", 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);
- /* compute log10(ether->mbps) into lg */
- for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
- mb /= 10;
- if (lg > 0)
- lg--;
- if (lg > 14) /* 2^(14+17) = 2ⁱ */
- lg = 14;
- /* allocate larger output queues for higher-speed interfaces */
- bsz = 1UL << (lg + 17); /* 2ⁱ⁷ = 128K, bsz = 2ⁿ × 128K */
- while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
- bsz /= 2;
- netifinit(ether, name, Ntypes, bsz);
- if(ether->oq == nil) {
- ether->oq = qopen(bsz, Qmsg, 0, 0);
- ether->limit = bsz;
- }
- if(ether->oq == nil)
- panic("etherreset %s: can't allocate output queue of %ld bytes",
- name, bsz);
- 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;
- }
- if(getconf("*noetherprobe"))
- return;
- cardno = ctlrno = 0;
- while(cards[cardno].type != nil && ctlrno < MaxEther){
- if(etherxx[ctlrno] != nil){
- ctlrno++;
- continue;
- }
- if((ether = etherprobe(cardno, ctlrno)) == nil){
- cardno++;
- continue;
- }
- etherxx[ctlrno] = ether;
- ctlrno++;
- }
- }
- 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);
- }
- }
- #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++){
- crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0);
- b >>= 1;
- }
- }
- return crc;
- }
- Dev etherdevtab = {
- 'l',
- "ether",
- etherreset,
- devinit,
- ethershutdown,
- etherattach,
- etherwalk,
- etherstat,
- etheropen,
- ethercreate,
- etherclose,
- etherread,
- etherbread,
- etherwrite,
- etherbwrite,
- devremove,
- etherwstat,
- };
|