Fix waserror/lock order
[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 <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, 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, 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, DMDIR | 0555, dp);
143                                 break;
144                         case 0:
145                                 q.path = Ncloneqid;
146                                 devdir(c, q, "clone", 0, eve, 0666, dp);
147                                 break;
148                         case 1:
149                                 q.path = Naddrqid;
150                                 devdir(c, q, "addr", 0, eve, 0666, dp);
151                                 break;
152                         case 2:
153                                 q.path = Nstatqid;
154                                 devdir(c, q, "stats", 0, eve, 0444, dp);
155                                 break;
156                         case 3:
157                                 q.path = Nifstatqid;
158                                 devdir(c, q, "ifstats", 0, eve, 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, 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;
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, 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, 0444, dp);
204                         break;
205                 case 3:
206                         q.path = NETQID(NETID(c->qid.path), Ntypeqid);
207                         devdir(c, q, "type", 0, eve, 0444, dp);
208                         break;
209                 case 4:
210                         q.path = NETQID(NETID(c->qid.path), Nifstatqid);
211                         devdir(c, q, "ifstats", 0, eve, 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, NULL);
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, NULL);
248                 }
249                 switch (NETTYPE(c->qid.path)) {
250                         case Ndataqid:
251                         case Nctlqid:
252                                 f = nif->f[id];
253                                 if (netown(f, current->user, omode & 7) < 0)
254                                         error(EPERM, NULL);
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 long
266 netifread(struct ether *nif, struct chan *c, void *a, long n,
267           uint32_t offset)
268 {
269         int i, j;
270         struct netfile *f;
271         char *p;
272
273         if (c->qid.type & QTDIR)
274                 return devdirread(c, a, n, (struct dirtab *)nif, 0, netifgen);
275
276         switch (NETTYPE(c->qid.path)) {
277                 case Ndataqid:
278                         f = nif->f[NETID(c->qid.path)];
279                         return qread(f->in, a, n);
280                 case Nctlqid:
281                         return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
282                 case Nstatqid:
283                         p = kzmalloc(READSTR, 0);
284                         if (p == NULL)
285                                 return 0;
286                         j = snprintf(p, READSTR, "in: %d\n", nif->inpackets);
287                         j += snprintf(p + j, READSTR - j, "link: %d\n", nif->link);
288                         j += snprintf(p + j, READSTR - j, "out: %d\n", nif->outpackets);
289                         j += snprintf(p + j, READSTR - j, "crc errs: %d\n", nif->crcs);
290                         j += snprintf(p + j, READSTR - j, "overflows: %d\n",
291                                                   nif->overflows);
292                         j += snprintf(p + j, READSTR - j, "soft overflows: %d\n",
293                                                   nif->soverflows);
294                         j += snprintf(p + j, READSTR - j, "framing errs: %d\n",
295                                                   nif->frames);
296                         j += snprintf(p + j, READSTR - j, "buffer errs: %d\n", nif->buffs);
297                         j += snprintf(p + j, READSTR - j, "output errs: %d\n", nif->oerrs);
298                         j += snprintf(p + j, READSTR - j, "prom: %d\n", nif->prom);
299                         j += snprintf(p + j, READSTR - j, "mbps: %d\n", nif->mbps);
300                         j += snprintf(p + j, READSTR - j, "addr: ");
301                         for (i = 0; i < nif->alen; i++)
302                                 j += snprintf(p + j, READSTR - j, "%02.2x", nif->addr[i]);
303                         j += snprintf(p + j, READSTR - j, "\n");
304                         j += snprintf(p + j, READSTR - j, "feat: ");
305                         if (nif->feat & NETF_IPCK)
306                                 j += snprintf(p + j, READSTR - j, "ipck ");
307                         if (nif->feat & NETF_UDPCK)
308                                 j += snprintf(p + j, READSTR - j, "udpck ");
309                         if (nif->feat & NETF_TCPCK)
310                                 j += snprintf(p + j, READSTR - j, "tcppck ");
311                         if (nif->feat & NETF_PADMIN)
312                                 j += snprintf(p + j, READSTR - j, "padmin ");
313                         if (nif->feat & NETF_SG)
314                                 j += snprintf(p + j, READSTR - j, "sg ");
315                         if (nif->feat & NETF_TSO)
316                                 j += snprintf(p + j, READSTR - j, "tso ");
317                         if (nif->feat & NETF_LRO)
318                                 j += snprintf(p + j, READSTR - j, "lro ");
319                         snprintf(p + j, READSTR - j, "\n");
320                         n = readstr(offset, a, n, p);
321                         kfree(p);
322                         return n;
323                 case Naddrqid:
324                         p = kzmalloc(READSTR, 0);
325                         if (p == NULL)
326                                 return 0;
327                         j = 0;
328                         for (i = 0; i < nif->alen; i++)
329                                 j += snprintf(p + j, READSTR - j, "%02.2x", nif->addr[i]);
330                         n = readstr(offset, a, n, p);
331                         kfree(p);
332                         return n;
333                 case Ntypeqid:
334                         f = nif->f[NETID(c->qid.path)];
335                         return readnum(offset, a, n, f->type, NUMSIZE);
336                 case Nifstatqid:
337                         return 0;
338         }
339         error(EINVAL, NULL);
340         return -1;      /* not reached */
341 }
342
343 struct block *netifbread(struct ether *nif, struct chan *c, long n,
344                                                  uint32_t offset)
345 {
346         if ((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
347                 return devbread(c, n, offset);
348
349         return qbread(nif->f[NETID(c->qid.path)]->in, n);
350 }
351
352 /*
353  *  make sure this type isn't already in use on this device
354  */
355 static int typeinuse(struct ether *nif, int type)
356 {
357         struct netfile *f, **fp, **efp;
358
359         if (type <= 0)
360                 return 0;
361
362         efp = &nif->f[nif->nfile];
363         for (fp = nif->f; fp < efp; fp++) {
364                 f = *fp;
365                 if (f == 0)
366                         continue;
367                 if (f->type == type)
368                         return 1;
369         }
370         return 0;
371 }
372
373 /*
374  *  the devxxx.c that calls us handles writing data, it knows best
375  */
376 long netifwrite(struct ether *nif, struct chan *c, void *a, long n)
377 {
378         ERRSTACK(1);
379         struct netfile *f;
380         int type;
381         char *p, buf[64];
382         uint8_t binaddr[Nmaxaddr];
383
384         if (NETTYPE(c->qid.path) != Nctlqid)
385                 error(EPERM, NULL);
386
387         if (n >= sizeof(buf))
388                 n = sizeof(buf) - 1;
389         memmove(buf, a, n);
390         buf[n] = 0;
391
392         qlock(&nif->qlock);
393         if (waserror()) {
394                 qunlock(&nif->qlock);
395                 nexterror();
396         }
397
398         f = nif->f[NETID(c->qid.path)];
399         if ((p = matchtoken(buf, "connect")) != 0) {
400                 type = strtol(p, 0, 0); /* allows any base, though usually hex */
401                 if (typeinuse(nif, type))
402                         error(EBUSY, NULL);
403                 f->type = type;
404                 if (f->type < 0)
405                         nif->all++;
406         } else if (matchtoken(buf, "promiscuous")) {
407                 if (f->prom == 0) {
408                         if (nif->prom == 0 && nif->promiscuous != NULL)
409                                 nif->promiscuous(nif->arg, 1);
410                         f->prom = 1;
411                         nif->prom++;
412                 }
413         } else if ((p = matchtoken(buf, "scanbs")) != 0) {
414                 /* scan for base stations */
415                 if (f->scan == 0) {
416                         type = strtol(p, 0, 0); /* allows any base, though usually hex */
417                         if (type < 5)
418                                 type = 5;
419                         if (nif->scanbs != NULL)
420                                 nif->scanbs(nif->arg, type);
421                         f->scan = type;
422                         nif->scan++;
423                 }
424         } else if (matchtoken(buf, "bridge")) {
425                 f->bridge = 1;
426         } else if (matchtoken(buf, "headersonly")) {
427                 f->headersonly = 1;
428         } else if ((p = matchtoken(buf, "addmulti")) != 0) {
429                 if (parseaddr(binaddr, p, nif->alen) < 0)
430                         error(EFAIL, "bad address");
431                 p = netmulti(nif, f, binaddr, 1);
432                 if (p)
433                         error(EFAIL, p);
434         } else if ((p = matchtoken(buf, "remmulti")) != 0) {
435                 if (parseaddr(binaddr, p, nif->alen) < 0)
436                         error(EFAIL, "bad address");
437                 p = netmulti(nif, f, binaddr, 0);
438                 if (p)
439                         error(EFAIL, p);
440         } else
441                 n = -1;
442         qunlock(&nif->qlock);
443         poperror();
444         return n;
445 }
446
447 int netifwstat(struct ether *nif, struct chan *c, uint8_t * db, int n)
448 {
449         struct dir *dir;
450         struct netfile *f;
451         int m;
452
453         f = nif->f[NETID(c->qid.path)];
454         if (f == 0)
455                 error(ENOENT, NULL);
456
457         if (netown(f, current->user, O_WRITE) < 0)
458                 error(EPERM, NULL);
459
460         dir = kzmalloc(sizeof(struct dir) + n, 0);
461         m = convM2D(db, n, &dir[0], (char *)&dir[1]);
462         if (m == 0) {
463                 kfree(dir);
464                 error(ENODATA, NULL);
465         }
466         if (!emptystr(dir[0].uid))
467                 strlcpy(f->owner, dir[0].uid, KNAMELEN);
468         if (dir[0].mode != ~0UL)
469                 f->mode = dir[0].mode;
470         kfree(dir);
471         return m;
472 }
473
474 int netifstat(struct ether *nif, struct chan *c, uint8_t * db, int n)
475 {
476         return devstat(c, db, n, (struct dirtab *)nif, 0, netifgen);
477 }
478
479 void netifclose(struct ether *nif, struct chan *c)
480 {
481         struct netfile *f;
482         int t;
483         struct netaddr *ap;
484
485         if ((c->flag & COPEN) == 0)
486                 return;
487
488         t = NETTYPE(c->qid.path);
489         if (t != Ndataqid && t != Nctlqid)
490                 return;
491
492         f = nif->f[NETID(c->qid.path)];
493         qlock(&f->qlock);
494         if (--(f->inuse) == 0) {
495                 if (f->prom) {
496                         qlock(&nif->qlock);
497                         if (--(nif->prom) == 0 && nif->promiscuous != NULL)
498                                 nif->promiscuous(nif->arg, 0);
499                         qunlock(&nif->qlock);
500                         f->prom = 0;
501                 }
502                 if (f->scan) {
503                         qlock(&nif->qlock);
504                         if (--(nif->scan) == 0 && nif->scanbs != NULL)
505                                 nif->scanbs(nif->arg, 0);
506                         qunlock(&nif->qlock);
507                         f->prom = 0;
508                         f->scan = 0;
509                 }
510                 if (f->nmaddr) {
511                         qlock(&nif->qlock);
512                         t = 0;
513                         for (ap = nif->maddr; ap; ap = ap->next) {
514                                 if (f->maddr[t / 8] & (1 << (t % 8)))
515                                         netmulti(nif, f, ap->addr, 0);
516                         }
517                         qunlock(&nif->qlock);
518                         f->nmaddr = 0;
519                 }
520                 if (f->type < 0) {
521                         qlock(&nif->qlock);
522                         --(nif->all);
523                         qunlock(&nif->qlock);
524                 }
525                 f->owner[0] = 0;
526                 f->type = 0;
527                 f->bridge = 0;
528                 f->headersonly = 0;
529                 qclose(f->in);
530         }
531         qunlock(&f->qlock);
532 }
533
534 spinlock_t netlock = SPINLOCK_INITIALIZER;
535
536 static int netown(struct netfile *p, char *o, int omode)
537 {
538         static int access[] = { 0400, 0200, 0600, 0100 };
539         int mode;
540         int t;
541
542         spin_lock(&netlock);
543         if (*p->owner) {
544                 if (strncmp(o, p->owner, KNAMELEN) == 0)        /* User */
545                         mode = p->mode;
546                 else if (strncmp(o, eve, KNAMELEN) == 0)        /* Bootes is group */
547                         mode = p->mode << 3;
548                 else
549                         mode = p->mode << 6;    /* Other */
550
551                 t = access[omode & 3];
552                 if ((t & mode) == t) {
553                         spin_unlock(&netlock);
554                         return 0;
555                 } else {
556                         spin_unlock(&netlock);
557                         return -1;
558                 }
559         }
560         strlcpy(p->owner, o, KNAMELEN);
561         p->mode = 0660;
562         spin_unlock(&netlock);
563         return 0;
564 }
565
566 /*
567  *  Increment the reference count of a network device.
568  *  If id < 0, return an unused ether device.
569  */
570 static int openfile(struct ether *nif, int id)
571 {
572         ERRSTACK(1);
573         struct netfile *f, **fp, **efp;
574
575         if (id >= 0) {
576                 f = nif->f[id];
577                 if (f == 0)
578                         error(ENODEV, NULL);
579                 qlock(&f->qlock);
580                 qreopen(f->in);
581                 f->inuse++;
582                 qunlock(&f->qlock);
583                 return id;
584         }
585
586         qlock(&nif->qlock);
587         if (waserror()) {
588                 qunlock(&nif->qlock);
589                 nexterror();
590         }
591         efp = &nif->f[nif->nfile];
592         for (fp = nif->f; fp < efp; fp++) {
593                 f = *fp;
594                 if (f == 0) {
595                         f = kzmalloc(sizeof(struct netfile), 0);
596                         if (f == 0)
597                                 exhausted("memory");
598                         /* since we lock before netifinit (if we ever call that...) */
599                         qlock_init(&f->qlock);
600                         f->in = qopen(nif->limit, Qmsg, 0, 0);
601                         if (f->in == NULL) {
602                                 kfree(f);
603                                 exhausted("memory");
604                         }
605                         *fp = f;
606                         qlock(&f->qlock);
607                 } else {
608                         qlock(&f->qlock);
609                         if (f->inuse) {
610                                 qunlock(&f->qlock);
611                                 continue;
612                         }
613                 }
614                 f->inuse = 1;
615                 qreopen(f->in);
616                 netown(f, current->user, 0);
617                 qunlock(&f->qlock);
618                 qunlock(&nif->qlock);
619                 poperror();
620                 return fp - nif->f;
621         }
622         error(ENODEV, NULL);
623         return -1;      /* not reached */
624 }
625
626 /*
627  *  look for a token starting a string,
628  *  return a pointer to first non-space char after it
629  */
630 static char *matchtoken(char *p, char *token)
631 {
632         int n;
633
634         n = strlen(token);
635         if (strncmp(p, token, n))
636                 return 0;
637         p += n;
638         if (*p == 0)
639                 return p;
640         if (*p != ' ' && *p != '\t' && *p != '\n')
641                 return 0;
642         while (*p == ' ' || *p == '\t' || *p == '\n')
643                 p++;
644         return p;
645 }
646
647 static uint32_t hash(uint8_t * a, int len)
648 {
649         uint32_t sum = 0;
650
651         while (len-- > 0)
652                 sum = (sum << 1) + *a++;
653         return sum % Nmhash;
654 }
655
656 int activemulti(struct ether *nif, uint8_t * addr, int alen)
657 {
658         struct netaddr *hp;
659
660         for (hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
661                 if (memcmp(addr, hp->addr, alen) == 0) {
662                         if (hp->ref)
663                                 return 1;
664                         else
665                                 break;
666                 }
667         return 0;
668 }
669
670 static int parseaddr(uint8_t * to, char *from, int alen)
671 {
672         char nip[4];
673         char *p;
674         int i;
675
676         p = from;
677         for (i = 0; i < alen; i++) {
678                 if (*p == 0)
679                         return -1;
680                 nip[0] = *p++;
681                 if (*p == 0)
682                         return -1;
683                 nip[1] = *p++;
684                 nip[2] = 0;
685                 to[i] = strtoul(nip, 0, 16);
686                 if (*p == ':')
687                         p++;
688         }
689         return 0;
690 }
691
692 /*
693  *  keep track of multicast addresses
694  */
695 static char *netmulti(struct ether *nif, struct netfile *f, uint8_t * addr,
696                                           int add)
697 {
698         struct netaddr **l, *ap;
699         int i;
700         uint32_t h;
701
702         if (nif->multicast == NULL)
703                 return "interface does not support multicast";
704
705         l = &nif->maddr;
706         i = 0;
707         for (ap = *l; ap; ap = *l) {
708                 if (memcmp(addr, ap->addr, nif->alen) == 0)
709                         break;
710                 i++;
711                 l = &ap->next;
712         }
713
714         if (add) {
715                 if (ap == 0) {
716                         /* TODO: AFAIK, this never gets freed.  if we fix that, we can use a
717                          * kref too (instead of int ap->ref). */
718                         *l = ap = kzmalloc(sizeof(*ap), 0);
719                         memmove(ap->addr, addr, nif->alen);
720                         ap->next = 0;
721                         ap->ref = 1;
722                         h = hash(addr, nif->alen);
723                         ap->hnext = nif->mhash[h];
724                         nif->mhash[h] = ap;
725                 } else {
726                         ap->ref++;
727                 }
728                 if (ap->ref == 1) {
729                         nif->nmaddr++;
730                         nif->multicast(nif->arg, addr, 1);
731                 }
732                 if (i < 8 * sizeof(f->maddr)) {
733                         if ((f->maddr[i / 8] & (1 << (i % 8))) == 0)
734                                 f->nmaddr++;
735                         f->maddr[i / 8] |= 1 << (i % 8);
736                 }
737         } else {
738                 if (ap == 0 || ap->ref == 0)
739                         return 0;
740                 ap->ref--;
741                 if (ap->ref == 0) {
742                         nif->nmaddr--;
743                         nif->multicast(nif->arg, addr, 0);
744                 }
745                 if (i < 8 * sizeof(f->maddr)) {
746                         if ((f->maddr[i / 8] & (1 << (i % 8))) != 0)
747                                 f->nmaddr--;
748                         f->maddr[i / 8] &= ~(1 << (i % 8));
749                 }
750         }
751         return 0;
752 }