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