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