9ns: Fix devtab function pointer signatures
[akaros.git] / kern / drivers / dev / ether.c
index af71126..f0a7c14 100644 (file)
@@ -1,4 +1,31 @@
-// INFERNO
+/* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+ * Portions Copyright © 1997-1999 Vita Nuova Limited
+ * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
+ *                                (www.vitanuova.com)
+ * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+ *
+ * Modified for the Akaros operating system:
+ * Copyright (c) 2013-2014 The Regents of the University of California
+ * Copyright (c) 2013-2015 Google Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
+
 #include <vfs.h>
 #include <kfs.h>
 #include <slab.h>
 #include <cpio.h>
 #include <pmap.h>
 #include <smp.h>
-#include <ip.h>
+#include <net/ip.h>
+
+struct dev etherdevtab;
+
+static char *devname(void)
+{
+       return etherdevtab.name;
+}
 
 enum {
        Type8021Q = 0x8100,                     /* value of type field for 802.1[pQ] tags */
@@ -37,32 +71,32 @@ struct chan *etherattach(char *spec)
                /* somebody interpret this for me. */
                if (((ctlrno == 0) && (p == spec)) ||
                        (ctlrno >= MaxEther) || ((*p) && (*p != '.')))
-                       error(Ebadarg);
+                       error(EINVAL, ERROR_FIXME);
                if (*p == '.') {        /* vlan */
                        vlanid = strtoul(p + 1, &p, 0);
                        if (vlanid <= 0 || vlanid > 0xFFF || *p)
-                               error(Ebadarg);
+                               error(EINVAL, ERROR_FIXME);
                }
        }
        if ((ether = etherxx[ctlrno]) == 0)
-               error(Enodev);
+               error(ENODEV, ERROR_FIXME);
        rlock(&ether->rwlock);
        if (waserror()) {
                runlock(&ether->rwlock);
                nexterror();
        }
        if (vlanid) {
-               if (ether->maxmtu < ETHERMAXTU + 4)
-                       error("interface cannot support 802.1 tags");
+               if (ether->max_mtu < ETHERMAXTU + ETHERHDRSIZE + 4)
+                       error(EFAIL, "interface cannot support 802.1 tags");
                vlan = vlanalloc(ether, vlanid);
-               chan = devattach('l', spec);
+               chan = devattach(devname(), spec);
                chan->dev = ctlrno + (vlanid << 8);
                chan->aux = vlan;
                poperror();
                runlock(&ether->rwlock);
                return chan;
        }
-       chan = devattach('l', spec);
+       chan = devattach(devname(), spec);
        chan->dev = ctlrno;
        chan->aux = ether;
        if (ether->attach)
@@ -85,7 +119,7 @@ static void ethershutdown(void)
 }
 
 static struct walkqid *etherwalk(struct chan *chan, struct chan *nchan,
-                                                                char **name, int nname)
+                                                                char **name, unsigned int nname)
 {
        ERRSTACK(1);
        struct walkqid *wq;
@@ -97,7 +131,7 @@ static struct walkqid *etherwalk(struct chan *chan, struct chan *nchan,
                runlock(&ether->rwlock);
                nexterror();
        }
-       wq = netifwalk(&ether->netif, chan, nchan, name, nname);
+       wq = netifwalk(ether, chan, nchan, name, nname);
        if (wq && wq->clone != NULL && wq->clone != chan)
                wq->clone->aux = ether;
        poperror();
@@ -105,10 +139,10 @@ static struct walkqid *etherwalk(struct chan *chan, struct chan *nchan,
        return wq;
 }
 
-static int etherstat(struct chan *chan, uint8_t * dp, int n)
+static size_t etherstat(struct chan *chan, uint8_t *dp, size_t n)
 {
        ERRSTACK(1);
-       int s;
+       size_t s;
        struct ether *ether;
 
        ether = chan->aux;
@@ -117,7 +151,7 @@ static int etherstat(struct chan *chan, uint8_t * dp, int n)
                runlock(&ether->rwlock);
                nexterror();
        }
-       s = netifstat(&ether->netif, chan, dp, n);
+       s = netifstat(ether, chan, dp, n);
        poperror();
        runlock(&ether->rwlock);
        return s;
@@ -135,7 +169,7 @@ static struct chan *etheropen(struct chan *chan, int omode)
                runlock(&ether->rwlock);
                nexterror();
        }
