Start bringing networking back in
authorRonald G. Minnich <rminnich@google.com>
Mon, 20 Jan 2014 16:53:21 +0000 (08:53 -0800)
committerRonald G. Minnich <rminnich@google.com>
Mon, 20 Jan 2014 16:53:51 +0000 (08:53 -0800)
breaks build. But we gotta have it.

Signed-off-by: Ronald G. Minnich <rminnich@google.com>
kern/drivers/dev/Kbuild
kern/drivers/dev/ether.c [new file with mode: 0644]
kern/drivers/dev/netif.c [new file with mode: 0644]
kern/include/ip.h
kern/include/ns.h

index c60d5cb..c1d1607 100644 (file)
@@ -1,7 +1,9 @@
 obj-y                                          += alarm.o
 obj-y                                          += cons.o
 obj-y                                          += dev.o
+obj-y                                          += ether.o
 obj-y                                          += mnt.o
+obj-y                                          += netif.o
 obj-y                                          += root.o
 obj-y                                          += tab.o
 obj-y                                          += vm.o
diff --git a/kern/drivers/dev/ether.c b/kern/drivers/dev/ether.c
new file mode 100644 (file)
index 0000000..f600139
--- /dev/null
@@ -0,0 +1,803 @@
+// INFERNO
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+enum {
+       Type8021Q=      0x8100, /* value of type field for 802.1[pQ] tags */
+};
+
+static struct ether *etherxx[MaxEther];        /* real controllers */
+static struct ether*   vlanalloc(struct ether*, int);
+static void    vlanoq(struct ether*, struct block*);
+
+struct chan*
+etherattach(char* spec)
+{
+       ERRSTACK(2);
+       uint32_t ctlrno;
+       char *p;
+       struct chan *chan;
+       struct ether *ether, *vlan;
+       int vlanid;
+
+       ctlrno = 0;
+       vlanid = 0;
+       if(spec && *spec){
+               ctlrno = strtoul(spec, &p, 0);
+               /* somebody interpret this for me. */
+               if((ctlrno == 0) && (p == spec) || (ctlrno >= MaxEther) || (*p) && (*p != '.'))
+                       error(Ebadarg);
+               if(*p == '.'){  /* vlan */
+                       vlanid = strtoul(p+1, &p, 0);
+                       if(vlanid <= 0 || vlanid > 0xFFF || *p)
+                               error(Ebadarg);
+               }
+       }
+       if((ether = etherxx[ctlrno]) == 0)
+               error(Enodev);
+       rlock(&ether->rwlock);
+       if(waserror()){
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       if(vlanid){
+               if(ether->maxmtu < ETHERMAXTU+4)
+                       error("interface cannot support 802.1 tags");
+               vlan = vlanalloc(ether, vlanid);
+               chan = devattach('l', spec);
+               chan->dev = ctlrno  + (vlanid<<8);
+               chan->aux = vlan;
+               poperror();
+               runlock(&ether->rwlock);
+               return chan;
+       }
+       chan = devattach('l', spec);
+       chan->dev = ctlrno;
+       chan->aux = ether;
+       if(ether->attach)
+               ether->attach(ether);
+       poperror();
+       runlock(&ether->rwlock);
+       return chan;
+}
+
+static void
+ethershutdown(void)
+{
+       struct ether *ether;
+       int i;
+
+       for(i=0; i<MaxEther; i++){
+               ether = etherxx[i];
+               if(ether != NULL && ether->detach != NULL)
+                       ether->detach(ether);
+       }
+}
+
+static struct walkqid*
+etherwalk(struct chan* chan, struct chan *nchan, char **name, int nname)
+{
+       ERRSTACK(2);
+       struct walkqid *wq;
+       struct ether *ether;
+
+       ether = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       wq = netifwalk(&ether->netif, chan, nchan, name, nname);
+       if(wq && wq->clone != NULL && wq->clone != chan)
+               wq->clone->aux = ether;
+       poperror();
+       runlock(&ether->rwlock);
+       return wq;
+}
+
+static int
+etherstat(struct chan* chan, uint8_t* dp, int n)
+{
+       ERRSTACK(2);
+       int s;
+       struct ether *ether;
+
+       ether = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       s = netifstat(&ether->netif, chan, dp, n);
+       poperror();
+       runlock(&ether->rwlock);
+       return s;
+}
+
+static struct chan*
+etheropen(struct chan* chan, int omode)
+{
+       ERRSTACK(2);
+       struct chan *c;
+       struct ether *ether;
+
+       ether = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       c = netifopen(&ether->netif, chan, omode);
+       poperror();
+       runlock(&ether->rwlock);
+       return c;
+}
+
+static void
+etherclose(struct chan* chan)
+{
+       ERRSTACK(2);
+       struct ether *ether;
+
+       ether = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       netifclose(&ether->netif, chan);
+       poperror();
+       runlock(&ether->rwlock);
+}
+
+static long
+etherread(struct chan* chan, void* buf, long n, int64_t off)
+{
+       ERRSTACK(2);
+       struct ether *ether;
+       uint32_t offset = off;
+       long r;
+
+       ether = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       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){
+                       r = ether->ifstat(ether, buf, n, offset);
+                       goto out;
+               }
+               if(NETTYPE(chan->qid.path) == Nstatqid)
+                       ether->ifstat(ether, buf, 0, offset);
+       }
+       r = netifread(&ether->netif, chan, buf, n, offset);
+out:
+       poperror();
+       runlock(&ether->rwlock);
+       return r;
+}
+
+static struct block*
+etherbread(struct chan* chan, long n, uint32_t offset)
+{
+       ERRSTACK(2);
+       struct block *b;
+       struct ether *ether;
+
+       ether = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       b = netifbread(&ether->netif, chan, n, offset);
+       poperror();
+       runlock(&ether->rwlock);
+       return b;
+}
+
+static int
+etherwstat(struct chan* chan, uint8_t* dp, int n)
+{
+       ERRSTACK(2);
+       struct ether *ether;
+       int r;
+
+       ether = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       r = netifwstat(&ether->netif, chan, dp, n);
+       poperror();
+       runlock(&ether->rwlock);
+       return r;
+}
+
+static void
+etherrtrace(struct netfile* f, struct etherpkt* pkt, int len)
+{
+       int i, n;
+       struct block *bp;
+
+       if(qwindow(f->in) <= 0)
+               return;
+       if(len > 58)
+               n = 58;
+       else
+               n = len;
+       bp = iallocb(64);
+       if(bp == NULL)
+               return;
+       memmove(bp->wp, pkt->d, n);
+       i = milliseconds();
+       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);
+}
+
+struct block*
+etheriq(struct ether* ether, struct block* bp, int fromwire)
+{
+       struct etherpkt *pkt;
+       uint16_t type;
+       int len, multi, tome, fromme, vlanid, i;
+       struct netfile **ep, *f, **fp, *fx;
+       struct block *xbp;
+       struct ether *vlan;
+
+       ether->netif.inpackets++;
+
+       pkt = (struct etherpkt*)bp->rp;
+       len = BLEN(bp);
+       type = (pkt->type[0]<<8)|pkt->type[1];
+       if(type == Type8021Q && ether->nvlan){
+               vlanid = nhgets(bp->rp+2*Eaddrlen+2) & 0xFFF;
+               if(vlanid){
+                       for(i = 0; i < ARRAY_SIZE(ether->vlans); i++){
+                               vlan = ether->vlans[i];
+                               if(vlan != NULL && vlan->vlanid == vlanid){
+                                       memmove(bp->rp+4, bp->rp, 2*Eaddrlen);
+                                       bp->rp += 4;
+                                       return etheriq(vlan, bp, fromwire);
+                               }
+                       }
+                       /* allow normal type handling to accept or discard it */
+               }
+       }
+
+       fx = 0;
+       ep = &ether->netif.f[Ntypes];
+
+       multi = pkt->d[0] & 1;
+       /* check for valid multcast addresses */
+       if(multi && memcmp(pkt->d, ether->netif.bcast, sizeof(pkt->d)) != 0 && ether->netif.prom == 0){
+               if(!activemulti(&ether->netif, 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->netif.f; fp < ep; fp++){
+               if((f = *fp) && (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)
+                                               ether->netif.soverflows++;
+                               }
+                               else
+                                       ether->netif.soverflows++;
+                       }
+                       else
+                               etherrtrace(f, pkt, len);
+               }
+       }
+
+       if(fx){
+               if(qpass(fx->in, bp) < 0)
+                       ether->netif.soverflows++;
+               return 0;
+       }
+       if(fromwire){
+               freeb(bp);
+               return 0;
+       }
+
+       return bp;
+}
+
+static int
+etheroq(struct ether* ether, struct block* bp)
+{
+       int len, loopback, s;
+       struct etherpkt *pkt;
+
+       ether->netif.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 = (struct etherpkt*)bp->rp;
+       len = BLEN(bp);
+       loopback = memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0;
+       if(loopback || memcmp(pkt->d, ether->netif.bcast, sizeof(pkt->d)) == 0 || ether->netif.prom){
+               s = splhi();
+               etheriq(ether, bp, 0);
+               splx(s);
+       }
+
+       if(!loopback){
+               if(ether->vlanid){
+                       /* add tag */
+                       bp = padblock(bp, 2+2);
+                       memmove(bp->rp, bp->rp+4, 2*Eaddrlen);
+                       hnputs(bp->rp+2*Eaddrlen, Type8021Q);
+                       hnputs(bp->rp+2*Eaddrlen+2, ether->vlanid & 0xFFF);     /* prio:3 0:1 vid:12 */
+                       ether = ether->ctlr;
+               }
+               qbwrite(ether->oq, bp);
+               if(ether->transmit != NULL)
+                       ether->transmit(ether);
+       }else
+               freeb(bp);
+
+       return len;
+}
+
+static long
+etherwrite(struct chan* chan, void* buf, long n, int64_t unused)
+{
+       ERRSTACK(2);
+       struct ether *ether;
+       struct block *bp;
+       int onoff;
+       struct cmdbuf *cb;
+       long l;
+
+       ether = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       if(NETTYPE(chan->qid.path) != Ndataqid) {
+               l = netifwrite(&ether->netif, chan, buf, n);
+               if(l >= 0)
+                       goto out;
+               cb = parsecmd(buf, n);
+               if(strcmp(cb->f[0], "nonblocking") == 0){
+                       if(cb->nf <= 1)
+                               onoff = 1;
+                       else
+                               onoff = atoi(cb->f[1]);
+                       if(ether->oq != NULL)
+                               qnoblock(ether->oq, onoff);
+                       kfree(cb);
+                       goto out;
+               }
+               kfree(cb);
+               if(ether->ctl!=NULL){
+                       l = ether->ctl(ether,buf,n);
+                       goto out;
+               }
+               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);
+       bp->wp += n;
+       poperror();
+
+       l = etheroq(ether, bp);
+out:
+       poperror();
+       runlock(&ether->rwlock);
+       return l;
+}
+
+static long
+etherbwrite(struct chan* chan, struct block* bp, uint32_t unused)
+{
+       ERRSTACK(2);
+       struct 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 = chan->aux;
+       rlock(&ether->rwlock);
+       if(waserror()) {
+               runlock(&ether->rwlock);
+               nexterror();
+       }
+       if(n > ether->maxmtu){
+               freeb(bp);
+               error(Etoobig);
+       }
+       if(n < ether->minmtu){
+               freeb(bp);
+               error(Etoosmall);
+       }
+       n = etheroq(ether, bp);
+       poperror();
+       runlock(&ether->rwlock);
+       return n;
+}
+
+static void
+nop(struct ether*unused)
+{
+}
+
+static long
+vlanctl(struct ether *ether, void *buf, long n)
+{
+       uint8_t ea[Eaddrlen];
+       struct ether *master;
+       struct cmdbuf *cb;
+       int i;
+
+       cb = parsecmd(buf, n);
+       if(cb->nf >= 2
+       && strcmp(cb->f[0], "ea")==0
+       && parseether(ea, cb->f[1]) == 0){
+               kfree(cb);
+               memmove(ether->ea, ea, Eaddrlen);
+               memmove(ether->netif.addr, ether->ea, Eaddrlen);
+               return 0;
+       }
+       if(cb->nf == 1 && strcmp(cb->f[0], "disable") == 0){
+               master = ether->ctlr;
+               qlock(&master->vlq);
+               for(i = 0; i < ARRAY_SIZE(master->vlans); i++)
+                       if(master->vlans[i] == ether){
+                               ether->vlanid = 0;
+                               master->nvlan--;
+                               break;
+                       }
+               qunlock(&master->vlq);
+               kfree(cb);
+               return 0;
+       }
+       kfree(cb);
+       error(Ebadctl);
+       return -1;      /* not reached */
+}
+
+static struct ether*
+vlanalloc(struct ether *ether, int id)
+{
+       ERRSTACK(2);
+       struct ether *vlan;
+       int i, fid;
+       char name[KNAMELEN];
+
+       qlock(&ether->vlq);
+       if(waserror()){
+               qunlock(&ether->vlq);
+               nexterror();
+       }
+       fid = -1;
+       for(i = 0; i < ARRAY_SIZE(ether->vlans); i++){
+               vlan = ether->vlans[i];
+               if(vlan != NULL && vlan->vlanid == id){
+                       poperror();
+                       qunlock(&ether->vlq);
+                       return vlan;
+               }
+               if(fid < 0 && (vlan == NULL || vlan->vlanid == 0))
+                       fid = i;
+       }
+       if(fid < 0)
+               error(Enoifc);
+       snprintf(name, sizeof(name), "ether%d.%d", ether->ctlrno, id);
+       vlan = ether->vlans[fid];
+       if(vlan == NULL){
+               vlan = kzmalloc(sizeof(struct ether), 1);
+               if(vlan == NULL)
+                       error(Enovmem);
+               netifinit(&vlan->netif, name, Ntypes, ether->netif.limit);
+               ether->vlans[fid] = vlan;       /* id is still zero, can't be matched */
+               ether->nvlan++;
+       }else
+               memmove(vlan->netif.name, name, KNAMELEN-1);
+#warning "fix me setting up vlans"
+#if 0
+       vlan->attach = nop;
+       vlan->transmit = NULL;
+       vlan->ctl = vlanctl;
+       vlan->irq = -1;
+//     vlan->promiscuous = ether->promiscuous;
+//     vlan->multicast = ether->multicast;
+       vlan->arg = vlan;
+       vlan->mbps = ether->mbps;
+       vlan->fullduplex = ether->fullduplex;
+       vlan->encry = ether->encry;
+       vlan->minmtu = ether->minmtu;
+       vlan->maxmtu = ether->maxmtu;
+       vlan->ctlrno = ether->ctlrno;
+       vlan->vlanid = id;
+       vlan->alen = Eaddrlen;
+       memmove(vlan->addr, ether->addr, sizeof(vlan->addr));
+       memmove(vlan->bcast, ether->bcast, sizeof(ether->bcast));
+       vlan->oq = NULL;
+       vlan->ctlr = ether;
+       vlan->vlanid = id;
+#endif
+       poperror();
+       qunlock(&ether->vlq);
+       return vlan;
+}
+
+static struct {
+       char*   type;
+       int     (*reset)(struct ether*);
+} cards[MaxEther+1];
+
+void
+addethercard(char* t, int (*r)(struct ether*))
+{
+       static int ncard;
+
+       if(ncard == MaxEther)
+               panic("too many ether cards");
+       cards[ncard].type = t;
+       cards[ncard].reset = r;
+       ncard++;
+}
+
+int
+parseether(uint8_t *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 void
+etherreset(void)
+{
+#warning "fix me etherreset"
+#if 0
+       struct ether *ether;
+       int i, n, ctlrno;
+       char name[KNAMELEN], buf[128];
+
+       for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){
+               if(ether == 0)
+                       ether = kzmalloc(sizeof(struct ether), 0);
+               memset(ether, 0, sizeof(struct ether));
+               ether->ctlrno = ctlrno;
+               ether->netif.mbps = 10;
+               ether->minmtu = ETHERMINTU;
+               ether->maxmtu = ETHERMAXTU;
+               ether->netif.itype = -1;
+
+               if(archether(ctlrno, ether) <= 0)
+                       continue;
+
+               for(n = 0; cards[n].type; n++){
+                       if(cistrcmp(cards[n].type, ether->type))
+                               continue;
+                       for(i = 0; i < ether->nopt; i++){
+                               if(cistrncmp(ether->opt[i], "ea=", 3) == 0){
+                                       if(parseether(ether->ea, &ether->opt[i][3]) == -1)
+                                               memset(ether->ea, 0, Eaddrlen);
+                               }else if(cistrcmp(ether->opt[i], "fullduplex") == 0 ||
+                                       cistrcmp(ether->opt[i], "10BASE-TFD") == 0)
+                                       ether->fullduplex = 1;
+                               else if(cistrcmp(ether->opt[i], "100BASE-TXFD") == 0)
+                                       ether->mbps = 100;
+                       }
+                       if(cards[n].reset(ether))
+                               break;
+                       snprintf(name, sizeof(name), "ether%d", ctlrno);
+
+                       if(ether->interrupt != NULL)
+                               intrenable(ether->itype, ether->irq, ether->interrupt, ether, name);
+
+                       i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %lud",
+                               ctlrno, ether->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");
+                       iprint(buf);
+
+                       if(ether->mbps == 100){
+                               netifinit(ether, name, Ntypes, 256*1024);
+                               if(ether->oq == 0)
+                                       ether->oq = qopen(256*1024, Qmsg, 0, 0);
+                       }
+                       else{
+                               netifinit(ether, name, Ntypes, 64*1024);
+                               if(ether->oq == 0)
+                                       ether->oq = qopen(64*1024, Qmsg, 0, 0);
+                       }
+                       if(ether->oq == 0)
+                               panic("etherreset %s", name);
+                       ether->alen = Eaddrlen;
+                       memmove(ether->addr, ether->ea, Eaddrlen);
+                       memset(ether->bcast, 0xFF, Eaddrlen);
+
+                       etherxx[ctlrno] = ether;
+                       ether = 0;
+                       break;
+               }
+       }
+       if(ether)
+               kfree(ether);
+#endif
+}
+
+static void
+etherpower(int on)
+{
+       int i;
+       struct ether *ether;
+
+       for(i = 0; i < MaxEther; i++){
+               if((ether = etherxx[i]) == NULL || ether->power == NULL)
+                       continue;
+               if(on){
+                       if(canrlock(&ether->rwlock))
+                               continue;
+                       if(ether->power != NULL)
+                               ether->power(ether, on);
+                       wunlock(&ether->rwlock);
+               }else{
+#warning "what is this eraders stuff? (rwlock FIX ME )"
+/*
+                       if(ether->readers)
+                               continue;
+*/
+                       wlock(&ether->rwlock);
+                       if(ether->power != NULL)
+                               ether->power(ether, on);
+                       /* Keep locked until power goes back on */
+               }
+       }
+}
+
+#define ETHERPOLY 0xedb88320
+
+/* really slow 32 bit crc for ethers */
+uint32_t
+ethercrc(uint8_t *p, int len)
+{
+       int i, j;
+       uint32_t crc, b;
+
+       crc = 0xffffffff;
+       for(i = 0; i < len; i++){
+               b = *p++;
+               for(j = 0; j < 8; j++){
+                       crc = (crc>>1) ^ (((crc^b) & 1) ? ETHERPOLY : 0);
+                       b >>= 1;
+               }
+       }
+       return crc;
+}
+
+struct dev etherdevtab = {
+       'l',
+       "ether",
+
+       etherreset,
+       devinit,
+       ethershutdown,
+       etherattach,
+       etherwalk,
+       etherstat,
+       etheropen,
+       devcreate,
+       etherclose,
+       etherread,
+       etherbread,
+       etherwrite,
+       etherbwrite,
+       devremove,
+       etherwstat,
+       etherpower,
+};
diff --git a/kern/drivers/dev/netif.c b/kern/drivers/dev/netif.c
new file mode 100644 (file)
index 0000000..f7c69fc
--- /dev/null
@@ -0,0 +1,680 @@
+// INFERNO
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+static int netown(struct netfile*, char *unused_char_p_t, int);
+static int openfile(struct netif*, int);
+static char* matchtoken( char *unused_char_p_t, char*);
+static char* netmulti(struct netif*, struct netfile*, uint8_t *unused_uint8_p_t, int);
+static int parseaddr( uint8_t *unused_uint8_p_t, char *unused_char_p_t, int);
+
+/*
+ *  set up a new network interface
+ */
+void
+netifinit(struct netif *nif, char *name, int nfile, uint32_t limit)
+{
+       strncpy(nif->name, name, KNAMELEN-1);
+       nif->name[KNAMELEN-1] = 0;
+       nif->nfile = nfile;
+       nif->f = kzmalloc(nfile * sizeof(struct netfile *), 0);
+       if(nif->f)
+               memset(nif->f, 0, nfile*sizeof(struct netfile*));
+       else
+               nif->nfile = 0;
+       nif->limit = limit;
+}
+
+/*
+ *  generate a 3 level directory
+ */
+static int
+netifgen(struct chan *c, char *unused_char_p_t, struct dirtab *vp, int unused_int, int i, struct dir *dp)
+{
+       struct qid q;
+       struct netif *nif = (struct netif*)vp;
+       struct netfile *f;
+       int t;
+       int perm;
+       char *o;
+
+       q.type = QTFILE;
+       q.vers = 0;
+
+       /* top level directory contains the name of the network */
+       if(c->qid.path == 0){
+               switch(i){
+               case DEVDOTDOT:
+                       q.path = 0;
+                       q.type = QTDIR;
+                       devdir(c, q, ".", 0, eve, 0555, dp);
+                       break;
+               case 0:
+                       q.path = N2ndqid;
+                       q.type = QTDIR;
+                       strncpy(up->genbuf,  nif->name, sizeof(up->genbuf));
+                       devdir(c, q, up->genbuf, 0, eve, 0555, dp);
+                       break;
+               default:
+                       return -1;
+               }
+               return 1;
+       }
+
+       /* second level contains clone plus all the conversations */
+       t = NETTYPE(c->qid.path);
+       if(t == N2ndqid || t == Ncloneqid || t == Naddrqid){
+               switch(i) {
+               case DEVDOTDOT:
+                       q.type = QTDIR;
+                       q.path = 0;
+                       devdir(c, q, ".", 0, eve, DMDIR|0555, dp);
+                       break;
+               case 0:
+                       q.path = Ncloneqid;
+                       devdir(c, q, "clone", 0, eve, 0666, dp);
+                       break;
+               case 1:
+                       q.path = Naddrqid;
+                       devdir(c, q, "addr", 0, eve, 0666, dp);
+                       break;
+               case 2:
+                       q.path = Nstatqid;
+                       devdir(c, q, "stats", 0, eve, 0444, dp);
+                       break;
+               case 3:
+                       q.path = Nifstatqid;
+                       devdir(c, q, "ifstats", 0, eve, 0444, dp);
+                       break;
+               default:
+                       i -= 4;
+                       if(i >= nif->nfile)
+                               return -1;
+                       if(nif->f[i] == 0)
+                               return 0;
+                       q.type = QTDIR;
+                       q.path = NETQID(i, N3rdqid);
+                       sprint(up->genbuf, "%d", i);
+                       devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
+                       break;
+               }
+               return 1;
+       }
+
+       /* third level */
+       f = nif->f[NETID(c->qid.path)];
+       if(f == 0)
+               return 0;
+       if(*f->owner){
+               o = f->owner;
+               perm = f->mode;
+       } else {
+               o = eve;
+               perm = 0666;
+       }
+       switch(i){
+       case DEVDOTDOT:
+               q.type = QTDIR;
+               q.path = N2ndqid;
+               strncpy(up->genbuf,  nif->name, sizeof(up->genbuf));
+               devdir(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
+               break;
+       case 0:
+               q.path = NETQID(NETID(c->qid.path), Ndataqid);
+               devdir(c, q, "data", 0, o, perm, dp);
+               break;
+       case 1:
+               q.path = NETQID(NETID(c->qid.path), Nctlqid);
+               devdir(c, q, "ctl", 0, o, perm, dp);
+               break;
+       case 2:
+               q.path = NETQID(NETID(c->qid.path), Nstatqid);
+               devdir(c, q, "stats", 0, eve, 0444, dp);
+               break;
+       case 3:
+               q.path = NETQID(NETID(c->qid.path), Ntypeqid);
+               devdir(c, q, "type", 0, eve, 0444, dp);
+               break;
+       case 4:
+               q.path = NETQID(NETID(c->qid.path), Nifstatqid);
+               devdir(c, q, "ifstats", 0, eve, 0444, dp);
+               break;
+       default:
+               return -1;
+       }
+       return 1;
+}
+
+struct walkqid*
+netifwalk(struct netif *nif, struct chan *c, struct chan *nc, char **name, int nname)
+{
+       return devwalk(c, nc, name, nname, (struct dirtab *)nif, 0, netifgen);
+}
+
+struct chan*
+netifopen(struct netif *nif, struct chan *c, int omode)
+{
+       int id;
+       struct netfile *f;
+
+       id = 0;
+       if(c->qid.type & QTDIR){
+               if(omode != OREAD)
+                       error(Eperm);
+       } else {
+               switch(NETTYPE(c->qid.path)){
+               case Ndataqid:
+               case Nctlqid:
+                       id = NETID(c->qid.path);
+                       openfile(nif, id);
+                       break;
+               case Ncloneqid:
+                       id = openfile(nif, -1);
+                       c->qid.path = NETQID(id, Nctlqid);
+                       break;
+               default:
+                       if(omode != OREAD)
+                               error(Ebadarg);
+               }
+               switch(NETTYPE(c->qid.path)){
+               case Ndataqid:
+               case Nctlqid:
+                       f = nif->f[id];
+                       if(netown(f, up->env->user, omode&7) < 0)
+                               error(Eperm);
+                       break;
+               }
+       }
+       c->mode = openmode(omode);
+       c->flag |= COPEN;
+       c->offset = 0;
+       c->iounit = qiomaxatomic;
+       return c;
+}
+
+long
+netifread(struct netif *nif, struct chan *c, void *a, long n, uint32_t offset)
+{
+       int i, j;
+       struct netfile *f;
+       char *p;
+
+       if(c->qid.type&QTDIR)
+               return devdirread(c, a, n, (struct dirtab*)nif, 0, netifgen);
+
+       switch(NETTYPE(c->qid.path)){
+       case Ndataqid:
+               f = nif->f[NETID(c->qid.path)];
+               return qread(f->in, a, n);
+       case Nctlqid:
+               return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
+       case Nstatqid:
+               p = kzmalloc(READSTR, 0);
+               if(p == NULL)
+                       return 0;
+               j = snprintf(p, READSTR, "in: %d\n", nif->inpackets);
+               j += snprintf(p+j, READSTR-j, "link: %d\n", nif->link);
+               j += snprintf(p+j, READSTR-j, "out: %d\n", nif->outpackets);
+               j += snprintf(p+j, READSTR-j, "crc errs: %d\n", nif->crcs);
+               j += snprintf(p+j, READSTR-j, "overflows: %d\n", nif->overflows);
+               j += snprintf(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows);
+               j += snprintf(p+j, READSTR-j, "framing errs: %d\n", nif->frames);
+               j += snprintf(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs);
+               j += snprintf(p+j, READSTR-j, "output errs: %d\n", nif->oerrs);
+               j += snprintf(p+j, READSTR-j, "prom: %d\n", nif->prom);
+               j += snprintf(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
+               j += snprintf(p+j, READSTR-j, "addr: ");
+               for(i = 0; i < nif->alen; i++)
+                       j += snprintf(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
+               snprintf(p+j, READSTR-j, "\n");
+               n = readstr(offset, a, n, p);
+               kfree(p);
+               return n;
+       case Naddrqid:
+               p = kzmalloc(READSTR, 0);
+               if(p == NULL)
+                       return 0;
+               j = 0;
+               for(i = 0; i < nif->alen; i++)
+                       j += snprintf(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
+               n = readstr(offset, a, n, p);
+               kfree(p);
+               return n;
+       case Ntypeqid:
+               f = nif->f[NETID(c->qid.path)];
+               return readnum(offset, a, n, f->type, NUMSIZE);
+       case Nifstatqid:
+               return 0;
+       }
+       error(Ebadarg);
+       return -1;      /* not reached */
+}
+
+struct block*
+netifbread(struct netif *nif, struct chan *c, long n, uint32_t offset)
+{
+       if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
+               return devbread(c, n, offset);
+
+       return qbread(nif->f[NETID(c->qid.path)]->in, n);
+}
+
+/*
+ *  make sure this type isn't already in use on this device
+ */
+static int
+typeinuse(struct netif *nif, int type)
+{
+       struct netfile *f, **fp, **efp;
+
+       if(type <= 0)
+               return 0;
+
+       efp = &nif->f[nif->nfile];
+       for(fp = nif->f; fp < efp; fp++){
+               f = *fp;
+               if(f == 0)
+                       continue;
+               if(f->type == type)
+                       return 1;
+       }
+       return 0;
+}
+
+/*
+ *  the devxxx.c that calls us handles writing data, it knows best
+ */
+long
+netifwrite(struct netif *nif, struct chan *c, void *a, long n)
+{
+       ERRSTACK(2);
+       struct netfile *f;
+       int type;
+       char *p, buf[64];
+       uint8_t binaddr[Nmaxaddr];
+
+       if(NETTYPE(c->qid.path) != Nctlqid)
+               error(Eperm);
+
+       if(n >= sizeof(buf))
+               n = sizeof(buf)-1;
+       memmove(buf, a, n);
+       buf[n] = 0;
+
+       if(waserror()){
+               qunlock(&nif->qlock);
+               nexterror();
+       }
+
+       qlock(&nif->qlock);
+       f = nif->f[NETID(c->qid.path)];
+       if((p = matchtoken(buf, "connect")) != 0){
+               type = atoi(p);
+               if(typeinuse(nif, type))
+                       error(Einuse);
+               f->type = type;
+               if(f->type < 0)
+                       nif->all++;
+       } else if(matchtoken(buf, "promiscuous")){
+               if(f->prom == 0){
+                       if(nif->prom == 0 && nif->promiscuous != NULL)
+                               nif->promiscuous(nif->arg, 1);
+                       f->prom = 1;
+                       nif->prom++;
+               }
+       } else if((p = matchtoken(buf, "scanbs")) != 0){
+               /* scan for base stations */
+               if(f->scan == 0){
+                       type = atoi(p);
+                       if(type < 5)
+                               type = 5;
+                       if(nif->scanbs != NULL)
+                               nif->scanbs(nif->arg, type);
+                       f->scan = type;
+                       nif->scan++;
+               }
+       } else if(matchtoken(buf, "bridge")){
+               f->bridge = 1;
+       } else if(matchtoken(buf, "headersonly")){
+               f->headersonly = 1;
+       } else if((p = matchtoken(buf, "addmulti")) != 0){
+               if(parseaddr(binaddr, p, nif->alen) < 0)
+                       error("bad address");
+               p = netmulti(nif, f, binaddr, 1);
+               if(p)
+                       error(p);
+       } else if((p = matchtoken(buf, "remmulti")) != 0){
+               if(parseaddr(binaddr, p, nif->alen) < 0)
+                       error("bad address");
+               p = netmulti(nif, f, binaddr, 0);
+               if(p)
+                       error(p);
+       } else
+               n = -1;
+       qunlock(&nif->qlock);
+       poperror();
+       return n;
+}
+
+int
+netifwstat(struct netif *nif, struct chan *c, uint8_t *db, int n)
+{
+       struct dir *dir;
+       struct netfile *f;
+       int m;
+
+       f = nif->f[NETID(c->qid.path)];
+       if(f == 0)
+               error(Enonexist);
+
+       if(netown(f, up->env->user, OWRITE) < 0)
+               error(Eperm);
+
+       dir = kzmalloc(sizeof(struct dir) + n, 0);
+       m = convM2D(db, n, &dir[0], ( char *unused_char_p_t)&dir[1]);
+       if(m == 0){
+               kfree(dir);
+               error(Eshortstat);
+       }
+       if(!emptystr(dir[0].uid))
+               strncpy(f->owner, dir[0].uid, KNAMELEN);
+       if(dir[0].mode != ~0UL)
+               f->mode = dir[0].mode;
+       kfree(dir);
+       return m;
+}
+
+int
+netifstat(struct netif *nif, struct chan *c, uint8_t *db, int n)
+{
+       return devstat(c, db, n, (struct dirtab *)nif, 0, netifgen);
+}
+
+void
+netifclose(struct netif *nif, struct chan *c)
+{
+       struct netfile *f;
+       int t;
+       struct netaddr *ap;
+
+       if((c->flag & COPEN) == 0)
+               return;
+
+       t = NETTYPE(c->qid.path);
+       if(t != Ndataqid && t != Nctlqid)
+               return;
+
+       f = nif->f[NETID(c->qid.path)];
+       qlock(&f->qlock);
+       if(--(f->inuse) == 0){
+               if(f->prom){
+                       qlock(&nif->qlock);
+                       if(--(nif->prom) == 0 && nif->promiscuous != NULL)
+                               nif->promiscuous(nif->arg, 0);
+                       qunlock(&nif->qlock);
+                       f->prom = 0;
+               }
+               if(f->scan){
+                       qlock(&nif->qlock);
+                       if(--(nif->scan) == 0 && nif->scanbs != NULL)
+                               nif->scanbs(nif->arg, 0);
+                       qunlock(&nif->qlock);
+                       f->prom = 0;
+                       f->scan = 0;
+               }
+               if(f->nmaddr){
+                       qlock(&nif->qlock);
+                       t = 0;
+                       for(ap = nif->maddr; ap; ap = ap->next){
+                               if(f->maddr[t/8] & (1<<(t%8)))
+                                       netmulti(nif, f, ap->addr, 0);
+                       }
+                       qunlock(&nif->qlock);
+                       f->nmaddr = 0;
+               }
+               if(f->type < 0){
+                       qlock(&nif->qlock);
+                       --(nif->all);
+                       qunlock(&nif->qlock);
+               }
+               f->owner[0] = 0;
+               f->type = 0;
+               f->bridge = 0;
+               f->headersonly = 0;
+               qclose(f->in);
+       }
+       qunlock(&f->qlock);
+}
+
+spinlock_t netlock;
+
+static int
+netown(struct netfile *p, char *o, int omode)
+{
+       static int access[] = { 0400, 0200, 0600, 0100 };
+       int mode;
+       int t;
+
+       spin_lock(&(&netlock)->lock);
+       if(*p->owner){
+               if(strncmp(o, p->owner, KNAMELEN) == 0) /* User */
+                       mode = p->mode;
+               else if(strncmp(o, eve, KNAMELEN) == 0) /* Bootes is group */
+                       mode = p->mode<<3;
+               else
+                       mode = p->mode<<6;              /* Other */
+
+               t = access[omode&3];
+               if((t & mode) == t){
+                       spin_unlock(&(&netlock)->lock);
+                       return 0;
+               } else {
+                       spin_unlock(&(&netlock)->lock);
+                       return -1;
+               }
+       }
+       strncpy(p->owner, o, KNAMELEN);
+       p->mode = 0660;
+       spin_unlock(&(&netlock)->lock);
+       return 0;
+}
+
+/*
+ *  Increment the reference count of a network device.
+ *  If id < 0, return an unused ether device.
+ */
+static int
+openfile(struct netif *nif, int id)
+{
+       ERRSTACK(2);
+       struct netfile *f, **fp, **efp;
+
+       if(id >= 0){
+               f = nif->f[id];
+               if(f == 0)
+                       error(Enodev);
+               qlock(&f->qlock);
+               qreopen(f->in);
+               f->inuse++;
+               qunlock(&f->qlock);
+               return id;
+       }
+
+       qlock(&nif->qlock);
+       if(waserror()){
+               qunlock(&nif->qlock);
+               nexterror();
+       }
+       efp = &nif->f[nif->nfile];
+       for(fp = nif->f; fp < efp; fp++){
+               f = *fp;
+               if(f == 0){
+                       f = kzmalloc(sizeof(struct netfile), 0);
+                       if(f == 0)
+                               exhausted("memory");
+                       f->in = qopen(nif->limit, Qmsg, 0, 0);
+                       if(f->in == NULL){
+                               kfree(f);
+                               exhausted("memory");
+                       }
+                       *fp = f;
+                       qlock(&f->qlock);
+               } else {
+                       qlock(&f->qlock);
+                       if(f->inuse){
+                               qunlock(&f->qlock);
+                               continue;
+                       }
+               }
+               f->inuse = 1;
+               qreopen(f->in);
+               netown(f, up->env->user, 0);
+               qunlock(&f->qlock);
+               qunlock(&nif->qlock);
+               poperror();
+               return fp - nif->f;
+       }
+       error(Enodev);
+       return -1;      /* not reached */
+}
+
+/*
+ *  look for a token starting a string,
+ *  return a pointer to first non-space char after it
+ */
+static char*
+matchtoken(char *p, char *token)
+{
+       int n;
+
+       n = strlen(token);
+       if(strncmp(p, token, n))
+               return 0;
+       p += n;
+       if(*p == 0)
+               return p;
+       if(*p != ' ' && *p != '\t' && *p != '\n')
+               return 0;
+       while(*p == ' ' || *p == '\t' || *p == '\n')
+               p++;
+       return p;
+}
+
+static uint32_t
+hash(uint8_t *a, int len)
+{
+       uint32_t sum = 0;
+
+       while(len-- > 0)
+               sum = (sum << 1) + *a++;
+       return sum%Nmhash;
+}
+
+int
+activemulti(struct netif *nif, uint8_t *addr, int alen)
+{
+       struct netaddr *hp;
+
+       for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
+               if(memcmp(addr, hp->addr, alen) == 0){
+                       if(hp->ref)
+                               return 1;
+                       else
+                               break;
+               }
+       return 0;
+}
+
+static int
+parseaddr(uint8_t *to, char *from, int alen)
+{
+       char nip[4];
+       char *p;
+       int i;
+
+       p = from;
+       for(i = 0; i < alen; 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;
+}
+
+/*
+ *  keep track of multicast addresses
+ */
+static char*
+netmulti(struct netif *nif, struct netfile *f, uint8_t *addr, int add)
+{
+       struct netaddr **l, *ap;
+       int i;
+       uint32_t h;
+
+       if(nif->multicast == NULL)
+               return "interface does not support multicast";
+
+       l = &nif->maddr;
+       i = 0;
+       for(ap = *l; ap; ap = *l){
+               if(memcmp(addr, ap->addr, nif->alen) == 0)
+                       break;
+               i++;
+               l = &ap->next;
+       }
+
+       if(add){
+               if(ap == 0){
+                       *l = ap = kzmalloc(sizeof(*ap), 0);
+                       memmove(ap->addr, addr, nif->alen);
+                       ap->next = 0;
+                       kref_init(&ap->ref, fake_release, 1);
+                       h = hash(addr, nif->alen);
+                       ap->hnext = nif->mhash[h];
+                       nif->mhash[h] = ap;
+               } else {
+                       ap->ref++;
+               }
+               if(ap->ref == 1){
+                       nif->nmaddr++;
+                       nif->multicast(nif->arg, addr, 1);
+               }
+               if(i < 8*sizeof(f->maddr)){
+                       if((f->maddr[i/8] & (1<<(i%8))) == 0)
+                               f->nmaddr++;
+                       f->maddr[i/8] |= 1<<(i%8);
+               }
+       } else {
+               if(ap == 0 || ap->ref == 0)
+                       return 0;
+               ap->ref--;
+               if(ap->ref == 0){
+                       nif->nmaddr--;
+                       nif->multicast(nif->arg, addr, 0);
+               }
+               if(i < 8*sizeof(f->maddr)){
+                       if((f->maddr[i/8] & (1<<(i%8))) != 0)
+                               f->nmaddr--;
+                       f->maddr[i/8] &= ~(1<<(i%8));
+               }
+       }
+       return 0;
+}
index c8eef0c..7ef5025 100644 (file)
@@ -847,4 +847,180 @@ extern int ReTransTimer;
 
 int kdial(char *dest, char *local, char *dir, int *cfdp);
 
+/* network interfaces and ethernet */
+// INFERNO
+
+enum
+{
+       Nmaxaddr=       64,
+       Nmhash=         31,
+
+       Ncloneqid=      1,
+       Naddrqid,
+       N2ndqid,
+       N3rdqid,
+       Ndataqid,
+       Nctlqid,
+       Nstatqid,
+       Ntypeqid,
+       Nifstatqid,
+};
+
+/*
+ *  Macros to manage Qid's used for multiplexed devices
+ */
+#define NETTYPE(x)     (((uint32_t)x)&0x1f)
+#define NETID(x)       ((((uint32_t)x))>>5)
+#define NETQID(i,t)    ((((uint32_t)i)<<5)|(t))
+
+/*
+ *  one per multiplexed connection
+ */
+struct netfile
+{
+       qlock_t qlock;
+
+       int     inuse;
+       uint32_t        mode;
+       char    owner[KNAMELEN];
+
+       int     type;                   /* multiplexor type */
+       int     prom;                   /* promiscuous mode */
+       int     scan;                   /* base station scanning interval */
+       int     bridge;                 /* bridge mode */
+       int     headersonly;            /* headers only - no data */
+       uint8_t maddr[8];               /* bitmask of multicast addresses requested */
+       int     nmaddr;                 /* number of multicast addresses */
+
+       struct queue    *in;                    /* input buffer */
+};
+
+/*
+ *  a network address
+ */
+struct netaddr
+{
+       struct netaddr  *next;          /* allocation chain */
+       struct netaddr  *hnext;
+       uint8_t addr[Nmaxaddr];
+       int     ref;
+};
+
+/*
+ *  a network interface
+ */
+struct netif
+{
+       qlock_t qlock;
+
+       /* multiplexing */
+       char    name[KNAMELEN];         /* for top level directory */
+       int     nfile;                  /* max number of Netfiles */
+       struct netfile  **f;
+
+       /* about net */
+       int     limit;                  /* flow control */
+       int     alen;                   /* address length */
+       int     mbps;                   /* megabits per sec */
+       int     link;                   /* link status */
+       uint8_t addr[Nmaxaddr];
+       uint8_t bcast[Nmaxaddr];
+       struct netaddr  *maddr;                 /* known multicast addresses */
+       int     nmaddr;                 /* number of known multicast addresses */
+       struct netaddr *mhash[Nmhash];          /* hash table of multicast addresses */
+       int     prom;                   /* number of promiscuous opens */
+       int     scan;                   /* number of base station scanners */
+       int     all;                    /* number of -1 multiplexors */
+
+       /* statistics */
+       int     misses;
+       int     inpackets;
+       int     outpackets;
+       int     crcs;           /* input crc errors */
+       int     oerrs;          /* output errors */
+       int     frames;         /* framing errors */
+       int     overflows;      /* packet overflows */
+       int     buffs;          /* buffering errors */
+       int     soverflows;     /* software overflow */
+
+       /* routines for touching the hardware */
+       void    *arg;
+       void    (*promiscuous)(void*, int);
+       void    (*multicast)(void*, uint8_t *unused_uint8_p_t, int);
+       void    (*scanbs)(void*, unsigned nt);  /* scan for base stations */
+};
+
+void   netifinit(struct netif*, char *, int , uint32_t);
+struct walkqid*        netifwalk(struct netif*, struct chan*, struct chan*, char **, int);
+struct chan*   netifopen(struct netif*, struct chan*, int);
+void   netifclose(struct netif*, struct chan*);
+long   netifread(struct netif*, struct chan*, void*, long, uint32_t);
+struct block*  netifbread(struct netif*, struct chan*, long, uint32_t);
+long   netifwrite(struct netif*, struct chan*, void*, long);
+int    netifwstat(struct netif*, struct chan*, uint8_t *, int);
+int    netifstat(struct netif*, struct chan*, uint8_t *, int);
+int    activemulti(struct netif*, uint8_t *, int);
+
+/*
+ *  Ethernet specific
+ */
+enum
+{
+       Eaddrlen=       6,
+       ETHERMINTU =    60,             /* minimum transmit size */
+       ETHERMAXTU =    1514,           /* maximum transmit size */
+       ETHERHDRSIZE =  14,             /* size of an ethernet header */
+};
+
+struct etherpkt
+{
+       uint8_t d[Eaddrlen];
+       uint8_t s[Eaddrlen];
+       uint8_t type[2];
+       uint8_t data[1500];
+};
+// INFERNO
+enum {
+       MaxEther        = 4,
+       MaxFID= 16,
+       Ntypes          = 8,
+};
+
+struct ether {
+       rwlock_t rwlock;
+       int     ctlrno;
+       int     tbdf;                   /* type+busno+devno+funcno */
+       int     minmtu;
+       int     maxmtu;
+       uint8_t ea[Eaddrlen];
+       int     encry;
+
+       void    (*attach)(struct ether*);       /* filled in by reset routine */
+       void    (*closed)(struct ether*);
+       void    (*detach)(struct ether*);
+       void    (*transmit)(struct ether*);
+       void    (*interrupt)(struct hw_trapframe*, void*);
+       long    (*ifstat)(struct ether*, void*, long, uint32_t);
+       long    (*ctl)(struct ether*, void*, long); /* custom ctl messages */
+       void    (*power)(struct ether*, int);   /* power on/off */
+       void    (*shutdown)(struct ether*);     /* shutdown hardware before reboot */
+       void    *ctlr;
+       int     pcmslot;                /* PCMCIA */
+       int     fullduplex;     /* non-zero if full duplex */
+       int     vlanid; /* non-zero if vlan */
+
+       struct queue*   oq;
+
+       qlock_t vlq;    /* array change */
+       int     nvlan;
+       struct ether*   vlans[MaxFID];
+
+       /* another case where we wish we had anon struct members. */
+       struct netif netif;
+};
+
+extern struct block* etheriq(struct ether*, struct block*, int);
+extern void addethercard( char *unused_char_p_t, int(*)(struct ether*));
+extern int archether( int unused_int, struct ether*);
+
 #endif /* ROS_KERN_IP_H */
index 644cba3..0abc05a 100644 (file)
@@ -958,6 +958,7 @@ char *get_cur_genbuf(void);
 /* hack for now. */
 #define        NOW     tsc2msec(read_tsc())
 #define        seconds() tsc2sec(read_tsc())
+#define        milliseconds() tsc2msec(read_tsc())
 
 /* kern/src/ns/parse.c */
 struct cmdbuf *parsecmd(char *p, int n);