net: Use chan flag O_NONBLOCK for nonblocking
[akaros.git] / kern / src / net / devip.c
index 5eac79b..48f67cd 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>
@@ -24,7 +51,6 @@ enum {
        Qtopdir = 1,                            /* top level directory */
        Qtopbase,
        Qarp = Qtopbase,
-       Qbootp,
        Qndb,
        Qiproute,
        Qiprouter,
@@ -74,6 +100,12 @@ extern char *eve;
 static long ndbwrite(struct Fs *, char *unused_char_p_t, uint32_t, int);
 static void closeconv(struct conv *);
 
+static struct conv *chan2conv(struct chan *chan)
+{
+       /* That's a lot of pointers to get to the conv! */
+       return ipfs[chan->dev]->p[PROTO(chan->qid)]->conv[CONV(chan->qid)];
+}
+
 static inline int founddevdir(struct chan *c, struct qid q, char *n,
                                                          int64_t length, char *user, long perm,
                                                          struct dir *db)
@@ -97,7 +129,7 @@ static int ip3gen(struct chan *c, int i, struct dir *dp)
        struct conv *cv;
        char *p;
 
-       cv = ipfs[c->dev]->p[PROTO(c->qid)]->conv[CONV(c->qid)];
+       cv = chan2conv(c);
        if (cv->owner == NULL)
                kstrdup(&cv->owner, eve);
        mkqid(&q, QID(PROTO(c->qid), CONV(c->qid), i), 0, QTFILE);
@@ -166,11 +198,6 @@ static int ip1gen(struct chan *c, int i, struct dir *dp)
                case Qarp:
                        p = "arp";
                        break;
-               case Qbootp:
-                       if (bootp == NULL)
-                               return 0;
-                       p = "bootp";
-                       break;
                case Qndb:
                        p = "ndb";
                        len = strlen(f->ndb);
@@ -219,7 +246,6 @@ ipgen(struct chan *c, char *unused_char_p_t, struct dirtab *d, int unused_int,
                        s -= f->np;
                        return ip1gen(c, s + Qtopbase, dp);
                case Qarp:
-               case Qbootp:
                case Qndb:
                case Qlog:
                case Qiproute:
@@ -291,7 +317,7 @@ static struct Fs *ipgetfs(int dev)
 
        qlock(&fslock);
        if (ipfs[dev] == NULL) {
-               f = kzmalloc(sizeof(struct Fs), KMALLOC_WAIT);
+               f = kzmalloc(sizeof(struct Fs), MEM_WAIT);
                rwinit(&f->rwlock);
                qlock_init(&f->iprouter.qlock);
                ip_init(f);
@@ -387,7 +413,7 @@ static struct chan *ipopen(struct chan *c, int omode)
                        break;
                case Qndb:
                        if (omode & (O_WRITE | O_TRUNC) && !iseve())
-                               error(EPERM, NULL);
+                               error(EPERM, ERROR_FIXME);
                        if ((omode & (O_WRITE | O_TRUNC)) == (O_WRITE | O_TRUNC))
                                f->ndb[0] = 0;
                        break;
@@ -406,18 +432,17 @@ static struct chan *ipopen(struct chan *c, int omode)
                case Qremote:
                case Qlocal:
                case Qstats:
-               case Qbootp:
                case Qipselftab:
                        if (omode & O_WRITE)
-                               error(EPERM, NULL);
+                               error(EPERM, ERROR_FIXME);
                        break;
                case Qsnoop:
                        if (omode & O_WRITE)
-                               error(EPERM, NULL);
+                               error(EPERM, ERROR_FIXME);
                        p = f->p[PROTO(c->qid)];
                        cv = p->conv[CONV(c->qid)];
                        if (strcmp(ATTACHER(c), cv->owner) != 0 && !iseve())
-                               error(EPERM, NULL);
+                               error(EPERM, ERROR_FIXME);
                        atomic_inc(&cv->snoopers);
                        break;
                case Qclone:
@@ -431,12 +456,9 @@ static struct chan *ipopen(struct chan *c, int omode)
                        qunlock(&p->qlock);
                        poperror();
                        if (cv == NULL) {
-                               error(ENODEV, NULL);
+                               error(ENODEV, ERROR_FIXME);
                                break;
                        }
-                       /* we only honor nonblock on a clone */
-                       if (c->flag & O_NONBLOCK)
-                               Fsconvnonblock(cv, TRUE);
                        mkqid(&c->qid, QID(p->x, cv->x, Qctl), 0, QTFILE);
                        break;
                case Qdata:
@@ -453,9 +475,9 @@ static struct chan *ipopen(struct chan *c, int omode)
                        }
                        if ((perm & (cv->perm >> 6)) != perm) {
                                if (strcmp(ATTACHER(c), cv->owner) != 0)
-                                       error(EPERM, NULL);
+                                       error(EPERM, ERROR_FIXME);
                                if ((perm & cv->perm) != perm)
-                                       error(EPERM, NULL);
+                                       error(EPERM, ERROR_FIXME);
 
                        }
                        cv->inuse++;
@@ -487,9 +509,9 @@ static struct chan *ipopen(struct chan *c, int omode)
                        }
                        if ((perm & (cv->perm >> 6)) != perm) {
                                if (strcmp(ATTACHER(c), cv->owner) != 0)
-                                       error(EPERM, NULL);
+                                       error(EPERM, ERROR_FIXME);
                                if ((perm & cv->perm) != perm)
-                                       error(EPERM, NULL);
+                                       error(EPERM, ERROR_FIXME);
 
                        }
 
@@ -518,7 +540,7 @@ static struct chan *ipopen(struct chan *c, int omode)
                                /* we can peek at incall without grabbing the cv qlock.  if
                                 * anything is there, it'll remain there until we dequeue it.
                                 * no one else can, since we hold the listenq lock */
-                               if (cv->nonblock && !cv->incall)
+                               if ((c->flag & O_NONBLOCK) && !cv->incall)
                                        error(EAGAIN, "listen queue empty");
                                /* wait for a connect */
                                rendez_sleep(&cv->listenr, should_wake, cv);
@@ -531,10 +553,6 @@ static struct chan *ipopen(struct chan *c, int omode)
                                        cv->incall = nc->next;
                                        mkqid(&c->qid, QID(PROTO(c->qid), nc->x, Qctl), 0, QTFILE);
                                        kstrdup(&cv->owner, ATTACHER(c));
-                                       /* O_NONBLOCK/CNONBLOCK when opening listen means the *new*
-                                        * conv is already non-blocking, like accept4() in Linux */
-                                       if (c->flag & O_NONBLOCK)
-                                               Fsconvnonblock(nc, TRUE);
                                }
                                qunlock(&cv->qlock);
 