-       c = netifopen(&ether->netif, chan, omode);
+       c = netifopen(ether, chan, omode);
        poperror();
        runlock(&ether->rwlock);
        return c;
@@ -152,12 +186,12 @@ static void etherclose(struct chan *chan)
                runlock(&ether->rwlock);
                nexterror();
        }
-       netifclose(&ether->netif, chan);
+       netifclose(ether, chan);
        poperror();
        runlock(&ether->rwlock);
 }
 
-static long etherread(struct chan *chan, void *buf, long n, int64_t off)
+static size_t etherread(struct chan *chan, void *buf, size_t n, off64_t off)
 {
        ERRSTACK(1);
        struct ether *ether;
@@ -182,14 +216,14 @@ static long etherread(struct chan *chan, void *buf, long n, int64_t off)
                if (NETTYPE(chan->qid.path) == Nstatqid)
                        ether->ifstat(ether, buf, 0, offset);
        }
-       r = netifread(&ether->netif, chan, buf, n, offset);
+       r = netifread(ether, chan, buf, n, offset);
 out:
        poperror();
        runlock(&ether->rwlock);
        return r;
 }
 
-static struct block *etherbread(struct chan *chan, long n, uint32_t offset)
+static struct block *etherbread(struct chan *chan, size_t n, off64_t offset)
 {
        ERRSTACK(1);
        struct block *b;
@@ -201,13 +235,13 @@ static struct block *etherbread(struct chan *chan, long n, uint32_t offset)
                runlock(&ether->rwlock);
                nexterror();
        }
-       b = netifbread(&ether->netif, chan, n, offset);
+       b = netifbread(ether, chan, n, offset);
        poperror();
        runlock(&ether->rwlock);
        return b;
 }
 
-static int etherwstat(struct chan *chan, uint8_t * dp, int n)
+static size_t etherwstat(struct chan *chan, uint8_t *dp, size_t n)
 {
        ERRSTACK(1);
        struct ether *ether;
@@ -219,7 +253,7 @@ static int etherwstat(struct chan *chan, uint8_t * dp, int n)
                runlock(&ether->rwlock);
                nexterror();
        }
-       r = netifwstat(&ether->netif, chan, dp, n);
+       r = netifwstat(ether, chan, dp, n);
        poperror();
        runlock(&ether->rwlock);
        return r;
@@ -236,7 +270,7 @@ static void etherrtrace(struct netfile *f, struct etherpkt *pkt, int len)
                n = 58;
        else
                n = len;
-       bp = iallocb(68);
+       bp = block_alloc(68, MEM_ATOMIC);
        if (bp == NULL)
                return;
        memmove(bp->wp, pkt->d, n);
