devproc: change user from char* to struct username
[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.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 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, "tcpck ");
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, ERROR_FIXME);
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, ERROR_FIXME);
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, ERROR_FIXME);
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 if (matchtoken(buf, "oneblock")) {
441                 /* Qmsg + Qcoal = one block at a time. */
442                 q_toggle_qmsg(f->in, TRUE);
443                 q_toggle_qcoalesce(f->in, TRUE);
444         } else
445                 n = -1;
446         qunlock(&nif->qlock);
447         poperror();
448         return n;
449 }
450
451 int netifwstat(struct ether *nif, struct chan *c, uint8_t * db, int n)
452 {
453         struct dir *dir;
454         struct netfile *f;
455         int m;
456
457         f = nif->f[NETID(c->qid.path)];
458         if (f == 0)
459                 error(ENOENT, ERROR_FIXME);
460
461         if (netown(f, current->user.name, O_WRITE) < 0)
462                 error(EPERM, ERROR_FIXME);
463
464         dir = kzmalloc(sizeof(struct dir) + n, 0);
465         m = convM2D(db, n, &dir[0], (char *)&dir[1]);
466         if (m == 0) {
467                 kfree(dir);
468                 error(ENODATA, ERROR_FIXME);
469         }
470         if (!emptystr(dir[0].uid))
471                 strlcpy(f->owner, dir[0].uid, KNAMELEN);
472         if (dir[0].mode != ~0UL)
473                 f->mode = dir[0].mode;
474         kfree(dir);
475         return m;
476 }
477
478 int netifstat(struct ether *nif, struct chan *c, uint8_t * db, int n)
479 {
480         return devstat(c, db, n, (struct dirtab *)nif, 0, netifgen);
481 }
482
483 void netifclose(struct ether *nif, struct chan *c)
484 {
485         struct netfile *f;
486         int t;
487         struct netaddr *ap;
488
489         if ((c->flag & COPEN) == 0)
490                 return;
491
492         t = NETTYPE(c->qid.path);
493         if (t != Ndataqid && t != Nctlqid)
494                 return;
495
496         f = nif->f[NETID(c->qid.path)];
497         qlock(&f->qlock);
498         if (--(f->inuse) == 0) {
499                 if (f->prom) {
500                         qlock(&nif->qlock);
501                         if (--(nif->prom) == 0 && nif->promiscuous != NULL)
502                                 nif->promiscuous(nif->arg, 0);
503                         qunlock(&nif->qlock);
504                         f->prom = 0;
505                 }
506                 if (f->scan) {
507                         qlock(&nif->qlock);
508                         if (--(nif->scan) == 0 && nif->scanbs != NULL)
509                                 nif->scanbs(nif->arg, 0);
510                         qunlock(&nif->qlock);
511                         f->prom = 0;
512                         f->scan = 0;
513                 }
514                 if (f->nmaddr) {
515                         qlock(&nif->qlock);
516                         t = 0;
517                         for (ap = nif->maddr; ap; ap = ap->next) {
518                                 if (f->maddr[t / 8] & (1 << (t % 8)))
519                                         netmulti(nif, f, ap->addr, 0);
520                         }
521                         qunlock(&nif->qlock);
522                         f->nmaddr = 0;
523                 }
524                 if (f->type < 0) {
525                         qlock(&nif->qlock);
526                         --(nif->all);
527                         qunlock(&nif->qlock);
528                 }
529                 f->owner[0] = 0;
530                 f->type = 0;
531                 f->bridge = 0;
532                 f->headersonly = 0;
533                 qclose(f->in);
534         }
535         qunlock(&f->qlock);
536 }
537
538 spinlock_t netlock = SPINLOCK_INITIALIZER;
539
540 static int netown(struct netfile *p, char *o, int omode)
541 {
542         static int access[] = { 0400, 0200, 0600, 0100 };
543         int mode;
544         int t;
545
546         spin_lock(&netlock);
547         if (*p->owner) {
548                 if (strncmp(o, p->owner, KNAMELEN) == 0)        /* User */
549                         mode = p->mode;
550                 else if (strncmp(o, eve.name, KNAMELEN) == 0)   /* Bootes is group */
551                         mode = p->mode << 3;
552                 else
553                         mode = p->mode << 6;    /* Other */
554
555                 t = access[omode & 3];
556                 if ((t & mode) == t) {
557                         spin_unlock(&netlock);
558                         return 0;
559                 } else {
560                         spin_unlock(&netlock);
561                         return -1;
562                 }
563         }
564         strlcpy(p->owner, o, KNAMELEN);
565         p->mode = 0660;
566         spin_unlock(&netlock);
567         return 0;
568 }
569
570 /*
571  *  Increment the reference count of a network device.
572  *  If id < 0, return an unused ether device.
573  */
574 static int openfile(struct ether *nif, int id)
575 {
576         ERRSTACK(1);
577         struct netfile *f, **fp, **efp;
578
579         if (id >= 0) {
580                 f = nif->f[id];
581                 if (f == 0)
582                         error(ENODEV, ERROR_FIXME);
583                 qlock(&f->qlock);
584                 qreopen(f->in);
585                 f->inuse++;
586                 qunlock(&f->qlock);
587                 return id;
588         }
589
590         qlock(&nif->qlock);
591         if (waserror()) {
592                 qunlock(&nif->qlock);
593                 nexterror();
594         }
595         efp = &nif->f[nif->nfile];
596         for (fp = nif->f; fp < efp; fp++) {
597                 f = *fp;
598                 if (f == 0) {
599                         f = kzmalloc(sizeof(struct netfile), 0);
600                         if (f == 0)
601                                 exhausted("memory");
602                         /* since we lock before netifinit (if we ever call that...) */
603                         qlock_init(&f->qlock);
604                         f->in = qopen(nif->limit, Qmsg, 0, 0);
605                         if (f->in == NULL) {
606                                 kfree(f);
607                                 exhausted("memory");
608                         }
609                         *fp = f;
610                         qlock(&f->qlock);
611                 } else {
612                         qlock(&f->qlock);
613                         if (f->inuse) {
614                                 qunlock(&f->qlock);
615                                 continue;
616                         }
617                 }
618                 f->inuse = 1;
619                 qreopen(f->in);
620                 netown(f, current->user.name, 0);
621                 qunlock(&f->qlock);
622                 qunlock(&nif->qlock);
623                 poperror();
624                 return fp - nif->f;
625         }
626         error(ENODEV, ERROR_FIXME);
627         return -1;      /* not reached */
628 }
629
630 /*
631  *  look for a token starting a string,
632  *  return a pointer to first non-space char after it
633  */
634 static char *matchtoken(char *p, char *token)
635 {
636         int n;
637
638         n = strlen(token);
639         if (strncmp(p, token, n))
640                 return 0;
641         p += n;
642         if (*p == 0)
643                 return p;
644         if (*p != ' ' && *p != '\t' && *p != '\n')
645                 return 0;
646         while (*p == ' ' || *p == '\t' || *p == '\n')
647                 p++;
648         return p;
649 }
650
651 static uint32_t hash(uint8_t * a, int len)
652 {
653         uint32_t sum = 0;
654
655         while (len-- > 0)
656                 sum = (sum << 1) + *a++;
657         return sum % Nmhash;
658 }
659
660 int activemulti(struct ether *nif, uint8_t * addr, int alen)
661 {
662         struct netaddr *hp;
663
664         for (hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
665                 if (memcmp(addr, hp->addr, alen) == 0) {
666                         if (hp->ref)
667                                 return 1;
668                         else
669                                 break;
670                 }
671         return 0;
672 }
673
674 static int parseaddr(uint8_t * to, char *from, int alen)
675 {
676         char nip[4];
677         char *p;
678         int i;
679
680         p = from;
681         for (i = 0; i < alen; i++) {
682                 if (*p == 0)
683                         return -1;
684                 nip[0] = *p++;
685                 if (*p == 0)
686                         return -1;
687                 nip[1] = *p++;
688                 nip[2] = 0;
689                 to[i] = strtoul(nip, 0, 16);
690                 if (*p == ':')
691                         p++;
692         }
693         return 0;
694 }
695
696 /*
697  *  keep track of multicast addresses
698  */
699 static char *netmulti(struct ether *nif, struct netfile *f, uint8_t * addr,
700                                           int add)
701 {
702         struct netaddr **l, *ap;
703         int i;
704         uint32_t h;
705
706         if (nif->multicast == NULL)
707                 return "interface does not support multicast";
708
709         l = &nif->maddr;
710         i = 0;
711         for (ap = *l; ap; ap = *l) {
712                 if (memcmp(addr, ap->addr, nif->alen) == 0)
713                         break;
714                 i++;
715                 l = &ap->next;
716         }
717
718         if (add) {
719                 if (ap == 0) {
720                         /* TODO: AFAIK, this never gets freed.  if we fix that, we can use a
721                          * kref too (instead of int ap->ref). */
722                         *l = ap = kzmalloc(sizeof(*ap), 0);
723                         memmove(ap->addr, addr, nif->alen);
724                         ap->next = 0;
725                         ap->ref = 1;
726                         h = hash(addr, nif->alen);
727                         ap->hnext = nif->mhash[h];
728                         nif->mhash[h] = ap;
729                 } else {
730                         ap->ref++;
731                 }
732                 if (ap->ref == 1) {
733                         nif->nmaddr++;
734                         nif->multicast(nif->arg, addr, 1);
735                 }
736                 if (i < 8 * sizeof(f->maddr)) {
737                         if ((f->maddr[i / 8] & (1 << (i % 8))) == 0)
738                                 f->nmaddr++;
739                         f->maddr[i / 8] |= 1 << (i % 8);
740                 }
741         } else {
742                 if (ap == 0 || ap->ref == 0)
743                         return 0;
744                 ap->ref--;
745                 if (ap->ref == 0) {
746                         nif->nmaddr--;
747                         nif->multicast(nif->arg, addr, 0);
748                 }
749                 if (i < 8 * sizeof(f->maddr)) {
750                         if ((f->maddr[i / 8] & (1 << (i % 8))) != 0)
751                                 f->nmaddr--;
752                         f->maddr[i / 8] &= ~(1 << (i % 8));
753                 }
754         }
755         return 0;
756 }