@@ -562,7 +580,7 @@ static int ipwstat(struct chan *c, uint8_t * dp, int n)
        f = ipfs[c->dev];
        switch (TYPE(c->qid)) {
                default:
-                       error(EPERM, NULL);
+                       error(EPERM, ERROR_FIXME);
                        break;
                case Qctl:
                case Qdata:
@@ -576,11 +594,11 @@ static int ipwstat(struct chan *c, uint8_t * dp, int n)
        }
        n = convM2D(dp, n, d, (char *)&d[1]);
        if (n == 0)
-               error(ENODATA, NULL);
+               error(ENODATA, ERROR_FIXME);
        p = f->p[PROTO(c->qid)];
        cv = p->conv[CONV(c->qid)];
        if (!iseve() && strcmp(ATTACHER(c), cv->owner) != 0)
-               error(EPERM, NULL);
+               error(EPERM, ERROR_FIXME);
        if (!emptystr(d->uid))
                kstrdup(&cv->owner, d->uid);
        if (d->mode != ~0UL)
@@ -607,8 +625,9 @@ static char *ipchaninfo(struct chan *ch, char *ret, size_t ret_l)
                case Qdata:
                        proto = f->p[PROTO(ch->qid)];
                        conv = proto->conv[CONV(ch->qid)];
