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