netif.c - vx32 - Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log
Files
Refs
---
netif.c (14502B)
---
     1 #include        "u.h"
     2 #include        "lib.h"
     3 #include        "mem.h"
     4 #include        "dat.h"
     5 #include        "fns.h"
     6 #include        "error.h"
     7 #include        "netif.h"
     8 
     9 static int netown(Netfile*, char*, int);
    10 static int openfile(Netif*, int);
    11 static char* matchtoken(char*, char*);
    12 static char* netmulti(Netif*, Netfile*, uchar*, int);
    13 static int parseaddr(uchar*, char*, int);
    14 
    15 int        netifdebug;
    16 #define        dprint(...)        if(netifdebug)print(__VA_ARGS__); else USED(netifdebug)
    17 
    18 /*
    19  *  set up a new network interface
    20  */
    21 void
    22 netifinit(Netif *nif, char *name, int nfile, ulong limit)
    23 {
    24         strncpy(nif->name, name, KNAMELEN-1);
    25         nif->name[KNAMELEN-1] = 0;
    26         nif->nfile = nfile;
    27         nif->f = xalloc(nfile*sizeof(Netfile*));
    28         if (nif->f == nil)
    29                 panic("netifinit: no memory");
    30         nif->limit = limit;
    31 }
    32 
    33 #define DD(c,q,nam,n,owner,perm,dp) dprint("%lux.%llux %s\n", q.type, q.path, nam); devdir(c,q,nam,n,owner,perm,dp)
    34 
    35 /*
    36  *  generate a 3 level directory
    37  */
    38 static int
    39 netifgen(Chan *c, char *dummy, Dirtab *vp, int dummy1, int i, Dir *dp)
    40 {
    41         Qid q;
    42         Netif *nif = (Netif*)vp;
    43         Netfile *f;
    44         int t, perm;
    45         char *o;
    46 
    47         memset(&q, 0, sizeof q);
    48         q.type = QTFILE;
    49         q.vers = 0;
    50 
    51         dprint("gen %d %llud %.2d        ", c->dri, c->qid.path, i);
    52         /* top level directory contains the name of the network */
    53         if(c->qid.path == 0){
    54                 switch(i){
    55                 case DEVDOTDOT:
    56                         q.path = 0;
    57                         q.type = QTDIR;
    58                         DD(c, q, ".", 0, eve, 0555, dp);
    59                         break;
    60                 case 0:
    61                         q.path = N2ndqid;
    62                         q.type = QTDIR;
    63                         strcpy(up->genbuf, nif->name);
    64                         DD(c, q, up->genbuf, 0, eve, 0555, dp);
    65                         break;
    66                 default:
    67                         dprint("-> -1 (top)\n");
    68                         return -1;
    69                 }
    70                 return 1;
    71         }
    72 
    73         /* second level contains clone plus all the conversations */
    74         t = NETTYPE(c->qid.path);
    75         if(t == N2ndqid || t == Ncloneqid || t == Naddrqid || t == Nstatqid || t == Nifstatqid){
    76                 switch(i){
    77                 case DEVDOTDOT:
    78                         q.type = QTDIR;
    79                         q.path = 0;
    80                         DD(c, q, ".", 0, eve, DMDIR|0555, dp);
    81                         break;
    82                 case 0:
    83                         q.path = Ncloneqid;
    84                         DD(c, q, "clone", 0, eve, 0666, dp);
    85                         break;
    86                 case 1:
    87                         q.path = Naddrqid;
    88                         DD(c, q, "addr", 0, eve, 0666, dp);
    89                         break;
    90                 case 2:
    91                         q.path = Nstatqid;
    92                         DD(c, q, "stats", 0, eve, 0444, dp);
    93                         break;
    94                 case 3:
    95                         q.path = Nifstatqid;
    96                         DD(c, q, "ifstats", 0, eve, 0444, dp);
    97                         break;
    98                 default:
    99                         i -= 4;
   100                         if(i >= nif->nfile){
   101                                 dprint("-> -1 (2d): %d %d\n", i, nif->nfile);
   102                                 return -1;
   103                         }
   104                         if(nif->f[i] == 0){
   105                                 dprint("nif->f[%d] -> 0\n", i);
   106                                 return 0;
   107                         }
   108                         q.type = QTDIR;
   109                         q.path = NETQID(i, N3rdqid);
   110                         sprint(up->genbuf, "%d", i);
   111                         DD(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
   112                         break;
   113                 }
   114                 return 1;
   115         }
   116 
   117         /* third level */
   118         f = nif->f[NETID(c->qid.path)];
   119         if(f == 0){
   120                 dprint("->f 0\n");
   121                 return -1;
   122         }
   123         if(*f->owner){
   124                 o = f->owner;
   125                 perm = f->mode;
   126         } else {
   127                 o = eve;
   128                 perm = 0666;
   129         }
   130         switch(i){
   131         case DEVDOTDOT:
   132                 q.type = QTDIR;
   133                 q.path = N2ndqid;
   134                 strcpy(up->genbuf, nif->name);
   135                 DD(c, q, up->genbuf, 0, eve, DMDIR|0555, dp);
   136                 break;
   137         case 0:
   138                 q.path = NETQID(NETID(c->qid.path), Ndataqid);
   139                 DD(c, q, "data", 0, o, perm, dp);
   140                 break;
   141         case 1:
   142                 q.path = NETQID(NETID(c->qid.path), Nctlqid);
   143                 DD(c, q, "ctl", 0, o, perm, dp);
   144                 break;
   145         case 2:
   146                 q.path = NETQID(NETID(c->qid.path), Nstatqid);
   147                 DD(c, q, "stats", 0, eve, 0444, dp);
   148                 break;
   149         case 3:
   150                 q.path = NETQID(NETID(c->qid.path), Ntypeqid);
   151                 DD(c, q, "type", 0, eve, 0444, dp);
   152                 break;
   153         case 4:
   154                 q.path = NETQID(NETID(c->qid.path), Nifstatqid);
   155                 DD(c, q, "ifstats", 0, eve, 0444, dp);
   156                 break;
   157         default:
   158                 dprint("-> -1 (third)\n");
   159                 return -1;
   160         }
   161         return 1;
   162 }
   163 
   164 static void
   165 prwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
   166 {
   167         char buf[512], *e, *p;
   168 
   169         if(netifdebug == 0)
   170                 return;
   171         p = buf;
   172         e = p + sizeof buf;
   173         for(int i = 0; i < nname; i++)
   174                 p = seprint(p, e, "%s ", name[i]);
   175         if(p > buf)
   176                 p--;
   177         *p = 0;
   178         print("netifwalk %lld [%s]\n", c->qid.path, buf);
   179 }
   180 
   181 Walkqid*
   182 netifwalk(Netif *nif, Chan *c, Chan *nc, char **name, int nname)
   183 {
   184         prwalk(nif, c, nc, name, nname);
   185         return devwalk(c, nc, name, nname, (Dirtab *)nif, 0, netifgen);
   186 }
   187 
   188 Chan*
   189 netifopen(Netif *nif, Chan *c, int omode)
   190 {
   191         int id;
   192         Netfile *f;
   193 
   194         dprint("netifopen %p %d\n", nif, c? c->qid.path: -1);
   195         id = 0;
   196         if(c->qid.type & QTDIR){
   197                 if(omode != OREAD)
   198                         error(Eperm);
   199         } else {
   200                 switch(NETTYPE(c->qid.path)){
   201                 case Ndataqid:
   202                 case Nctlqid:
   203                         id = NETID(c->qid.path);
   204                         openfile(nif, id);
   205                         break;
   206                 case Ncloneqid:
   207                         id = openfile(nif, -1);
   208                         c->qid.path = NETQID(id, Nctlqid);
   209                         break;
   210                 default:
   211                         if(omode != OREAD)
   212                                 error(Ebadarg);
   213                 }
   214                 switch(NETTYPE(c->qid.path)){
   215                 case Ndataqid:
   216                 case Nctlqid:
   217                         f = nif->f[id];
   218                         if(netown(f, up->user, omode&7) < 0)
   219                                 error(Eperm);
   220                         break;
   221                 }
   222         }
   223         c->mode = openmode(omode);
   224         c->flag |= COPEN;
   225         c->offset = 0;
   226         c->iounit = qiomaxatomic;
   227         return c;
   228 }
   229 
   230 long
   231 netifread(Netif *nif, Chan *c, void *a, long n, ulong offset)
   232 {
   233         int i, j;
   234         Netfile *f;
   235         char *p;
   236 
   237         dprint("netifread %lud %lud\n", c->qid.path, NETTYPE(c->qid.path));
   238         if(c->qid.type&QTDIR)
   239                 return devdirread(c, a, n, (Dirtab*)nif, 0, netifgen);
   240 
   241         switch(NETTYPE(c->qid.path)){
   242         case Ndataqid:
   243                 f = nif->f[NETID(c->qid.path)];
   244                 return qread(f->in, a, n);
   245         case Nctlqid:
   246                 return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE);
   247         case Nstatqid:
   248                 dprint("netstatqid\n");
   249                 p = smalloc(READSTR);
   250                 j = snprint(p, READSTR, "in: %llud\n", nif->inpackets);
   251                 j += snprint(p+j, READSTR-j, "link: %d\n", nif->link);
   252                 j += snprint(p+j, READSTR-j, "out: %llud\n", nif->outpackets);
   253                 j += snprint(p+j, READSTR-j, "crc errs: %d\n", nif->crcs);
   254                 j += snprint(p+j, READSTR-j, "overflows: %d\n", nif->overflows);
   255                 j += snprint(p+j, READSTR-j, "soft overflows: %d\n", nif->soverflows);
   256                 j += snprint(p+j, READSTR-j, "framing errs: %d\n", nif->frames);
   257                 j += snprint(p+j, READSTR-j, "buffer errs: %d\n", nif->buffs);
   258                 j += snprint(p+j, READSTR-j, "output errs: %d\n", nif->oerrs);
   259                 j += snprint(p+j, READSTR-j, "prom: %d\n", nif->prom);
   260                 j += snprint(p+j, READSTR-j, "mbps: %d\n", nif->mbps);
   261                 j += snprint(p+j, READSTR-j, "addr: ");
   262                 for(i = 0; i < nif->alen; i++)
   263                         j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
   264                 snprint(p+j, READSTR-j, "\n");
   265                 n = readstr(offset, a, n, p);
   266                 free(p);
   267                 return n;
   268         case Naddrqid:
   269                 p = malloc(READSTR);
   270                 j = 0;
   271                 for(i = 0; i < nif->alen; i++)
   272                         j += snprint(p+j, READSTR-j, "%2.2ux", nif->addr[i]);
   273                 n = readstr(offset, a, n, p);
   274                 free(p);
   275                 return n;
   276         case Ntypeqid:
   277                 f = nif->f[NETID(c->qid.path)];
   278                 return readnum(offset, a, n, f->type, NUMSIZE);
   279         case Nifstatqid:
   280                 return 0;
   281         }
   282         error(Ebadarg);
   283         return -1;        /* not reached */
   284 }
   285 
   286 Block*
   287 netifbread(Netif *nif, Chan *c, long n, ulong offset)
   288 {
   289         if((c->qid.type & QTDIR) || NETTYPE(c->qid.path) != Ndataqid)
   290                 return devbread(c, n, offset);
   291 
   292         return qbread(nif->f[NETID(c->qid.path)]->in, n);
   293 }
   294 
   295 /*
   296  *  make sure this type isn't already in use on this device
   297  */
   298 static int
   299 typeinuse(Netif *nif, int type)
   300 {
   301         Netfile *f, **fp, **efp;
   302 
   303         if(type <= 0)
   304                 return 0;
   305 
   306         efp = &nif->f[nif->nfile];
   307         for(fp = nif->f; fp < efp; fp++){
   308                 f = *fp;
   309                 if(f == 0)
   310                         continue;
   311                 if(f->type == type)
   312                         return 1;
   313         }
   314         return 0;
   315 }
   316 
   317 /*
   318  *  the devxxx.c that calls us handles writing data, it knows best
   319  */
   320 long
   321 netifwrite(Netif *nif, Chan *c, void *a, long n)
   322 {
   323         Netfile *f;
   324         int type;
   325         char *p, buf[64];
   326         uchar binaddr[Nmaxaddr];
   327 
   328         if(NETTYPE(c->qid.path) != Nctlqid)
   329                 error(Eperm);
   330 
   331         if(n >= sizeof(buf))
   332                 n = sizeof(buf)-1;
   333         memmove(buf, a, n);
   334         buf[n] = 0;
   335 
   336         if(waserror()){
   337                 QUNLOCK(nif);
   338                 nexterror();
   339         }
   340 
   341         QLOCK(nif);
   342         f = nif->f[NETID(c->qid.path)];
   343         if((p = matchtoken(buf, "connect")) != 0){
   344                 type = atoi(p);
   345                 if(typeinuse(nif, type))
   346                         error(Einuse);
   347                 f->type = type;
   348                 if(f->type < 0)
   349                         nif->all++;
   350         } else if(matchtoken(buf, "promiscuous")){
   351                 if(f->prom == 0){
   352                         if(nif->prom == 0 && nif->promiscuous != nil)
   353                                 nif->promiscuous(nif->arg, 1);
   354                         f->prom = 1;
   355                         nif->prom++;
   356                 }
   357         } else if((p = matchtoken(buf, "scanbs")) != 0){
   358                 /* scan for base stations */
   359                 if(f->scan == 0){
   360                         type = atoi(p);
   361                         if(type < 5)
   362                                 type = 5;
   363                         if(nif->scanbs != nil)
   364                                 nif->scanbs(nif->arg, type);
   365                         f->scan = type;
   366                         nif->scan++;
   367                 }
   368         } else if(matchtoken(buf, "bridge")){
   369                 f->bridge = 1;
   370         } else if(matchtoken(buf, "headersonly")){
   371                 f->headersonly = 1;
   372         } else if((p = matchtoken(buf, "addmulti")) != 0){
   373                 if(parseaddr(binaddr, p, nif->alen) < 0)
   374                         error("bad address");
   375                 p = netmulti(nif, f, binaddr, 1);
   376                 if(p)
   377                         error(p);
   378         } else if((p = matchtoken(buf, "remmulti")) != 0){
   379                 if(parseaddr(binaddr, p, nif->alen) < 0)
   380                         error("bad address");
   381                 p = netmulti(nif, f, binaddr, 0);
   382                 if(p)
   383                         error(p);
   384         } else
   385                 n = -1;
   386         QUNLOCK(nif);
   387         poperror();
   388         return n;
   389 }
   390 
   391 int
   392 netifwstat(Netif *nif, Chan *c, uchar *db, int n)
   393 {
   394         Dir *dir;
   395         Netfile *f;
   396         int m;
   397 
   398         f = nif->f[NETID(c->qid.path)];
   399         if(f == 0)
   400                 error(Enonexist);
   401 
   402         if(netown(f, up->user, OWRITE) < 0)
   403                 error(Eperm);
   404 
   405         dir = smalloc(sizeof(Dir)+n);
   406         m = convM2D(db, n, &dir[0], (char*)&dir[1]);
   407         if(m == 0){
   408                 free(dir);
   409                 error(Eshortstat);
   410         }
   411         if(!emptystr(dir[0].uid))
   412                 strncpy(f->owner, dir[0].uid, KNAMELEN);
   413         if(dir[0].mode != ~0UL)
   414                 f->mode = dir[0].mode;
   415         free(dir);
   416         return m;
   417 }
   418 
   419 int
   420 netifstat(Netif *nif, Chan *c, uchar *db, int n)
   421 {
   422         dprint("netifstat %s nfile %d %lld type=%d\n", nif->name, nif->nfile, c->qid.path, c->type);
   423         return devstat(c, db, n, (Dirtab *)nif, 0, netifgen);
   424 }
   425 
   426 void
   427 netifclose(Netif *nif, Chan *c)
   428 {
   429         Netfile *f;
   430         int t;
   431         Netaddr *ap;
   432 
   433         if((c->flag & COPEN) == 0)
   434                 return;
   435 
   436         t = NETTYPE(c->qid.path);
   437         if(t != Ndataqid && t != Nctlqid)
   438                 return;
   439 
   440         f = nif->f[NETID(c->qid.path)];
   441         QLOCK(f);
   442         if(--(f->inuse) == 0){
   443                 if(f->prom){
   444                         QLOCK(nif);
   445                         if(--(nif->prom) == 0 && nif->promiscuous != nil)
   446                                 nif->promiscuous(nif->arg, 0);
   447                         QUNLOCK(nif);
   448                         f->prom = 0;
   449                 }
   450                 if(f->scan){
   451                         QLOCK(nif);
   452                         if(--(nif->scan) == 0 && nif->scanbs != nil)
   453                                 nif->scanbs(nif->arg, 0);
   454                         QUNLOCK(nif);
   455                         f->prom = 0;
   456                         f->scan = 0;
   457                 }
   458                 if(f->nmaddr){
   459                         QLOCK(nif);
   460                         t = 0;
   461                         for(ap = nif->maddr; ap; ap = ap->next){
   462                                 if(f->maddr[t/8] & (1<<(t%8)))
   463                                         netmulti(nif, f, ap->addr, 0);
   464                         }
   465                         QUNLOCK(nif);
   466                         f->nmaddr = 0;
   467                 }
   468                 if(f->type < 0){
   469                         QLOCK(nif);
   470                         --(nif->all);
   471                         QUNLOCK(nif);
   472                 }
   473                 f->owner[0] = 0;
   474 print("drop type %.4ux\n", f->type);
   475                 f->type = 0;
   476                 f->bridge = 0;
   477                 f->headersonly = 0;
   478                 qclose(f->in);
   479         }
   480         QUNLOCK(f);
   481 }
   482 
   483 Lock netlock;
   484 
   485 static int
   486 netown(Netfile *p, char *o, int omode)
   487 {
   488         static int access[] = { 0400, 0200, 0600, 0100 };
   489         int mode;
   490         int t;
   491 
   492         lock(&netlock);
   493         if(*p->owner){
   494                 if(strncmp(o, p->owner, KNAMELEN) == 0)        /* User */
   495                         mode = p->mode;
   496                 else if(strncmp(o, eve, KNAMELEN) == 0)        /* Bootes is group */
   497                         mode = p->mode<<3;
   498                 else
   499                         mode = p->mode<<6;                /* Other */
   500 
   501                 t = access[omode&3];
   502                 if((t & mode) == t){
   503                         unlock(&netlock);
   504                         return 0;
   505                 } else {
   506                         unlock(&netlock);
   507                         return -1;
   508                 }
   509         }
   510         strncpy(p->owner, o, KNAMELEN);
   511         p->mode = 0660;
   512         unlock(&netlock);
   513         return 0;
   514 }
   515 
   516 /*
   517  *  Increment the reference count of a network device.
   518  *  If id < 0, return an unused ether device.
   519  */
   520 static int
   521 openfile(Netif *nif, int id)
   522 {
   523         Netfile *f, **fp, **efp;
   524 
   525         if(id >= 0){
   526                 f = nif->f[id];
   527                 if(f == 0)
   528                         error(Enodev);
   529                 QLOCK(f);
   530                 qreopen(f->in);
   531                 f->inuse++;
   532                 QUNLOCK(f);
   533                 return id;
   534         }
   535 
   536         QLOCK(nif);
   537         if(waserror()){
   538                 QUNLOCK(nif);
   539                 nexterror();
   540         }
   541         efp = &nif->f[nif->nfile];
   542         for(fp = nif->f; fp < efp; fp++){
   543                 f = *fp;
   544                 if(f == 0){
   545                         f = malloc(sizeof(Netfile));
   546                         if(f == 0)
   547                                 exhausted("memory");
   548                         f->in = qopen(nif->limit, Qmsg, 0, 0);
   549                         if(f->in == nil){
   550                                 free(f);
   551                                 exhausted("memory");
   552                         }
   553                         *fp = f;
   554                         QLOCK(f);
   555                 } else {
   556                         QLOCK(f);
   557                         if(f->inuse){
   558                                 QUNLOCK(f);
   559                                 continue;
   560                         }
   561                 }
   562                 f->inuse = 1;
   563                 qreopen(f->in);
   564                 netown(f, up->user, 0);
   565                 QUNLOCK(f);
   566                 QUNLOCK(nif);
   567                 poperror();
   568                 return fp - nif->f;
   569         }
   570         error(Enodev);
   571         return -1;        /* not reached */
   572 }
   573 
   574 /*
   575  *  look for a token starting a string,
   576  *  return a pointer to first non-space char after it
   577  */
   578 static char*
   579 matchtoken(char *p, char *token)
   580 {
   581         int n;
   582 
   583         n = strlen(token);
   584         if(strncmp(p, token, n))
   585                 return 0;
   586         p += n;
   587         if(*p == 0)
   588                 return p;
   589         if(*p != ' ' && *p != '\t' && *p != '\n')
   590                 return 0;
   591         while(*p == ' ' || *p == '\t' || *p == '\n')
   592                 p++;
   593         return p;
   594 }
   595 
   596 void
   597 hnputv(void *p, uvlong v)
   598 {
   599         uchar *a;
   600 
   601         a = p;
   602         hnputl(a, v>>32);
   603         hnputl(a+4, v);
   604 }
   605 
   606 void
   607 hnputl(void *p, uint v)
   608 {
   609         uchar *a;
   610 
   611         a = p;
   612         a[0] = v>>24;
   613         a[1] = v>>16;
   614         a[2] = v>>8;
   615         a[3] = v;
   616 }
   617 
   618 void
   619 hnputs(void *p, ushort v)
   620 {
   621         uchar *a;
   622 
   623         a = p;
   624         a[0] = v>>8;
   625         a[1] = v;
   626 }
   627 
   628 uvlong
   629 nhgetv(void *p)
   630 {
   631         uchar *a;
   632 
   633         a = p;
   634         return ((vlong)nhgetl(a) << 32) | nhgetl(a+4);
   635 }
   636 
   637 uint
   638 nhgetl(void *p)
   639 {
   640         uchar *a;
   641 
   642         a = p;
   643         return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|(a[3]<<0);
   644 }
   645 
   646 ushort
   647 nhgets(void *p)
   648 {
   649         uchar *a;
   650 
   651         a = p;
   652         return (a[0]<<8)|(a[1]<<0);
   653 }
   654 
   655 static ulong
   656 hash(uchar *a, int len)
   657 {
   658         ulong sum = 0;
   659 
   660         while(len-- > 0)
   661                 sum = (sum << 1) + *a++;
   662         return sum%Nmhash;
   663 }
   664 
   665 int
   666 activemulti(Netif *nif, uchar *addr, int alen)
   667 {
   668         Netaddr *hp;
   669 
   670         for(hp = nif->mhash[hash(addr, alen)]; hp; hp = hp->hnext)
   671                 if(memcmp(addr, hp->addr, alen) == 0){
   672                         if(hp->ref)
   673                                 return 1;
   674                         else
   675                                 break;
   676                 }
   677         return 0;
   678 }
   679 
   680 static int
   681 parseaddr(uchar *to, char *from, int alen)
   682 {
   683         char nip[4];
   684         char *p;
   685         int i;
   686 
   687         p = from;
   688         for(i = 0; i < alen; i++){
   689                 if(*p == 0)
   690                         return -1;
   691                 nip[0] = *p++;
   692                 if(*p == 0)
   693                         return -1;
   694                 nip[1] = *p++;
   695                 nip[2] = 0;
   696                 to[i] = strtoul(nip, 0, 16);
   697                 if(*p == ':')
   698                         p++;
   699         }
   700         return 0;
   701 }
   702 
   703 /*
   704  *  keep track of multicast addresses
   705  */
   706 static char*
   707 netmulti(Netif *nif, Netfile *f, uchar *addr, int add)
   708 {
   709         Netaddr **l, *ap;
   710         int i;
   711         ulong h;
   712 
   713         if(nif->multicast == nil)
   714                 return "interface does not support multicast";
   715 
   716         l = &nif->maddr;
   717         i = 0;
   718         for(ap = *l; ap; ap = *l){
   719                 if(memcmp(addr, ap->addr, nif->alen) == 0)
   720                         break;
   721                 i++;
   722                 l = &ap->next;
   723         }
   724 
   725         if(add){
   726                 if(ap == 0){
   727                         *l = ap = smalloc(sizeof(*ap));
   728                         memmove(ap->addr, addr, nif->alen);
   729                         ap->next = 0;
   730                         ap->ref = 1;
   731                         h = hash(addr, nif->alen);
   732                         ap->hnext = nif->mhash[h];
   733                         nif->mhash[h] = ap;
   734                 } else {
   735                         ap->ref++;
   736                 }
   737                 if(ap->ref == 1){
   738                         nif->nmaddr++;
   739                         nif->multicast(nif->arg, addr, 1);
   740                 }
   741                 if(i < 8*sizeof(f->maddr)){
   742                         if((f->maddr[i/8] & (1<<(i%8))) == 0)
   743                                 f->nmaddr++;
   744                         f->maddr[i/8] |= 1<<(i%8);
   745                 }
   746         } else {
   747                 if(ap == 0 || ap->ref == 0)
   748                         return 0;
   749                 ap->ref--;
   750                 if(ap->ref == 0){
   751                         nif->nmaddr--;
   752                         nif->multicast(nif->arg, addr, 0);
   753                 }
   754                 if(i < 8*sizeof(f->maddr)){
   755                         if((f->maddr[i/8] & (1<<(i%8))) != 0)
   756                                 f->nmaddr--;
   757                         f->maddr[i/8] &= ~(1<<(i%8));
   758                 }
   759         }
   760         return 0;
   761 }