-                       snprintf(ret, ret_l, "Qdata, proto %s, conv idx %d", proto->name,
-                                        conv->x);
+                       snprintf(ret, ret_l, "Qdata, %s proto %s, conv idx %d",
+                                SLIST_EMPTY(&conv->data_taps) ? "untapped" : "tapped",
+                                proto->name, conv->x);
                        break;
                case Qarp:
                        ret = "Qarp";
@@ -619,8 +638,9 @@ static char *ipchaninfo(struct chan *ch, char *ret, size_t ret_l)
                case Qlisten:
                        proto = f->p[PROTO(ch->qid)];
                        conv = proto->conv[CONV(ch->qid)];
-                       snprintf(ret, ret_l, "Qlisten, proto %s, conv idx %d", proto->name,
-                                        conv->x);
+                       snprintf(ret, ret_l, "Qlisten, %s proto %s, conv idx %d",
+                                SLIST_EMPTY(&conv->listen_taps) ? "untapped" : "tapped",
+                                proto->name, conv->x);
                        break;
                case Qlog:
                        ret = "Qlog";
@@ -721,15 +741,13 @@ static long ipread(struct chan *ch, void *a, long n, int64_t off)
        p = a;
        switch (TYPE(ch->qid)) {
                default:
-                       error(EPERM, NULL);
+                       error(EPERM, ERROR_FIXME);
                case Qtopdir:
                case Qprotodir:
                case Qconvdir:
                        return devdirread(ch, a, n, 0, 0, ipgen);
                case Qarp:
                        return arpread(f->arp, a, offset, n);
-               case Qbootp:
-                       return bootpread(a, offset, n);
                case Qndb:
                        return readstr(offset, a, n, f->ndb);
                case Qiproute:
@@ -777,14 +795,15 @@ static long ipread(struct chan *ch, void *a, long n, int64_t off)
                        x = f->p[PROTO(ch->qid)];
                        c = x->conv[CONV(ch->qid)];
                        sofar = (*x->state) (c, buf, Statelen - 2);
-                       sofar += snprintf(buf + sofar, Statelen - 2 - sofar, "nonblock %s\n",
-                                         c->nonblock ? "on" : "off");
                        rv = readstr(offset, p, n, buf);
                        kfree(buf);
                        return rv;
                case Qdata:
                        c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
-                       return qread(c->rq, a, n);
+                       if (ch->flag & O_NONBLOCK)
+                               return qread_nonblock(c->rq, a, n);
+                       else
+                               return qread(c->rq, a, n);
                case Qerr:
                        c = f->p[PROTO(ch->qid)]->conv[CONV(ch->qid)];
                        return qread(c->eq, a, n);
@@ -806,15 +825,14 @@ static long ipread(struct chan *ch, void *a, long n, int64_t off)
 static struct block *ipbread(struct chan *ch, long n, uint32_t offset)
 {
        struct conv *c;
-       struct Proto *x;
-       struct Fs *f;
 
        switch (TYPE(ch->qid)) {
                case Qdata:
-                       f = ipfs[ch->dev];
-                       x = f->p[PROTO(ch->qid)];
-                       c = x->conv[CONV(ch->qid)];
-                       return qbread(c->rq, n);
+                       c = chan2conv(ch);
+                       if (ch->flag & O_NONBLOCK)
+                               return qbread_nonblock(c->rq, n);
+                       else
+                               return qbread(c->rq, n);
                default:
                        return devbread(ch, n, offset);
        }
@@ -831,7 +849,7 @@ static void setladdr(struct conv *c)
 /*
  *  set a local port making sure the quad of raddr,rport,laddr,lport is unique
  */
-static char *setluniqueport(struct conv *c, int lport)
+static void setluniqueport(struct conv *c, int lport)
 {
        struct Proto *p;
        struct conv *xp;
@@ -852,12 +870,11 @@ static char *setluniqueport(struct conv *c, int lport)
                        && ipcmp(xp->raddr, c->raddr) == 0
                        && ipcmp(xp->laddr, c->laddr) == 0) {
                        qunlock(&p->qlock);
-                       return "address in use";
+                       error(EFAIL, "address in use");
                }
        }
        c->lport = lport;
        qunlock(&p->qlock);
-       return NULL;
 }
 
 /*
@@ -889,7 +906,7 @@ static void setlport(struct conv *c)
                                *pp = 600;
                } else
                        while (*pp < 5000)
-                               *pp = nrand(1 << 15);
+                               urandom_read(pp, sizeof(*pp));
 
                found = 0;
                for (x = 0; x < p->nc; x++) {
@@ -911,15 +928,12 @@ static void setlport(struct conv *c)
  *  set a local address and port from a string of the form
  *     [address!]port[!r]
  */
