netif.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) 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 }