#include "all.h" #include "io.h" #include "mem.h" #include "../ip/ip.h" #include "../dev/aoe.h" #include "etherif.h" #define dprint(...) /* print(__VA_ARGS__) */ Ether etherif[MaxEther]; int nether; void etheriq(Ether* ether, Msgbuf* mb) { ilock(ðer->rqlock); if(ether->rqhead) ether->rqtail->next = mb; else ether->rqhead = mb; ether->rqtail = mb; mb->next = 0; iunlock(ðer->rqlock); wakeup(ðer->rqr); } static int isinput(void* arg) { return ((Ether*)arg)->rqhead != 0; } static void etheri(void) { Ether *ether; Ifc *ifc; Msgbuf *mb; Enpkt *p; ether = u->arg; ifc = ðer->ifc; print("ether%di: %E %I\n", ether->ctlrno, ether->ifc.ea, ether->ifc.ipa); ether->attach(ether); for(;;) { sleep(ðer->rqr, isinput, ether); ilock(ðer->rqlock); if(ether->rqhead == 0) { iunlock(ðer->rqlock); continue; } mb = ether->rqhead; ether->rqhead = mb->next; iunlock(ðer->rqlock); p = (Enpkt*)mb->data; switch(nhgets(p->type)){ case Arptype: arpreceive(p, mb->count, ifc); break; case Cectype: cecreceive(p, mb->count, ifc); break; case Aoetype: aoereceive(p, mb->count, ifc); break; case Iptype: ipreceive(p, mb->count, ifc); break; default: goto done; } ifc->rxpkt++; ifc->work.count++; ifc->rate.count += mb->count; done: mbfree(mb); } } #ifdef no static void ethero(void) { Ether *ether; Ifc *ifc; Msgbuf *mb; int len; ether = u->arg; ifc = ðer->ifc; print("ether%do: %E %I\n", ether->ctlrno, ifc->ea, ifc->ipa); for(;;) { mb = recv(ifc->reply, 1); if(mb == nil) continue; len = mb->count; if(len > ether->ifc.maxmtu){ print("ether%do: pkt too big - %d\n", ether->ctlrno, len); mbfree(mb); continue; } if(len < ETHERMINTU) { memset(mb->data+len, 0, ETHERMINTU-len); mb->count = len = ETHERMINTU; } memmove(((Enpkt*)(mb->data))->s, ifc->ea, sizeof(ifc->ea)); ilock(ðer->tqlock); if(ether->tqhead) ether->tqtail->next = mb; else ether->tqhead = mb; ether->tqtail = mb; mb->next = 0; iunlock(ðer->tqlock); ether->transmit(ether); ifc->work.count++; ifc->rate.count += len; ifc->txpkt++; } } Msgbuf* etheroq(Ether* ether) { Msgbuf *mb; mb = nil; ilock(ðer->tqlock); if(ether->tqhead){ mb = ether->tqhead; ether->tqhead = mb->next; } iunlock(ðer->tqlock); return mb; } #endif /* * look, ma. no extra queue. */ static void ethero(void) { Ether *e; e = u->arg; print("ether%do: %E %I\n", e->ctlrno, e->ifc.ea, e->ifc.ipa); for(;;){ recv(e->ifc.reply, 0); // wait for something to do. e->transmit(e); } } Msgbuf* etheroq(Ether* e) { Msgbuf *m; Enpkt *p; Ifc *f; int len; f = &e->ifc; loop: if(f->reply->count == 0) return 0; m = recv(f->reply, 1); len = m->count; if(len > f->maxmtu){ print("ether%do: pkt too big - %d\n", e->ctlrno, len); mbfree(m); goto loop; } if(len < ETHERMINTU){ memset(m->data+len, 0, ETHERMINTU-len); m->count = len = ETHERMINTU; } p = (Enpkt*)m->data; memmove(p->s, f->ea, sizeof f->ea); f->work.count++; f->rate.count += len; f->txpkt++; return m; } static void cmd_state(int, char*[]) { int i; Ifc *ifc; for(i = 0; i < nether; i++){ if(etherif[i].mbps == 0) continue; ifc = ðerif[i].ifc; print("ether stats %d %E\n", etherif[i].ctlrno, etherif[i].ea); print(" work =%9W pkts\n", &ifc->work); print(" rate =%9W Bps\n", &ifc->rate); print(" err = %3ld rc %3ld sum\n", ifc->rcverr, ifc->sumerr); } } void etherstart(void) { int i; Ifc *ifc, *tail; char buf[100], *p; nether = 0; tail = 0; for(i = 0; i < MaxEther; i++){ if(etherif[i].mbps == 0) continue; ifc = ðerif[i].ifc; lock(ifc); getipa(ifc, etherif[i].ctlrno); if(!isvalidip(ifc->ipa)){ unlock(ifc); etherif[i].mbps = 0; continue; } if(ifc->reply == 0){ dofilter(&ifc->work); dofilter(&ifc->rate); ifc->reply = newqueue(Nqueue); } unlock(ifc); sprint(etherif[i].oname, "ether%do", etherif[i].ctlrno); userinit(ethero, etherif+i, etherif[i].oname); sprint(etherif[i].iname, "ether%di", etherif[i].ctlrno); userinit(etheri, etherif+i, etherif[i].iname); ifc->next = nil; if(enets != nil) tail->next = ifc; else enets = ifc; tail = ifc; nether++; } if(nether){ cmd_install("state", "-- ether stats", cmd_state); arpstart(); if(p = getconf("route")){ snprint(buf, sizeof buf, "route %s", p); cmd_exec(buf); } } } static int parseether(uchar *to, char *from) { char nip[4]; char *p; int i; p = from; while(*p == ' ') ++p; for(i = 0; i < 6; 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; } void etherinit(void) { Ether *e; int i, n, ctlrno; for(ctlrno = 0; ctlrno < MaxEther; ctlrno++){ e = etherif+ctlrno; memset(e, 0, sizeof *e); if(!isaconfig("ether", ctlrno, e)){ dprint("%d: !isaconfig\n", ctlrno); continue; } for(n = 0; n < netherctlr; n++){ if(cistrcmp(etherctlr[n].type, e->type)) continue; dprint("%d: FOUND ether %s\n", ctlrno, etherctlr[n].type); e->ctlrno = ctlrno; e->tbdf = BUSUNKNOWN; e->ifc.maxmtu = ETHERMAXTU; for(i = 0; i < e->nopt; i++){ if(strncmp(e->opt[i], "ea=", 3)) continue; if(parseether(e->ea, &e->opt[i][3]) == -1) memset(e->ea, 0, Easize); } dprint(" reset ... "); if(etherctlr[n].reset(e)){ dprint("fail\n"); break; } dprint("okay\n"); if(e->irq == 2) e->irq = 9; setvec(Int0vec + e->irq, e->interrupt, e); memmove(e->ifc.ea, e->ea, sizeof e->ea); print("ether%d: %s: %dMbps port %#p irq %ld mtu %d", ctlrno, e->type, e->mbps, e->port, e->irq, e->ifc.maxmtu); print(": %E\n", e->ea); break; } } }