-static char *setladdrport(struct conv *c, char *str, int announcing)
+static void setladdrport(struct conv *c, char *str, int announcing)
 {
        char *p;
-       char *rv;
        uint16_t lport;
        uint8_t addr[IPaddrlen];
 
-       rv = NULL;
-
        /*
         *  ignore restricted part if it exists.  it's
         *  meaningless on local ports.
@@ -946,32 +960,31 @@ static char *setladdrport(struct conv *c, char *str, int announcing)
                        if (ipforme(c->p->f, addr))
                                ipmove(c->laddr, addr);
                        else
-                               return "not a local IP address";
+                               error(EFAIL, "not a local IP address");
                }
        }
 
        /* one process can get all connections */
        if (announcing && strcmp(p, "*") == 0) {
                if (!iseve())
-                       error(EPERM, NULL);
-               return setluniqueport(c, 0);
+                       error(EPERM, ERROR_FIXME);
+               setluniqueport(c, 0);
        }
 
        lport = atoi(p);
        if (lport <= 0)
                setlport(c);
        else
-               rv = setluniqueport(c, lport);
-       return rv;
+               setluniqueport(c, lport);
 }
 
-static char *setraddrport(struct conv *c, char *str)
+static void setraddrport(struct conv *c, char *str)
 {
        char *p;
 
        p = strchr(str, '!');
        if (p == NULL)
-               return "malformed address";
+               error(EFAIL, "malformed address");
        *p++ = 0;
        parseip(c->raddr, str);
        c->rport = atoi(p);
@@ -980,33 +993,25 @@ static char *setraddrport(struct conv *c, char *str)
                if (strstr(p, "!r") != NULL)
                        c->restricted = 1;
        }
-       return NULL;
 }
 
 /*
  *  called by protocol connect routine to set addresses
  */
