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