@@ -272,15 +306,17 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
 {
        struct etherpkt *pkt;
        uint16_t type;
-       int len, multi, tome, fromme, vlanid, i;
+       int multi, tome, fromme, vlanid, i;
        struct netfile **ep, *f, **fp, *fx;
        struct block *xbp;
        struct ether *vlan;
 
-       ether->netif.inpackets++;
+       ether->inpackets++;
 
        pkt = (struct etherpkt *)bp->rp;
-       len = BLEN(bp);
+       /* TODO: we might need to assert more for higher layers, or otherwise deal
+        * with extra data. */
+       assert(BHLEN(bp) >= offsetof(struct etherpkt, data));
        type = (pkt->type[0] << 8) | pkt->type[1];
        if (type == Type8021Q && ether->nvlan) {
                vlanid = nhgets(bp->rp + 2 * Eaddrlen + 2) & 0xFFF;
@@ -288,6 +324,8 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
                        for (i = 0; i < ARRAY_SIZE(ether->vlans); i++) {
                                vlan = ether->vlans[i];
                                if (vlan != NULL && vlan->vlanid == vlanid) {
+                                       /* might have a problem with extra data here */
+                                       assert(BHLEN(bp) >= 4 + 2 * Eaddrlen);
                                        memmove(bp->rp + 4, bp->rp, 2 * Eaddrlen);
                                        bp->rp += 4;
                                        return etheriq(vlan, bp, fromwire);
@@ -298,13 +336,13 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
        }
 
        fx = 0;
-       ep = &ether->netif.f[Ntypes];
+       ep = &ether->f[Ntypes];
 
        multi = pkt->d[0] & 1;
        /* check for valid multcast addresses */
-       if (multi && eaddrcmp(pkt->d, ether->netif.bcast) != 0
-               && ether->netif.prom == 0) {
-               if (!activemulti(&ether->netif, pkt->d, sizeof(pkt->d))) {
+       if (multi && eaddrcmp(pkt->d, ether->bcast) != 0
+               && ether->prom == 0) {
+               if (!activemulti(ether, pkt->d, sizeof(pkt->d))) {
                        if (fromwire) {
                                freeb(bp);
                                bp = 0;
@@ -323,30 +361,33 @@ struct block *etheriq(struct ether *ether, struct block *bp, int fromwire)
         * 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++) {
+       for (fp = ether->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 (f->headersonly) {
+                                       etherrtrace(f, pkt, BHLEN(bp));
+                                       continue;
+                               }
+                               if (fromwire && fx == 0) {
+                                       fx = f;
+                                       continue;
+                               }
+                               xbp = copyblock(bp, MEM_ATOMIC);
+                               if (xbp == 0) {
+                                       ether->soverflows++;
+                                       continue;
+                               }
+                               if (qpass(f->in, xbp) < 0)
+                                       ether->soverflows++;
                        }
        }
 
        if (fx) {
                if (qpass(fx->in, bp) < 0)
-                       ether->netif.soverflows++;
+                       ether->soverflows++;
                return 0;
        }
        if (fromwire) {
@@ -363,10 +404,11 @@ static int etheroq(struct ether *ether, struct block *bp)
        struct etherpkt *pkt;
        int8_t irq_state = 0;
 
-       ether->netif.outpackets++;
+       ether->outpackets++;
 
-       if (!(ether->netif.feat & NETF_SG))
+       if (!(ether->feat & NETF_SG))
                bp = linearizeblock(bp);
+       ptclcsum_finalize(bp, ether->feat);
        /*
         * 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
@@ -379,37 +421,36 @@ static int etheroq(struct ether *ether, struct block *bp)
        pkt = (struct etherpkt *)bp->rp;
        len = BLEN(bp);
        loopback = eaddrcmp(pkt->d, ether->ea) == 0;
-       if (loopback || eaddrcmp(pkt->d, ether->netif.bcast) == 0
-               || ether->netif.prom) {
+       if (loopback || eaddrcmp(pkt->d, ether->bcast) == 0 || ether->prom) {
                disable_irqsave(&irq_state);
                etheriq(ether, bp, 0);
                enable_irqsave(&irq_state);
+               if (loopback) {
+                       freeb(bp);
+                       return len;
+               }
        }
 
-       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;
-               }
+       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;
+       }
 
-               if ((ether->netif.feat & NETF_PADMIN) == 0 && BLEN(bp) < ether->minmtu)
-                       bp = adjustblock(bp, ether->minmtu);
+       if ((ether->feat & NETF_PADMIN) == 0 && BLEN(bp) < ether->min_mtu)
+               bp = adjustblock(bp, ether->min_mtu);
 
-               ptclcsum_finalize(bp, ether->netif.feat);
-               qbwrite(ether->oq, bp);
-               if (ether->transmit != NULL)
-                       ether->transmit(ether);
-       } else
-               freeb(bp);
+       qbwrite(ether->oq, bp);
+       if (ether->transmit != NULL)
+               ether->transmit(ether);
 
        return len;
 }
 
-static long etherwrite(struct chan *chan, void *buf, long n, int64_t unused)
+static size_t etherwrite(struct chan *chan, void *buf, size_t n, off64_t unused)
 {
        ERRSTACK(2);
        struct ether *ether;
@@ -425,17 +466,21 @@ static long etherwrite(struct chan *chan, void *buf, long n, int64_t unused)
                nexterror();
        }
        if (NETTYPE(chan->qid.path) != Ndataqid) {
-               l = netifwrite(&ether->netif, chan, buf, n);
+               l = netifwrite(ether, chan, buf, n);
                if (l >= 0)
                        goto out;
                cb = parsecmd(buf, n);
+               if (cb->nf < 1) {
+                       kfree(cb);
+                       error(EFAIL, "short control request");
+               }
                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);
+                               qdropoverflow(ether->oq, onoff);
                        kfree(cb);
                        goto out;
                }
@@ -444,12 +489,12 @@ static long etherwrite(struct chan *chan, void *buf, long n, int64_t unused)
                        l = ether->ctl(ether, buf, n);
                        goto out;
                }
-               error(Ebadctl);
+               error(EINVAL, ERROR_FIXME);
        }
 
-       if (n > ether->maxmtu)
-               error(Etoobig);
-       bp = allocb(n);
+       if (n > ether->mtu + ETHERHDRSIZE)
+               error(E2BIG, ERROR_FIXME);
+       bp = block_alloc(n, MEM_WAIT);
        if (waserror()) {
                freeb(bp);
                nexterror();
@@ -466,7 +511,7 @@ out:
        return l;
 }
 
-static long etherbwrite(struct chan *chan, struct block *bp, uint32_t unused)
+static size_t etherbwrite(struct chan *chan, struct block *bp, off64_t unused)
 {
        ERRSTACK(1);
        struct ether *ether;
@@ -489,9 +534,9 @@ static long etherbwrite(struct chan *chan, struct block *bp, uint32_t unused)
                runlock(&ether->rwlock);
                nexterror();
        }
-       if (n > ether->maxmtu && (bp->flag & Btso) == 0) {
+       if (n > ether->mtu + ETHERHDRSIZE && (bp->flag & Btso) == 0) {
                freeb(bp);
-               error(Etoobig);
+               error(E2BIG, ERROR_FIXME);
        }
        n = etheroq(ether, bp);
        poperror();
@@ -515,7 +560,7 @@ static long vlanctl(struct ether *ether, void *buf, long n)
                && 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);
+               memmove(ether->addr, ether->ea, Eaddrlen);
                return 0;
        }
        if (cb->nf == 1 && strcmp(cb->f[0], "disable") == 0) {
@@ -532,7 +577,7 @@ static long vlanctl(struct ether *ether, void *buf, long n)
                return 0;
        }
        kfree(cb);
-       error(Ebadctl);
+       error(EINVAL, ERROR_FIXME);
        return -1;      /* not reached */
 }
 
@@ -560,37 +605,38 @@ static struct ether *vlanalloc(struct ether *ether, int id)
                        fid = i;
        }
        if (fid < 0)
-               error(Enoifc);
+               error(ENOENT, ERROR_FIXME);
        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);
+                       error(ENOMEM, ERROR_FIXME);
                rwinit(&vlan->rwlock);
                qlock_init(&vlan->vlq);
-               netifinit(&vlan->netif, name, Ntypes, ether->netif.limit);
+               netifinit(vlan, name, Ntypes, ether->limit);
                ether->vlans[fid] = vlan;       /* id is still zero, can't be matched */
                ether->nvlan++;
        } else
-               memmove(vlan->netif.name, name, KNAMELEN - 1);
+               memmove(vlan->name, name, KNAMELEN - 1);
        vlan->attach = nop;
        vlan->transmit = NULL;
        vlan->ctl = vlanctl;
        vlan->irq = -1;
-       vlan->netif.promiscuous = ether->netif.promiscuous;
-       vlan->netif.multicast = ether->netif.multicast;
-       vlan->netif.arg = vlan;
-       vlan->netif.mbps = ether->netif.mbps;
+       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->mtu = ether->mtu;
+       vlan->min_mtu = ether->min_mtu;
+       vlan->max_mtu = ether->max_mtu;
        vlan->ctlrno = ether->ctlrno;
        vlan->vlanid = id;
-       vlan->netif.alen = Eaddrlen;
-       memmove(vlan->netif.addr, ether->netif.addr, sizeof(vlan->netif.addr));
-       memmove(vlan->netif.bcast, ether->netif.bcast, sizeof(ether->netif.bcast));
+       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;
@@ -649,10 +695,12 @@ static void etherreset(void)
                memset(ether, 0, sizeof(struct ether));
                rwinit(&ether->rwlock);
                qlock_init(&ether->vlq);
+               rendez_init(&ether->link_rz);
                ether->ctlrno = ctlrno;
-               ether->netif.mbps = 10;
-               ether->minmtu = ETHERMINTU;
-               ether->maxmtu = ETHERMAXTU;
+               ether->mbps = 10;
+               ether->mtu = ETHERMAXTU;
+               ether->min_mtu = ETHERMINTU;
+               ether->max_mtu = ETHERMAXTU;
                /* looked like irq type, we don't have these yet */
                //ether->netif.itype = -1;
 
@@ -687,7 +735,8 @@ static void etherreset(void)
 
                        i = snprintf(buf, sizeof(buf),
                                                 "#l%d: %s: %dMbps port 0x%x irq %u", ctlrno,
-                                                ether->type, ether->netif.mbps, ether->port,
+                                                ether->type, ether->mbps,
+                                    ether->port,
                                                 ether->irq);
                        /* Looks like this is for printing MMIO addrs */
 #if 0
@@ -705,7 +754,7 @@ static void etherreset(void)
                        snprintf(buf + i, sizeof(buf) - i, "\n");
                        printk(buf);
 
-                       switch (ether->netif.mbps) {
+                       switch (ether->mbps) {
 
                        case 1 ... 99:
                                qsize = 64 * 1024;
@@ -719,14 +768,14 @@ static void etherreset(void)
                        default:
                                qsize = 8 * 1024 * 1024;
                        }
-                       netifinit(&ether->netif, name, Ntypes, qsize);
+                       netifinit(ether, name, Ntypes, qsize);
                        if (ether->oq == 0)
                                ether->oq = qopen(qsize, Qmsg, 0, 0);
                        if (ether->oq == 0)
                                panic("etherreset %s", name);
-                       ether->netif.alen = Eaddrlen;
-                       memmove(ether->netif.addr, ether->ea, Eaddrlen);
-                       memset(ether->netif.bcast, 0xFF, Eaddrlen);
+                       ether->alen = Eaddrlen;
+                       memmove(ether->addr, ether->ea, Eaddrlen);
+                       memset(ether->bcast, 0xFF, Eaddrlen);
 
                        etherxx[ctlrno] = ether;
                        ether = 0;
@@ -793,24 +842,23 @@ uint32_t ethercrc(uint8_t * p, int len)
 }
 
 struct dev etherdevtab __devtab = {
-       'l',
-       "ether",
-
-       etherreset,
-       devinit,
-       ethershutdown,
-       etherattach,
-       etherwalk,
-       etherstat,
-       etheropen,
-       devcreate,
-       etherclose,
-       etherread,
-       etherbread,
-       etherwrite,
-       etherbwrite,
-       devremove,
-       etherwstat,
-       etherpower,
-       devchaninfo,
+       .name = "ether",
+
+       .reset = etherreset,
+       .init = devinit,
+       .shutdown = ethershutdown,
+       .attach = etherattach,
+       .walk = etherwalk,
+       .stat = etherstat,
+       .open = etheropen,
+       .create = devcreate,
+       .close = etherclose,
+       .read = etherread,
+       .bread = etherbread,
+       .write = etherwrite,
+       .bwrite = etherbwrite,
+       .remove = devremove,
+       .wstat = etherwstat,
+       .power = etherpower,
+       .chaninfo = devchaninfo,
 };