-char *Fsstdconnect(struct conv *c, char *argv[], int argc)
+void Fsstdconnect(struct conv *c, char *argv[], int argc)
 {
-       char *p;
-
        switch (argc) {
                default:
-                       return "bad args to connect";
+                       error(EINVAL, "bad args to %s", __func__);
                case 2:
-                       p = setraddrport(c, argv[1]);
-                       if (p != NULL)
-                               return p;
+                       setraddrport(c, argv[1]);
                        setladdr(c);
                        setlport(c);
                        break;
                case 3:
-                       p = setraddrport(c, argv[1]);
-                       if (p != NULL)
-                               return p;
-                       p = setladdrport(c, argv[2], 0);
-                       if (p != NULL)
-                               return p;
+                       setraddrport(c, argv[1]);
+                       setladdrport(c, argv[2], 0);
+                       break;
        }
 
        if ((memcmp(c->raddr, v4prefix, IPv4off) == 0 &&
@@ -1015,8 +1020,6 @@ char *Fsstdconnect(struct conv *c, char *argv[], int argc)
                c->ipversion = V4;
        else
                c->ipversion = V6;
-
-       return NULL;
 }
 
 /*
@@ -1033,14 +1036,12 @@ static void connectctlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
        char *p;
 
        if (c->state != 0)
-               error(EBUSY, NULL);
+               error(EBUSY, ERROR_FIXME);
        c->state = Connecting;
        c->cerr[0] = '\0';
        if (x->connect == NULL)
                error(EFAIL, "connect not supported");
-       p = x->connect(c, cb->f, cb->nf);
-       if (p != NULL)
-               error(EFAIL, p);
+       x->connect(c, cb->f, cb->nf);
 
        qunlock(&c->qlock);
        if (waserror()) {
@@ -1058,15 +1059,16 @@ static void connectctlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
 /*
  *  called by protocol announce routine to set addresses
  */
-char *Fsstdannounce(struct conv *c, char *argv[], int argc)
+void Fsstdannounce(struct conv *c, char *argv[], int argc)
 {
        memset(c->raddr, 0, sizeof(c->raddr));
        c->rport = 0;
        switch (argc) {
                default:
-                       return "bad args to announce";
+                       error(EINVAL, "bad args to announce");
                case 2:
-                       return setladdrport(c, argv[1], 1);
+                       setladdrport(c, argv[1], 1);
+                       break;
        }
 }
 
@@ -1084,14 +1086,12 @@ static void announcectlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
        char *p;
 
        if (c->state != 0)
-               error(EBUSY, NULL);
+               error(EBUSY, ERROR_FIXME);
        c->state = Announcing;
        c->cerr[0] = '\0';
        if (x->announce == NULL)
                error(EFAIL, "announce not supported");
-       p = x->announce(c, cb->f, cb->nf);
-       if (p != NULL)
-               error(EFAIL, p);
+       x->announce(c, cb->f, cb->nf);
 
        qunlock(&c->qlock);
        if (waserror()) {
@@ -1109,48 +1109,48 @@ static void announcectlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
 /*
  *  called by protocol bind routine to set addresses
  */
-char *Fsstdbind(struct conv *c, char *argv[], int argc)
+void Fsstdbind(struct conv *c, char *argv[], int argc)
 {
        switch (argc) {
                default:
-                       return "bad args to bind";
+                       error(EINVAL, "bad args to bind");
                case 2:
-                       return setladdrport(c, argv[1], 0);
+                       setladdrport(c, argv[1], 0);
+                       break;
        }
 }
 
-void Fsconvnonblock(struct conv *cv, bool onoff)
-{
-       qnonblock(cv->wq, onoff);
-       qnonblock(cv->rq, onoff);
-       cv->nonblock = onoff;
-}
-
 static void bindctlmsg(struct Proto *x, struct conv *c, struct cmdbuf *cb)
 {
-       char *p;
-
        if (x->bind == NULL)
-               p = Fsstdbind(c, cb->f, cb->nf);
+               Fsstdbind(c, cb->f, cb->nf);
        else
-               p = x->bind(c, cb->f, cb->nf);
-       if (p != NULL)
-               error(EFAIL, p);
+               x->bind(c, cb->f, cb->nf);
 }
 
-static void nonblockctlmsg(struct conv *c, struct cmdbuf *cb)
+static void shutdownctlmsg(struct conv *cv, struct cmdbuf *cb)
 {
        if (cb->nf < 2)
                goto err;
-       if (!strcmp(cb->f[1], "on"))
-               Fsconvnonblock(c, TRUE);
-       else if (!strcmp(cb->f[1], "off"))
-               Fsconvnonblock(c, FALSE);
-       else
+       if (!strcmp(cb->f[1], "rd")) {
+               qhangup(cv->rq, "shutdown");
+               if (cv->p->shutdown)
+                       cv->p->shutdown(cv, SHUT_RD);
+       } else if (!strcmp(cb->f[1], "wr")) {
+               qhangup(cv->wq, "shutdown");
+               if (cv->p->shutdown)
+                       cv->p->shutdown(cv, SHUT_WR);
+       } else if (!strcmp(cb->f[1], "rdwr")) {
+               qhangup(cv->rq, "shutdown");
+               qhangup(cv->wq, "shutdown");
+               if (cv->p->shutdown)
+                       cv->p->shutdown(cv, SHUT_RDWR);
+       } else {
                goto err;
+       }
        return;
 err:
-       error(EINVAL, "nonblock [on|off]");
+       error(EINVAL, "shutdown [rx|tx|rxtx]");
 }
 
 static void tosctlmsg(struct conv *c, struct cmdbuf *cb)
@@ -1185,11 +1185,14 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
 
        switch (TYPE(ch->qid)) {
                default:
-                       error(EPERM, NULL);
+                       error(EPERM, ERROR_FIXME);
                case Qdata:
                        x = f->p[PROTO(ch->qid)];
                        c = x->conv[CONV(ch->qid)];
-                       qwrite(c->wq, a, n);
+                       if (ch->flag & O_NONBLOCK)
+                               qwrite_nonblock(c->wq, a, n);
+                       else
+                               qwrite(c->wq, a, n);
                        break;
                case Qarp:
                        return arpwrite(f, a, n);
@@ -1219,8 +1222,8 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
                                announcectlmsg(x, c, cb);
                        else if (strcmp(cb->f[0], "bind") == 0)
                                bindctlmsg(x, c, cb);
-                       else if (strcmp(cb->f[0], "nonblock") == 0)
-                               nonblockctlmsg(c, cb);
+                       else if (strcmp(cb->f[0], "shutdown") == 0)
+                               shutdownctlmsg(c, cb);
                        else if (strcmp(cb->f[0], "ttl") == 0)
                                ttlctlmsg(c, cb);
                        else if (strcmp(cb->f[0], "tos") == 0)
@@ -1250,9 +1253,7 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
                                parseip(ia, cb->f[1]);
                                ipifcremmulti(c, c->raddr, ia);
                        } else if (x->ctl != NULL) {
-                               p = x->ctl(c, cb->f, cb->nf);
-                               if (p != NULL)
-                                       error(EFAIL, p);
+                               x->ctl(c, cb->f, cb->nf);
                        } else
                                error(EFAIL, "unknown control request");
                        qunlock(&c->qlock);
@@ -1265,19 +1266,18 @@ static long ipwrite(struct chan *ch, void *v, long n, int64_t off)
 static long ipbwrite(struct chan *ch, struct block *bp, uint32_t offset)
 {
        struct conv *c;
-       struct Proto *x;
-       struct Fs *f;
        int n;
 
        switch (TYPE(ch->qid)) {
                case Qdata:
-                       f = ipfs[ch->dev];
-                       x = f->p[PROTO(ch->qid)];
-                       c = x->conv[CONV(ch->qid)];
+                       c = chan2conv(ch);
                        if (bp->next)
                                bp = concatblock(bp);
                        n = BLEN(bp);
-                       qbwrite(c->wq, bp);
+                       if (ch->flag & O_NONBLOCK)
+                               qbwrite_nonblock(c->wq, bp);
+                       else
+                               qbwrite(c->wq, bp);
                        return n;
                default:
                        return devbwrite(ch, bp, offset);
@@ -1322,26 +1322,20 @@ static void ip_wake_cb(struct queue *q, void *data, int filter)
 
 int iptapfd(struct chan *chan, struct fd_tap *tap, int cmd)
 {
-       struct conv *conv;
-       struct Proto *x;
-       struct Fs *f;
+       struct conv *conv = chan2conv(chan);
        int ret;
 
        #define DEVIP_LEGAL_DATA_TAPS (FDTAP_FILT_READABLE | FDTAP_FILT_WRITABLE | \
-                                      FDTAP_FILT_HANGUP)
+                                      FDTAP_FILT_HANGUP | FDTAP_FILT_PRIORITY |   \
+                                      FDTAP_FILT_ERROR)
        #define DEVIP_LEGAL_LISTEN_TAPS (FDTAP_FILT_READABLE | FDTAP_FILT_HANGUP)
 
-       /* That's a lot of pointers to get to the conv! */
-       f = ipfs[chan->dev];
-       x = f->p[PROTO(chan->qid)];
-       conv = x->conv[CONV(chan->qid)];
-
        switch (TYPE(chan->qid)) {
                case Qdata:
                        if (tap->filter & ~DEVIP_LEGAL_DATA_TAPS) {
                                set_errno(ENOSYS);
-                               set_errstr("Unsupported #%s data tap, must be %p", devname(),
-                                          DEVIP_LEGAL_DATA_TAPS);
+                               set_errstr("Unsupported #%s data tap %p, must be %p", devname(),
+                                          tap->filter, DEVIP_LEGAL_DATA_TAPS);
                                return -1;
                        }
                        spin_lock(&conv->tap_lock);
@@ -1373,8 +1367,8 @@ int iptapfd(struct chan *chan, struct fd_tap *tap, int cmd)
                case Qlisten:
                        if (tap->filter & ~DEVIP_LEGAL_LISTEN_TAPS) {
                                set_errno(ENOSYS);
-                               set_errstr("Unsupported #%s listen tap, must be %p", devname(),
-                                          DEVIP_LEGAL_LISTEN_TAPS);
+                               set_errstr("Unsupported #%s listen tap %p, must be %p",
+                                          devname(), tap->filter, DEVIP_LEGAL_LISTEN_TAPS);
                                return -1;
                        }
                        spin_lock(&conv->tap_lock);
@@ -1478,7 +1472,7 @@ retry:
                if (c == NULL) {
                        c = kzmalloc(sizeof(struct conv), 0);
                        if (c == NULL)
-                               error(ENOMEM, NULL);
+                               error(ENOMEM, ERROR_FIXME);
                        qlock_init(&c->qlock);
                        qlock_init(&c->listenq);
                        rendez_init(&c->cr);
@@ -1493,7 +1487,7 @@ retry:
                                c->ptcl = kzmalloc(p->ptclsize, 0);
                                if (c->ptcl == NULL) {
                                        kfree(c);
-                                       error(ENOMEM, NULL);
+                                       error(ENOMEM, ERROR_FIXME);
                                }
                        }
                        *pp = c;
@@ -1533,7 +1527,6 @@ retry:
        c->restricted = 0;
        c->ttl = MAXTTL;
        c->tos = DFLTTOS;
-       c->nonblock = FALSE;
        qreopen(c->rq);
        qreopen(c->wq);
        qreopen(c->eq);
@@ -1545,10 +1538,9 @@ retry:
 int Fsconnected(struct conv *c, char *msg)
 {
        if (msg != NULL && *msg != '\0')
-               strncpy(c->cerr, msg, sizeof(c->cerr));
+               strlcpy(c->cerr, msg, sizeof(c->cerr));
 
        switch (c->state) {
-
                case Announcing:
                        c->state = Announced;
                        break;
@@ -1631,9 +1623,9 @@ struct conv *Fsnewcall(struct conv *c, uint8_t * raddr, uint16_t rport,
 static long ndbwrite(struct Fs *f, char *a, uint32_t off, int n)
 {
        if (off > strlen(f->ndb))
-               error(EIO, NULL);
+               error(EIO, ERROR_FIXME);
        if (off + n >= sizeof(f->ndb) - 1)
-               error(EIO, NULL);
+               error(EIO, ERROR_FIXME);
        memmove(f->ndb + off, a, n);
        f->ndb[off + n] = 0;
        f->ndbvers++;