vfs: Remove KFS, blockdev and devfs
[akaros.git] / kern / src / net / netif.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <slab.h>
31 #include <kmalloc.h>
32 #include <kref.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <assert.h>
36 #include <error.h>
37 #include <cpio.h>
38 #include <pmap.h>
39 #include <smp.h>
40 #include <net/ip.h>
41
42 static int netown(struct netfile *, char *unused_char_p_t, int);
43 static int openfile(struct ether *, int);
44 static char *matchtoken(char *unused_char_p_t, char *);
45 static char *netmulti(struct ether *, struct netfile *,
46                                           uint8_t * unused_uint8_p_t, int);
47 static int parseaddr(uint8_t * unused_uint8_p_t, char *unused_char_p_t, int);
48
49 /*
50  *  set up a new network interface
51  */
52 void netifinit(struct ether *nif, char *name, int nfile, uint32_t limit)
53 {
54         qlock_init(&nif->qlock);
55         strlcpy(nif->name, name, KNAMELEN);
56         nif->nfile = nfile;
57         nif->f = kzmalloc(nfile * sizeof(struct netfile *), 0);
58         if (nif->f)
59                 memset(nif->f, 0, nfile * sizeof(struct netfile *));
60         else
61                 nif->nfile = 0;
62         nif->limit = limit;
63 }
64
65 /*
66  *  generate a 3 level directory
67  */
68 static int
69 netifgen(struct chan *c, char *unused_char_p_t, struct dirtab *vp,
70                  int unused_int, int i, struct dir *dp)
71 {
72         struct qid q;
73         struct ether *nif = (struct ether *)vp;
74         struct netfile *f;
75         int perm;
76         char *o;
77
78         q.type = QTFILE;
79         q.vers = 0;
80
81         /* top level directory contains the name of the network */
82         if (c->qid.path == 0) {
83                 switch (i) {
84                         case DEVDOTDOT:
85                                 q.path = 0;
86                                 q.type = QTDIR;
87                                 devdir(c, q, ".", 0, eve.name, 0555, dp);
88                                 break;
89                         case 0:
90                                 q.path = N2ndqid;
91                                 q.type = QTDIR;
92                                 strlcpy(get_cur_genbuf(), nif->name, GENBUF_SZ);
93                                 devdir(c, q, get_cur_genbuf(), 0, eve.name, 0555, dp);
94                                 break;
95                         default:
96                                 return -1;
97                 }
98                 return 1;
99         }
100
101         /* second level contains clone plus all the conversations.
102          *
103          * This ancient comment is from plan9.  Inferno and nxm both had issues
104          * here.  You couldn't ls /net/ether0/ when it didn't have any convs.  There
105          * were also issues with nxm where you couldn't stat ether0/x/stats
106          * properly.
107          *
108          * The issue is that if we handle things like Nstatqid, then we will never
109          * pass it down to the third level. And since we just set the path ==
110          * Nstatqid, we won't have the NETID muxed in. If someone isn't trying to
111          * generate a chan, but instead is looking it up (devwalk generates, devstat
112          * already has the chan), then they are also looking for a devdir with path
113          * containing ID << 5. So if you stat ether0/1/ifstats, devstat is looking
114          * for path 41, but we return path 9 (41 = 32 + 9). (these numbers are
115          * before we tracked NETID + 1).
116          *
117          * We (akaros and plan9) had a big if here, that would catch things that do
118          * not exist in the subdirs of a netif. Things like clone make sense here.
119          * I guess addr too, though that seems to be added since the original
120          * comment. You can see what the 3rd level was expecting to parse by looking
121          * farther down in the code.
122          *
123          * The root of the problem was that the old code couldn't tell the
124          * difference between no netid and netid 0. Now, we determine if we're at
125          * the second level by the lack of a netid, instead of trying to enumerate
126          * the qid types that the second level could have. The latter approach
127          * allowed for something like ether0/1/stats, but we couldn't actually
128          * devstat ether0/stats directly. It's worth noting that there is no
129          * difference to the content of ether0/stats and ether0/x/stats (when you
130          * read), but they have different chan qids.
131          *
132          * Here's the old if block:
133          t = NETTYPE(c->qid.path);
134          if (t == N2ndqid || t == Ncloneqid || t == Naddrqid) {
135          */
136         if (NETID(c->qid.path) == -1) {
137                 switch (i) {
138                         case DEVDOTDOT:
139                                 q.type = QTDIR;
140                                 q.path = 0;
141                                 devdir(c, q, ".", 0, eve.name, DMDIR | 0555, dp);
142                                 break;
143                         case 0:
144                                 q.path = Ncloneqid;
145                                 devdir(c, q, "clone", 0, eve.name, 0666, dp);
146                                 break;
147                         case 1:
148                                 q.path = Naddrqid;
149                                 devdir(c, q, "addr", 0, eve.name, 0666, dp);
150                                 break;
151                         case 2:
152                                 q.path = Nstatqid;
153                                 devdir(c, q, "stats", 0, eve.name, 0444, dp);
154                                 break;
155                         case 3:
156                                 q.path = Nifstatqid;
157                                 devdir(c, q, "ifstats", 0, eve.name, 0444, dp);
158                                 break;
159                         default:
160                                 i -= 4;
161                                 if (i >= nif->nfile)
162                                         return -1;
163                                 if (nif->f[i] == 0)
164                                         return 0;
165                                 q.type = QTDIR;
166                                 q.path = NETQID(i, N3rdqid);
167                                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%d", i);
168                                 devdir(c, q, get_cur_genbuf(), 0, eve.name, DMDIR | 0555, dp);
169                                 break;
170                 }
171                 return 1;
172         }
173
174         /* third level */
175         f = nif->f[NETID(c->qid.path)];
176         if (f == 0)
177                 return 0;
178         if (*f->owner) {
179                 o = f->owner;
180                 perm = f->mode;
181         } else {
182                 o = eve.name;
183                 perm = 0666;
184         }
185         switch (i) {
186                 case DEVDOTDOT:
187                         q.type = QTDIR;
188                         q.path = N2ndqid;
189                         strlcpy(get_cur_genbuf(), nif->name, GENBUF_SZ);
190                         devdir(c, q, get_cur_genbuf(), 0, eve.name, DMDIR | 0555, dp);
191                         break;
192                 case 0:
193                         q.path = NETQID(NETID(c->qid.path), Ndataqid);
194                         devdir(c, q, "data", 0, o, perm, dp);
195                         break;
196                 case 1:
197                         q.path = NETQID(NETID(c->qid.path), Nctlqid);
198                         devdir(c, q, "ctl", 0, o, perm, dp);
199                         break;
200                 case 2:
201                         q.path = NETQID(NETID(c->qid.path), Nstatqid);
202                         devdir(c, q, "stats", 0, eve.name, 0444, dp);
203                         break;
204                 case 3:
205                         q.path = NETQID(NETID(c->qid.path), Ntypeqid);
206                         devdir(c, q, "type", 0, eve.name, 0444, dp);
207                         break;
208                 case 4:
209                         q.path = NETQID(NETID(c->qid.path), Nifstatqid);
210                         devdir(c, q, "ifstats", 0, eve.name, 0444, dp);
211                         break;
212                 default:
213                         return -1;
214         }
215         return 1;
216 }
217
218 struct walkqid *netifwalk(struct ether *nif, struct chan *c, struct chan *nc,
219                                                   char **name, int nname)
220 {
221         return devwalk(c, nc, name, nname, (struct dirtab *)nif, 0, netifgen);
222 }
223
224 struct chan *netifopen(struct ether *nif, struct chan *c, int omode)
225 {
226         int id;
227         struct netfile *f;
228
229         id = 0;
230         if (c->qid.type & QTDIR) {
231                 if (omode & O_WRITE)
232                         error(EPERM, ERROR_FIXME);
233         } else {
234                 switch (NETTYPE(c->qid.path)) {
235                         case Ndataqid:
236                         case Nctlqid:
237                                 id = NETID(c->qid.path);
238                                 openfile(nif, id);
239                                 break;
240                         case Ncloneqid:
241                                 id = openfile(nif, -1);
242                                 c->qid.path = NETQID(id, Nctlqid);
243                                 break;
244                         default:
245                                 if (omode & O_WRITE)
246                                         error(EINVAL, ERROR_FIXME);
247                 }
248                 switch (NETTYPE(c->qid.path)) {
249                         case Ndataqid:
250                         case Nctlqid:
251                                 f = nif->f[id];
252                                 if (netown(f, current->user.name, omode & 7) < 0)
253                                         error(EPERM, ERROR_FIXME);
254                                 break;
255                 }
256         }
257         c->mode = openmode(omode);
258         c->flag |= COPEN;
259         c->offset = 0;
260         c->iounit = qiomaxatomic;
261         return c;
262 }
263
264 /* Helper for building the features for netifread */
265 static int feature_appender(int features, char *p, int sofar)
266 {
267         if (features & NETF_IPCK)
268                 sofar += snprintf(p + sofar, READSTR - sofar, "ipck ");
269         if (features & NETF_UDPCK)
270                 sofar += snprintf(p + sofar, READSTR - sofar, "udpck ");
271         if (features & NETF_TCPCK)
272                 sofar += snprintf(p + sofar, READSTR - sofar, "tcpck ");
273         if (features & NETF_PADMIN)
274                 sofar += snprintf(p + sofar, READSTR - sofar, "padmin ");
275         if (features & NETF_SG)
276                 sofar += snprintf(p + sofar, READSTR - sofar, "sg ");
277         if (features & NETF_TSO)
278                 sofar += snprintf(p + sofar, READSTR - sofar, "tso ");
279         if (features & NETF_LRO)
280                 sofar += snprintf(p + sofar, READSTR - sofar, "lro ");
281         if (features & NETF_RXCSUM)
282                 sofar += snprintf(p + sofar, READSTR - sofar, "rxcsum ");
283         return sofar;
284 }
285
286 long
287 netifread(struct ether *nif, struct chan *c, void *a, long n,
288           uint32_t offset)
289 {
290         int i, j;
291         struct netfile *f;
292         char *p;
293
294         if (c->qid.type & QTDIR)
295                 return devdirread(c, a, n, (struct dirtab *)nif, 0, netifgen);
296
297         switch (NETTYPE(c->qid.path)) {
298                 case Ndataqid:
299                         f = nif->f[NETID(c->qid.path)];
300                         return qread(f->in, a, n);
301                 case Nctlqid:
302                         return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
303                 case Nstatqid:
304                         p = kzmalloc(READSTR, 0);
305                         if (p == NULL)
306                                 return 0;
307                         j = 0;
308                         j += snprintf(p + j, READSTR - j, "driver: %s\n", nif->drv_name);
309                         j += snprintf(p + j, READSTR - j, "in: %d\n", nif->inpackets);
310                         j += snprintf(p + j, READSTR - j, "link: %d\n", nif->link);
311                         j += snprintf(p + j, READSTR - j, "out: %d\n", nif->outpackets);
312                         j += snprintf(p + j, READSTR - j, "crc errs: %d\n", nif->crcs);
313                         j += snprintf(p + j, READSTR - j, "overflows: %d\n",
314                                                   nif->overflows);
315                         j += snprintf(p + j, READSTR - j, "soft overflows: %d\n",
316                                                   nif->soverflows);
317                         j += snprintf(p + j, READSTR - j, "framing errs: %d\n",
318                                                   nif->frames);
319                         j += snprintf(p + j, READSTR - j, "buffer errs: %d\n", nif->buffs);
320                         j += snprintf(p + j, READSTR - j, "output errs: %d\n", nif->oerrs);
321                         j += snprintf(p + j, READSTR - j, "prom: %d\n", nif->prom);
322                         j += snprintf(p + j, READSTR - j, "mbps: %d\n", nif->mbps);
323                         j += snprintf(p + j, READSTR - j, "addr: ");
324                         for (i = 0; i < nif->alen; i++)
325                                 j += snprintf(p + j, READSTR - j, "%02.2x", nif->addr[i]);
326                         j += snprintf(p + j, READSTR - j, "\n");
327
328                         j += snprintf(p + j, READSTR - j, "feat: ");
329                         j = feature_appender(nif->feat, p, j);
330                         j += snprintf(p + j, READSTR - j, "\n");
331
332                         j += snprintf(p + j, READSTR - j, "hw_features: ");
333                         j = feature_appender(nif->hw_features, p, j);
334                         j += snprintf(p + j, READSTR - j, "\n");
335
336                         n = readstr(offset, a, n, p);
337                         kfree(p);
338                         return n;
339                 case Naddrqid:
340                         p = kzmalloc(READSTR, 0);
341                         if (p == NULL)
342                                 return 0;
343                         j = 0;
344                         for (i = 0; i < nif->alen; i++)
345                                 j += snprintf(p + j, READSTR - j, "%02.2x", nif->addr[i]);
346                         n = readstr(offset, a, n, p);
347                         kfree(p);
348                         return n;
349                 case Ntypeqid:
350                         f = nif->f[NETID(c->qid.path)];
351                         return readnum(offset, a, n, f->type, NUMSIZE);
352                 case Nifstatqid:
353                         return 0;
354         }
355         error(EINVAL, ERROR_FIXME);
356         return -1;      /* not reached */
357 }
358
359 struct block *netifbread(struct ether *nif, struct chan *c, long n,
360                                                  uint32_t offset)
361 {
362         if ((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
363                 return devbread(c, n, offset);
364
365         return qbread(nif->f[NETID(c->qid.path)]->in, n);
366 }
367
368 /*
369  *  make sure this type isn't already in use on this device
370  */
371 static int typeinuse(struct ether *nif, int type)
372 {
373         struct netfile *f, **fp, **efp;
374
375         if (type <= 0)
376                 return 0;
377
378         efp = &nif->f[nif->nfile];
379         for (fp = nif->f; fp < efp; fp++) {
380                 f = *fp;
381                 if (f == 0)
382                         continue;
383                 if (f->type == type)
384                         return 1;
385         }
386         return 0;
387 }
388
389 /*
390  *  the devxxx.c that calls us handles writing data, it knows best
391  */
392 long netifwrite(struct ether *nif, struct chan *c, void *a, long n)
393 {
394         ERRSTACK(1);
395         struct netfile *f;
396         int type;
397         char *p, buf[64];
398         uint8_t binaddr[Nmaxaddr];
399
400         if (NETTYPE(c->qid.path) != Nctlqid)
401                 error(EPERM, ERROR_FIXME);
402
403         if (n >= sizeof(buf))
404                 n = sizeof(buf) - 1;
405         memmove(buf, a, n);
406         buf[n] = 0;
407
408         qlock(&nif->qlock);
409         if (waserror()) {
410                 qunlock(&nif->qlock);
411                 nexterror();
412         }
413
414         f = nif->f[NETID(c->qid.path)];
415         if ((p = matchtoken(buf, "connect")) != 0) {
416                 /* We'd like to not use the NIC until it has come up fully -
417                  * auto-negotiation is done and packets will get sent out.  This is
418                  * about the best place to do it. */
419                 netif_wait_for_carrier(nif);
420                 type = strtol(p, 0, 0); /* allows any base, though usually hex */
421                 if (typeinuse(nif, type))
422                         error(EBUSY, ERROR_FIXME);
423                 f->type = type;
424                 if (f->type < 0)
425                         nif->all++;
426         } else if (matchtoken(buf, "promiscuous")) {
427                 if (f->prom == 0) {
428                         /* Note that promisc has two meanings: put the NIC into promisc
429                          * mode, and record our outbound traffic.  See etheroq(). */
430                         /* TODO: consider porting linux's interface for set_rx_mode. */
431                         if (nif->prom == 0 && nif->promiscuous != NULL)
432                                 nif->promiscuous(nif->arg, 1);
433                         f->prom = 1;
434                         nif->prom++;
435                 }
436         } else if ((p = matchtoken(buf, "scanbs")) != 0) {
437                 /* scan for base stations */
438                 if (f->scan == 0) {
439                         type = strtol(p, 0, 0); /* allows any base, though usually hex */
440                         if (type < 5)
441                                 type = 5;
442                         if (nif->scanbs != NULL)
443                                 nif->scanbs(nif->arg, type);
444                         f->scan = type;
445                         nif->scan++;
446                 }
447         } else if (matchtoken(buf, "bridge")) {
448                 f->bridge = 1;
449         } else if (matchtoken(buf, "headersonly")) {
450                 f->headersonly = 1;
451         } else if ((p = matchtoken(buf, "addmulti")) != 0) {
452                 if (parseaddr(binaddr, p, nif->alen) < 0)
453                         error(EFAIL, "bad address");
454                 p = netmulti(nif, f, binaddr, 1);
455                 if (p)
456                         error(EFAIL, p);
457         } else if ((p = matchtoken(buf, "remmulti")) != 0) {
458                 if (parseaddr(binaddr, p, nif->alen) < 0)
459                         error(EFAIL, "bad address");
460                 p = netmulti(nif, f, binaddr, 0);
461                 if (p)
462                         error(EFAIL, p);
463         } else if (matchtoken(buf, "oneblock")) {
464                 /* Qmsg + Qcoal = one block at a time. */
465                 q_toggle_qmsg(f->in, TRUE);
466                 q_toggle_qcoalesce(f->in, TRUE);
467         } else
468                 n = -1;
469         qunlock(&nif->qlock);
470         poperror();
471         return n;
472 }
473
474 int netifwstat(struct ether *nif, struct chan *c, uint8_t * db, int n)
475 {
476         struct dir *dir;
477         struct netfile *f;
478         int m;
479
480         f = nif->f[NETID(c->qid.path)];
481         if (f == 0)
482                 error(ENOENT, ERROR_FIXME);
483
484         if (netown(f, current->user.name, O_WRITE) < 0)
485                 error(EPERM, ERROR_FIXME);
486
487         dir = kzmalloc(sizeof(struct dir) + n, 0);
488         m = convM2D(db, n, &dir[0], (char *)&dir[1]);
489         if (m == 0) {
490                 kfree(dir);
491                 error(ENODATA, ERROR_FIXME);
492         }
493         if (!emptystr(dir[0].uid))
494                 strlcpy(f->owner, dir[0].uid, KNAMELEN);
495         if (dir[0].mode != -1)
496                 f->mode = dir[0].mode;
497         kfree(dir);
498         return m;
499 }
500
501 int netifstat(struct ether *nif, struct chan *c, uint8_t * db, int n)
502 {
503         return devstat(c, db, n, (struct dirtab *)nif, 0, netifgen);
504 }
505
506 void netifclose(struct ether *nif, struct chan *c)
507 {
508         struct netfile *f;
509         int t;
510         struct netaddr *ap;
511
512         if ((c->flag & COPEN) == 0)
513                 return;
514
515         t = NETTYPE(c->qid.path);
516         if (t != Ndataqid && t != Nctlqid)
517                 return;
518
519         f = nif->f[NETID(c->qid.path)];
520         qlock(&f->qlock);
521         if (--(f->inuse) == 0) {
522                 if (f->prom) {
523                         qlock(&nif->qlock);
524                         if (--(nif->prom) == 0 && nif->promiscuous != NULL)
525                                 nif->promiscuous(nif->arg, 0);
526                         qunlock(&nif->qlock);
527                         f->prom = 0;
528                 }
529                 if (f->scan) {
530                         qlock(&nif->qlock);
531                         if (--(nif->scan) == 0 && nif->scanbs != NULL)
532                                 nif->scanbs(nif->arg, 0);
533                         qunlock(&nif->qlock);
534                         f->prom = 0;
535                         f->scan = 0;
536                 }
537                 if (f->nmaddr) {
538                         qlock(&nif->qlock);
539                         t = 0;
540                         for (ap = nif->maddr; ap; ap = ap->next) {
541                                 if (f->maddr[t / 8] & (1 << (t % 8)))
542                                         netmulti(nif, f, ap->addr, 0);
543                         }
544                         qunlock(&nif->qlock);
545                         f->nmaddr = 0;
546                 }
547                 if (f->type < 0) {
548                         qlock(&nif->qlock);
549                         --(nif->all);
550                         qunlock(&nif->qlock);
551                 }
552                 f->owner[0] = 0;
553                 f->type = 0;
554                 f->bridge = 0;
555                 f->headersonly = 0;
556                 qclose(f->in);
557         }
558         qunlock(&f->qlock);
559 }
560
561 spinlock_t netlock = SPINLOCK_INITIALIZER;
562
563 static int netown(struct netfile *p, char *o, int omode)
564 {
565         int mode;
566         int rwx;
567
568         spin_lock(&netlock);
569         if (*p->owner) {
570                 if (strncmp(o, p->owner, KNAMELEN) == 0)        /* User */
571                         mode = p->mode;
572                 else if (strncmp(o, eve.name, KNAMELEN) == 0)   /* Bootes is group */
573                         mode = p->mode << 3;
574                 else
575                         mode = p->mode << 6;    /* Other */
576
577                 rwx = omode_to_rwx(omode);
578                 if ((rwx & mode) == rwx) {
579                         spin_unlock(&netlock);
580                         return 0;
581                 } else {
582                         spin_unlock(&netlock);
583                         return -1;
584                 }
585         }
586         strlcpy(p->owner, o, KNAMELEN);
587         p->mode = 0660;
588         spin_unlock(&netlock);
589         return 0;
590 }
591
592 /*
593  *  Increment the reference count of a network device.
594  *  If id < 0, return an unused ether device.
595  */
596 static int openfile(struct ether *nif, int id)
597 {
598         ERRSTACK(1);
599         struct netfile *f, **fp, **efp;
600
601         if (id >= 0) {
602                 f = nif->f[id];
603                 if (f == 0)
604                         error(ENODEV, ERROR_FIXME);
605                 qlock(&f->qlock);
606                 qreopen(f->in);
607                 f->inuse++;
608                 qunlock(&f->qlock);
609                 return id;
610         }
611
612         qlock(&nif->qlock);
613         if (waserror()) {
614                 qunlock(&nif->qlock);
615                 nexterror();
616         }
617         efp = &nif->f[nif->nfile];
618         for (fp = nif->f; fp < efp; fp++) {
619                 f = *fp;
620                 if (f == 0) {
621                         f = kzmalloc(sizeof(struct netfile), 0);
622                         if (f == 0)
623                                 exhausted("memory");
624                         /* since we lock before netifinit (if we ever call that...) */
625                         qlock_init(&f->qlock);
626                         f->in = qopen(nif->limit, Qmsg, 0, 0);
627                         if (f->in == NULL) {
628                                 kfree(f);
629                                 exhausted("memory");
630                         }
631                         *fp = f;
632                         qlock(&f->qlock);
633                 } else {
634                         qlock(&f->qlock);
635                         if (f->inuse) {
636                                 qunlock(&f->qlock);
637                                 continue;
638                         }
639                 }
640                 f->inuse = 1;
641                 qreopen(f->in);
642                 netown(f, current->user.name, 0);
643                 qunlock(&f->qlock);
644                 qunlock(&nif->qlock);
645                 poperror();
646                 return fp - nif->f;
647         }
648         error(ENODEV, ERROR_FIXME);
649         return -1;      /* not reached */
650 }
651
652 /*
653  *  look for a token starting a string,
654  *  return a pointer to first non-space char after it
655  */
656 static char *matchtoken(char *p, char *token)
657 {
658         int n;
659
660         n = strlen(token);
661         if (strncmp(p, token, n))
662                 return 0;
663         p += n;
664         if (*p == 0)
665                 return p;
666         if (*p != ' ' && *p != '\t' && *p != '\n')
667                 return 0;
668         while (*p == ' ' || *p == '\t' || *p == '\n')
669                 p++;
670         return p;
671 }
672
673 static uint32_t hash(uint8_t * a, int len)
674 {
675         uint32_t sum = 0;
676
677         while (len-- > 0)
678                 sum = (sum << 1) + *a++;
679         return sum % Nmhash;
680 }
681
682 int activemulti(struct ether *nif, uint8_t * addr, int alen)
683 {
684         struct netaddr *hp;
685
686         for (hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
687                 if (memcmp(addr, hp->addr, alen) == 0) {
688                         if (hp->ref)
689                                 return 1;
690                         else
691                                 break;
692                 }
693         return 0;
694 }
695
696 static int parseaddr(uint8_t * to, char *from, int alen)
697 {
698         char nip[4];
699         char *p;
700         int i;
701
702         p = from;
703         for (i = 0; i < alen; i++) {
704                 if (*p == 0)
705                         return -1;
706                 nip[0] = *p++;
707                 if (*p == 0)
708                         return -1;
709                 nip[1] = *p++;
710                 nip[2] = 0;
711                 to[i] = strtoul(nip, 0, 16);
712                 if (*p == ':')
713                         p++;
714         }
715         return 0;
716 }
717
718 /*
719  *  keep track of multicast addresses
720  */
721 static char *netmulti(struct ether *nif, struct netfile *f, uint8_t * addr,
722                                           int add)
723 {
724         struct netaddr **l, *ap;
725         int i;
726         uint32_t h;
727
728         if (nif->multicast == NULL)
729                 return "interface does not support multicast";
730
731         l = &nif->maddr;
732         i = 0;
733         for (ap = *l; ap; ap = *l) {
734                 if (memcmp(addr, ap->addr, nif->alen) == 0)
735                         break;
736                 i++;
737                 l = &ap->next;
738         }
739
740         if (add) {
741                 if (ap == 0) {
742                         /* TODO: AFAIK, this never gets freed.  if we fix that, we can use a
743                          * kref too (instead of int ap->ref). */
744                         *l = ap = kzmalloc(sizeof(*ap), 0);
745                         memmove(ap->addr, addr, nif->alen);
746                         ap->next = 0;
747                         ap->ref = 1;
748                         h = hash(addr, nif->alen);
749                         ap->hnext = nif->mhash[h];
750                         nif->mhash[h] = ap;
751                 } else {
752                         ap->ref++;
753                 }
754                 if (ap->ref == 1) {
755                         nif->nmaddr++;
756                         nif->multicast(nif->arg, addr, 1);
757                 }
758                 if (i < 8 * sizeof(f->maddr)) {
759                         if ((f->maddr[i / 8] & (1 << (i % 8))) == 0)
760                                 f->nmaddr++;
761                         f->maddr[i / 8] |= 1 << (i % 8);
762                 }
763         } else {
764                 if (ap == 0 || ap->ref == 0)
765                         return 0;
766                 ap->ref--;
767                 if (ap->ref == 0) {
768                         nif->nmaddr--;
769                         nif->multicast(nif->arg, addr, 0);
770                 }
771                 if (i < 8 * sizeof(f->maddr)) {
772                         if ((f->maddr[i / 8] & (1 << (i % 8))) != 0)
773                                 f->nmaddr--;
774                         f->maddr[i / 8] &= ~(1 << (i % 8));
775                 }
776         }
777         return 0;
778 }
779
780 /* Prints the contents of stats to [va + offset, va + offset + amt). */
781 ssize_t linux_ifstat(struct netif_stats *stats, void *va, size_t amt,
782                      off_t offset)
783 {
784         char *p;
785         size_t sofar = 0;
786         ssize_t ret;
787
788         p = kzmalloc(READSTR, MEM_WAIT);
789         sofar += snprintf(p + sofar, READSTR - sofar,
790                           "rx pkts            : %lu\n", stats->rx_packets);
791         sofar += snprintf(p + sofar, READSTR - sofar,
792                           "tx pkts            : %lu\n", stats->tx_packets);
793         sofar += snprintf(p + sofar, READSTR - sofar,
794                           "rx bytes           : %lu\n", stats->rx_bytes);
795         sofar += snprintf(p + sofar, READSTR - sofar,
796                           "tx bytes           : %lu\n", stats->tx_bytes);
797         sofar += snprintf(p + sofar, READSTR - sofar,
798                           "rx errors          : %lu\n", stats->rx_errors);
799         sofar += snprintf(p + sofar, READSTR - sofar,
800                           "tx errors          : %lu\n", stats->tx_errors);
801         sofar += snprintf(p + sofar, READSTR - sofar,
802                           "rx dropped         : %lu\n", stats->rx_dropped);
803         sofar += snprintf(p + sofar, READSTR - sofar,
804                           "tx dropped         : %lu\n", stats->tx_dropped);
805         sofar += snprintf(p + sofar, READSTR - sofar,
806                           "multicast          : %lu\n", stats->multicast);
807         sofar += snprintf(p + sofar, READSTR - sofar,
808                           "collisions         : %lu\n", stats->collisions);
809         sofar += snprintf(p + sofar, READSTR - sofar, "\n");
810
811         sofar += snprintf(p + sofar, READSTR - sofar,
812                           "rx length errors   : %lu\n", stats->rx_length_errors);
813         sofar += snprintf(p + sofar, READSTR - sofar,
814                           "rx over errors     : %lu\n", stats->rx_over_errors);
815         sofar += snprintf(p + sofar, READSTR - sofar,
816                           "rx crc errors      : %lu\n", stats->rx_crc_errors);
817         sofar += snprintf(p + sofar, READSTR - sofar,
818                           "rx frame errors    : %lu\n", stats->rx_frame_errors);
819         sofar += snprintf(p + sofar, READSTR - sofar,
820                           "rx fifo errors     : %lu\n", stats->rx_fifo_errors);
821         sofar += snprintf(p + sofar, READSTR - sofar,
822                           "rx missed errors   : %lu\n", stats->rx_missed_errors);
823         sofar += snprintf(p + sofar, READSTR - sofar, "\n");
824
825         sofar += snprintf(p + sofar, READSTR - sofar,
826                           "tx aborted errors  : %lu\n", stats->tx_aborted_errors);
827         sofar += snprintf(p + sofar, READSTR - sofar,
828                           "tx carrier errors  : %lu\n", stats->tx_carrier_errors);
829         sofar += snprintf(p + sofar, READSTR - sofar,
830                           "tx fifo errors     : %lu\n", stats->tx_fifo_errors);
831         sofar += snprintf(p + sofar, READSTR - sofar,
832                           "tx heartbeat errors: %lu\n", stats->tx_heartbeat_errors);
833         sofar += snprintf(p + sofar, READSTR - sofar,
834                           "tx window errors   : %lu\n", stats->tx_window_errors);
835         sofar += snprintf(p + sofar, READSTR - sofar, "\n");
836
837         sofar += snprintf(p + sofar, READSTR - sofar,
838                           "rx compressed      : %lu\n", stats->rx_compressed);
839         sofar += snprintf(p + sofar, READSTR - sofar,
840                           "tx compressed      : %lu\n", stats->tx_compressed);
841         sofar += snprintf(p + sofar, READSTR - sofar,
842                           "rx nohandler       : %lu\n", stats->rx_nohandler);
843         ret = readstr(offset, va, amt, p);
844         kfree(p);
845         return ret;
846 }