ipifc.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       ipifc.c (34075B)
       ---
            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 
            8 #include "ip.h"
            9 #include "ipv6.h"
           10 
           11 #define DPRINT if(0)print
           12 
           13 enum {
           14         Maxmedia        = 32,
           15         Nself                = Maxmedia*5,
           16         NHASH                = 1<<6,
           17         NCACHE                = 256,
           18         QMAX                = 64*1024-1,
           19 };
           20 
           21 Medium *media[Maxmedia] = { 0 };
           22 
           23 /*
           24  *  cache of local addresses (addresses we answer to)
           25  */
           26 struct Ipself
           27 {
           28         uchar        a[IPaddrlen];
           29         Ipself        *hnext;                /* next address in the hash table */
           30         Iplink        *link;                /* binding twixt Ipself and Ipifc */
           31         ulong        expire;
           32         uchar        type;                /* type of address */
           33         int        ref;
           34         Ipself        *next;                /* free list */
           35 };
           36 
           37 struct Ipselftab
           38 {
           39         QLock        qlock;
           40         int        inited;
           41         int        acceptall;        /* true if an interface has the null address */
           42         Ipself        *hash[NHASH];        /* hash chains */
           43 };
           44 
           45 /*
           46  *  Multicast addresses are chained onto a Chan so that
           47  *  we can remove them when the Chan is closed.
           48  */
           49 typedef struct Ipmcast Ipmcast;
           50 struct Ipmcast
           51 {
           52         Ipmcast        *next;
           53         uchar        ma[IPaddrlen];        /* multicast address */
           54         uchar        ia[IPaddrlen];        /* interface address */
           55 };
           56 
           57 /* quick hash for ip addresses */
           58 #define hashipa(a) ( (ulong)(((a)[IPaddrlen-2]<<8) | (a)[IPaddrlen-1])%NHASH )
           59 
           60 static char tifc[] = "ifc ";
           61 
           62 static void        addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type);
           63 static void        remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a);
           64 static char*        ipifcjoinmulti(Ipifc *ifc, char **argv, int argc);
           65 static char*        ipifcleavemulti(Ipifc *ifc, char **argv, int argc);
           66 static void        ipifcregisterproxy(Fs*, Ipifc*, uchar*);
           67 static char*        ipifcremlifc(Ipifc*, Iplifc*);
           68 
           69 /*
           70  *  link in a new medium
           71  */
           72 void
           73 addipmedium(Medium *med)
           74 {
           75         int i;
           76 
           77         for(i = 0; i < nelem(media)-1; i++)
           78                 if(media[i] == nil){
           79                         media[i] = med;
           80                         break;
           81                 }
           82 }
           83 
           84 /*
           85  *  find the medium with this name
           86  */
           87 Medium*
           88 ipfindmedium(char *name)
           89 {
           90         Medium **mp;
           91 
           92         for(mp = media; *mp != nil; mp++)
           93                 if(strcmp((*mp)->name, name) == 0)
           94                         break;
           95         return *mp;
           96 }
           97 
           98 /*
           99  *  attach a device (or pkt driver) to the interface.
          100  *  called with c locked
          101  */
          102 static char*
          103 ipifcbind(Conv *c, char **argv, int argc)
          104 {
          105         Ipifc *ifc;
          106         Medium *m;
          107 
          108         if(argc < 2)
          109                 return Ebadarg;
          110 
          111         ifc = (Ipifc*)c->ptcl;
          112 
          113         /* bind the device to the interface */
          114         m = ipfindmedium(argv[1]);
          115         if(m == nil)
          116                 return "unknown interface type";
          117 
          118         WLOCK(ifc);
          119         if(ifc->m != nil){
          120                 WUNLOCK(ifc);
          121                 return "interface already bound";
          122         }
          123         if(waserror()){
          124                 WUNLOCK(ifc);
          125                 nexterror();
          126         }
          127 
          128         /* do medium specific binding */
          129         (*m->bind)(ifc, argc, argv);
          130 
          131         /* set the bound device name */
          132         if(argc > 2)
          133                 strncpy(ifc->dev, argv[2], sizeof(ifc->dev));
          134         else
          135                 snprint(ifc->dev, sizeof ifc->dev, "%s%d", m->name, c->x);
          136         ifc->dev[sizeof(ifc->dev)-1] = 0;
          137 
          138         /* set up parameters */
          139         ifc->m = m;
          140         ifc->mintu = ifc->m->mintu;
          141         ifc->maxtu = ifc->m->maxtu;
          142         if(ifc->m->unbindonclose == 0)
          143                 ifc->conv->inuse++;
          144         ifc->rp.mflag = 0;                /* default not managed */
          145         ifc->rp.oflag = 0;
          146         ifc->rp.maxraint = 600000;        /* millisecs */
          147         ifc->rp.minraint = 200000;
          148         ifc->rp.linkmtu = 0;                /* no mtu sent */
          149         ifc->rp.reachtime = 0;
          150         ifc->rp.rxmitra = 0;
          151         ifc->rp.ttl = MAXTTL;
          152         ifc->rp.routerlt = 3 * ifc->rp.maxraint;
          153 
          154         /* any ancillary structures (like routes) no longer pertain */
          155         ifc->ifcid++;
          156 
          157         /* reopen all the queues closed by a previous unbind */
          158         qreopen(c->rq);
          159         qreopen(c->eq);
          160         qreopen(c->sq);
          161 
          162         WUNLOCK(ifc);
          163         poperror();
          164 
          165         return nil;
          166 }
          167 
          168 /*
          169  *  detach a device from an interface, close the interface
          170  *  called with ifc->conv closed
          171  */
          172 static char*
          173 ipifcunbind(Ipifc *ifc)
          174 {
          175         char *err;
          176 
          177         if(waserror()){
          178                 WUNLOCK(ifc);
          179                 nexterror();
          180         }
          181         WLOCK(ifc);
          182 
          183         /* dissociate routes */
          184         if(ifc->m != nil && ifc->m->unbindonclose == 0)
          185                 ifc->conv->inuse--;
          186         ifc->ifcid++;
          187 
          188         /* disassociate logical interfaces (before zeroing ifc->arg) */
          189         while(ifc->lifc){
          190                 err = ipifcremlifc(ifc, ifc->lifc);
          191                 /*
          192                  * note: err non-zero means lifc not found,
          193                  * which can't happen in this case.
          194                  */
          195                 if(err)
          196                         error(err);
          197         }
          198 
          199         /* disassociate device */
          200         if(ifc->m && ifc->m->unbind)
          201                 (*ifc->m->unbind)(ifc);
          202         memset(ifc->dev, 0, sizeof(ifc->dev));
          203         ifc->arg = nil;
          204         ifc->reassemble = 0;
          205 
          206         /* close queues to stop queuing of packets */
          207         qclose(ifc->conv->rq);
          208         qclose(ifc->conv->wq);
          209         qclose(ifc->conv->sq);
          210 
          211         ifc->m = nil;
          212         WUNLOCK(ifc);
          213         poperror();
          214         return nil;
          215 }
          216 
          217 char sfixedformat[] = "device %s maxtu %d sendra %d recvra %d mflag %d oflag"
          218 " %d maxraint %d minraint %d linkmtu %d reachtime %d rxmitra %d ttl %d routerlt"
          219 " %d pktin %lud pktout %lud errin %lud errout %lud\n";
          220 
          221 char slineformat[] = "        %-40I %-10M %-40I %-12lud %-12lud\n";
          222 
          223 static int
          224 ipifcstate(Conv *c, char *state, int n)
          225 {
          226         Ipifc *ifc;
          227         Iplifc *lifc;
          228         int m;
          229 
          230         ifc = (Ipifc*)c->ptcl;
          231         m = snprint(state, n, sfixedformat,
          232                 ifc->dev, ifc->maxtu, ifc->sendra6, ifc->recvra6,
          233                 ifc->rp.mflag, ifc->rp.oflag, ifc->rp.maxraint,
          234                 ifc->rp.minraint, ifc->rp.linkmtu, ifc->rp.reachtime,
          235                 ifc->rp.rxmitra, ifc->rp.ttl, ifc->rp.routerlt,
          236                 ifc->in, ifc->out, ifc->inerr, ifc->outerr);
          237 
          238         RLOCK(ifc);
          239         for(lifc = ifc->lifc; lifc && n > m; lifc = lifc->next)
          240                 m += snprint(state+m, n - m, slineformat, lifc->local,
          241                         lifc->mask, lifc->remote, lifc->validlt, lifc->preflt);
          242         if(ifc->lifc == nil)
          243                 m += snprint(state+m, n - m, "\n");
          244         RUNLOCK(ifc);
          245         return m;
          246 }
          247 
          248 static int
          249 ipifclocal(Conv *c, char *state, int n)
          250 {
          251         Ipifc *ifc;
          252         Iplifc *lifc;
          253         Iplink *link;
          254         int m;
          255 
          256         ifc = (Ipifc*)c->ptcl;
          257         m = 0;
          258 
          259         RLOCK(ifc);
          260         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
          261                 m += snprint(state+m, n - m, "%-40.40I ->", lifc->local);
          262                 for(link = lifc->link; link; link = link->lifclink)
          263                         m += snprint(state+m, n - m, " %-40.40I", link->self->a);
          264                 m += snprint(state+m, n - m, "\n");
          265         }
          266         RUNLOCK(ifc);
          267         return m;
          268 }
          269 
          270 static int
          271 ipifcinuse(Conv *c)
          272 {
          273         Ipifc *ifc;
          274 
          275         ifc = (Ipifc*)c->ptcl;
          276         return ifc->m != nil;
          277 }
          278 
          279 /*
          280  *  called when a process writes to an interface's 'data'
          281  */
          282 static void
          283 ipifckick(void *x)
          284 {
          285         Conv *c = x;
          286         Block *bp;
          287         Ipifc *ifc;
          288 
          289         bp = qget(c->wq);
          290         if(bp == nil)
          291                 return;
          292 
          293         ifc = (Ipifc*)c->ptcl;
          294         if(!CANRLOCK(ifc)){
          295                 freeb(bp);
          296                 return;
          297         }
          298         if(waserror()){
          299                 RUNLOCK(ifc);
          300                 nexterror();
          301         }
          302         if(ifc->m == nil || ifc->m->pktin == nil)
          303                 freeb(bp);
          304         else
          305                 (*ifc->m->pktin)(c->p->f, ifc, bp);
          306         RUNLOCK(ifc);
          307         poperror();
          308 }
          309 
          310 /*
          311  *  called when a new ipifc structure is created
          312  */
          313 static void
          314 ipifccreate(Conv *c)
          315 {
          316         Ipifc *ifc;
          317 
          318         c->rq = qopen(QMAX, 0, 0, 0);
          319         c->sq = qopen(2*QMAX, 0, 0, 0);
          320         c->wq = qopen(QMAX, Qkick, ipifckick, c);
          321         ifc = (Ipifc*)c->ptcl;
          322         ifc->conv = c;
          323         ifc->unbinding = 0;
          324         ifc->m = nil;
          325         ifc->reassemble = 0;
          326 }
          327 
          328 /*
          329  *  called after last close of ipifc data or ctl
          330  *  called with c locked, we must unlock
          331  */
          332 static void
          333 ipifcclose(Conv *c)
          334 {
          335         Ipifc *ifc;
          336         Medium *m;
          337 
          338         ifc = (Ipifc*)c->ptcl;
          339         m = ifc->m;
          340         if(m && m->unbindonclose)
          341                 ipifcunbind(ifc);
          342 }
          343 
          344 /*
          345  *  change an interface's mtu
          346  */
          347 char*
          348 ipifcsetmtu(Ipifc *ifc, char **argv, int argc)
          349 {
          350         int mtu;
          351 
          352         if(argc < 2 || ifc->m == nil)
          353                 return Ebadarg;
          354         mtu = strtoul(argv[1], 0, 0);
          355         if(mtu < ifc->m->mintu || mtu > ifc->m->maxtu)
          356                 return Ebadarg;
          357         ifc->maxtu = mtu;
          358         return nil;
          359 }
          360 
          361 /*
          362  *  add an address to an interface.
          363  */
          364 char*
          365 ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
          366 {
          367         int i, type, mtu, sendnbrdisc = 0;
          368         uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
          369         uchar bcast[IPaddrlen], net[IPaddrlen];
          370         Iplifc *lifc, **l;
          371         Fs *f;
          372 
          373         if(ifc->m == nil)
          374                 return "ipifc not yet bound to device";
          375 
          376         f = ifc->conv->p->f;
          377 
          378         type = Rifc;
          379         memset(ip, 0, IPaddrlen);
          380         memset(mask, 0, IPaddrlen);
          381         memset(rem, 0, IPaddrlen);
          382         switch(argc){
          383         case 6:
          384                 if(strcmp(argv[5], "proxy") == 0)
          385                         type |= Rproxy;
          386                 /* fall through */
          387         case 5:
          388                 mtu = strtoul(argv[4], 0, 0);
          389                 if(mtu >= ifc->m->mintu && mtu <= ifc->m->maxtu)
          390                         ifc->maxtu = mtu;
          391                 /* fall through */
          392         case 4:
          393                 if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1)
          394                         return Ebadip;
          395                 parseipmask(mask, argv[2]);
          396                 maskip(rem, mask, net);
          397                 break;
          398         case 3:
          399                 if (parseip(ip, argv[1]) == -1)
          400                         return Ebadip;
          401                 parseipmask(mask, argv[2]);
          402                 maskip(ip, mask, rem);
          403                 maskip(rem, mask, net);
          404                 break;
          405         case 2:
          406                 if (parseip(ip, argv[1]) == -1)
          407                         return Ebadip;
          408                 memmove(mask, defmask(ip), IPaddrlen);
          409                 maskip(ip, mask, rem);
          410                 maskip(rem, mask, net);
          411                 break;
          412         default:
          413                 return Ebadarg;
          414         }
          415         if(isv4(ip))
          416                 tentative = 0;
          417         WLOCK(ifc);
          418 
          419         /* ignore if this is already a local address for this ifc */
          420         for(lifc = ifc->lifc; lifc; lifc = lifc->next) {
          421                 if(ipcmp(lifc->local, ip) == 0) {
          422                         if(lifc->tentative != tentative)
          423                                 lifc->tentative = tentative;
          424                         if(lifcp) {
          425                                 lifc->onlink = lifcp->onlink;
          426                                 lifc->autoflag = lifcp->autoflag;
          427                                 lifc->validlt = lifcp->validlt;
          428                                 lifc->preflt = lifcp->preflt;
          429                                 lifc->origint = lifcp->origint;
          430                         }
          431                         goto out;
          432                 }
          433         }
          434 
          435         /* add the address to the list of logical ifc's for this ifc */
          436         lifc = smalloc(sizeof(Iplifc));
          437         ipmove(lifc->local, ip);
          438         ipmove(lifc->mask, mask);
          439         ipmove(lifc->remote, rem);
          440         ipmove(lifc->net, net);
          441         lifc->tentative = tentative;
          442         if(lifcp) {
          443                 lifc->onlink = lifcp->onlink;
          444                 lifc->autoflag = lifcp->autoflag;
          445                 lifc->validlt = lifcp->validlt;
          446                 lifc->preflt = lifcp->preflt;
          447                 lifc->origint = lifcp->origint;
          448         } else {                /* default values */
          449                 lifc->onlink = lifc->autoflag = 1;
          450                 lifc->validlt = lifc->preflt = ~0L;
          451                 lifc->origint = NOW / 1000;
          452         }
          453         lifc->next = nil;
          454 
          455         for(l = &ifc->lifc; *l; l = &(*l)->next)
          456                 ;
          457         *l = lifc;
          458 
          459         /* check for point-to-point interface */
          460         if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */
          461         if(ipcmp(mask, IPallbits) == 0)
          462                 type |= Rptpt;
          463 
          464         /* add local routes */
          465         if(isv4(ip))
          466                 v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type);
          467         else
          468                 v6addroute(f, tifc, rem, mask, rem, type);
          469 
          470         addselfcache(f, ifc, lifc, ip, Runi);
          471 
          472         if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){
          473                 ipifcregisterproxy(f, ifc, rem);
          474                 goto out;
          475         }
          476 
          477         if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) {
          478                 /* add subnet directed broadcast address to the self cache */
          479                 for(i = 0; i < IPaddrlen; i++)
          480                         bcast[i] = (ip[i] & mask[i]) | ~mask[i];
          481                 addselfcache(f, ifc, lifc, bcast, Rbcast);
          482 
          483                 /* add subnet directed network address to the self cache */
          484                 for(i = 0; i < IPaddrlen; i++)
          485                         bcast[i] = (ip[i] & mask[i]) & mask[i];
          486                 addselfcache(f, ifc, lifc, bcast, Rbcast);
          487 
          488                 /* add network directed broadcast address to the self cache */
          489                 memmove(mask, defmask(ip), IPaddrlen);
          490                 for(i = 0; i < IPaddrlen; i++)
          491                         bcast[i] = (ip[i] & mask[i]) | ~mask[i];
          492                 addselfcache(f, ifc, lifc, bcast, Rbcast);
          493 
          494                 /* add network directed network address to the self cache */
          495                 memmove(mask, defmask(ip), IPaddrlen);
          496                 for(i = 0; i < IPaddrlen; i++)
          497                         bcast[i] = (ip[i] & mask[i]) & mask[i];
          498                 addselfcache(f, ifc, lifc, bcast, Rbcast);
          499 
          500                 addselfcache(f, ifc, lifc, IPv4bcast, Rbcast);
          501         }
          502         else {
          503                 if(ipcmp(ip, v6loopback) == 0) {
          504                         /* add node-local mcast address */
          505                         addselfcache(f, ifc, lifc, v6allnodesN, Rmulti);
          506 
          507                         /* add route for all node multicast */
          508                         v6addroute(f, tifc, v6allnodesN, v6allnodesNmask,
          509                                 v6allnodesN, Rmulti);
          510                 }
          511 
          512                 /* add all nodes multicast address */
          513                 addselfcache(f, ifc, lifc, v6allnodesL, Rmulti);
          514 
          515                 /* add route for all nodes multicast */
          516                 v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL,
          517                         Rmulti);
          518 
          519                 /* add solicited-node multicast address */
          520                 ipv62smcast(bcast, ip);
          521                 addselfcache(f, ifc, lifc, bcast, Rmulti);
          522 
          523                 sendnbrdisc = 1;
          524         }
          525 
          526         /* register the address on this network for address resolution */
          527         if(isv4(ip) && ifc->m->areg != nil)
          528                 (*ifc->m->areg)(ifc, ip);
          529 
          530 out:
          531         WUNLOCK(ifc);
          532         if(tentative && sendnbrdisc)
          533                 icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac);
          534         return nil;
          535 }
          536 
          537 /*
          538  *  remove a logical interface from an ifc
          539  *  always called with ifc WLOCK'd
          540  */
          541 static char*
          542 ipifcremlifc(Ipifc *ifc, Iplifc *lifc)
          543 {
          544         Iplifc **l;
          545         Fs *f;
          546 
          547         f = ifc->conv->p->f;
          548 
          549         /*
          550          *  find address on this interface and remove from chain.
          551          *  for pt to pt we actually specify the remote address as the
          552          *  addresss to remove.
          553          */
          554         for(l = &ifc->lifc; *l != nil && *l != lifc; l = &(*l)->next)
          555                 ;
          556         if(*l == nil)
          557                 return "address not on this interface";
          558         *l = lifc->next;
          559 
          560         /* disassociate any addresses */
          561         while(lifc->link)
          562                 remselfcache(f, ifc, lifc, lifc->link->self->a);
          563 
          564         /* remove the route for this logical interface */
          565         if(isv4(lifc->local))
          566                 v4delroute(f, lifc->remote+IPv4off, lifc->mask+IPv4off, 1);
          567         else {
          568                 v6delroute(f, lifc->remote, lifc->mask, 1);
          569                 if(ipcmp(lifc->local, v6loopback) == 0)
          570                         /* remove route for all node multicast */
          571                         v6delroute(f, v6allnodesN, v6allnodesNmask, 1);
          572                 else if(memcmp(lifc->local, v6linklocal, v6llpreflen) == 0)
          573                         /* remove route for all link multicast */
          574                         v6delroute(f, v6allnodesL, v6allnodesLmask, 1);
          575         }
          576 
          577         free(lifc);
          578         return nil;
          579 }
          580 
          581 /*
          582  *  remove an address from an interface.
          583  *  called with c->car locked
          584  */
          585 char*
          586 ipifcrem(Ipifc *ifc, char **argv, int argc)
          587 {
          588         char *rv;
          589         uchar ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen];
          590         Iplifc *lifc;
          591 
          592         if(argc < 3)
          593                 return Ebadarg;
          594 
          595         if (parseip(ip, argv[1]) == -1)
          596                 return Ebadip;
          597         parseipmask(mask, argv[2]);
          598         if(argc < 4)
          599                 maskip(ip, mask, rem);
          600         else
          601                 if (parseip(rem, argv[3]) == -1)
          602                         return Ebadip;
          603 
          604         WLOCK(ifc);
          605 
          606         /*
          607          *  find address on this interface and remove from chain.
          608          *  for pt to pt we actually specify the remote address as the
          609          *  addresss to remove.
          610          */
          611         for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next) {
          612                 if (memcmp(ip, lifc->local, IPaddrlen) == 0
          613                 && memcmp(mask, lifc->mask, IPaddrlen) == 0
          614                 && memcmp(rem, lifc->remote, IPaddrlen) == 0)
          615                         break;
          616         }
          617 
          618         rv = ipifcremlifc(ifc, lifc);
          619         WUNLOCK(ifc);
          620         return rv;
          621 }
          622 
          623 /*
          624  * distribute routes to active interfaces like the
          625  * TRIP linecards
          626  */
          627 void
          628 ipifcaddroute(Fs *f, int vers, uchar *addr, uchar *mask, uchar *gate, int type)
          629 {
          630         Medium *m;
          631         Conv **cp, **e;
          632         Ipifc *ifc;
          633 
          634         e = &f->ipifc->conv[f->ipifc->nc];
          635         for(cp = f->ipifc->conv; cp < e; cp++){
          636                 if(*cp != nil) {
          637                         ifc = (Ipifc*)(*cp)->ptcl;
          638                         m = ifc->m;
          639                         if(m && m->addroute)
          640                                 m->addroute(ifc, vers, addr, mask, gate, type);
          641                 }
          642         }
          643 }
          644 
          645 void
          646 ipifcremroute(Fs *f, int vers, uchar *addr, uchar *mask)
          647 {
          648         Medium *m;
          649         Conv **cp, **e;
          650         Ipifc *ifc;
          651 
          652         e = &f->ipifc->conv[f->ipifc->nc];
          653         for(cp = f->ipifc->conv; cp < e; cp++){
          654                 if(*cp != nil) {
          655                         ifc = (Ipifc*)(*cp)->ptcl;
          656                         m = ifc->m;
          657                         if(m && m->remroute)
          658                                 m->remroute(ifc, vers, addr, mask);
          659                 }
          660         }
          661 }
          662 
          663 /*
          664  *  associate an address with the interface.  This wipes out any previous
          665  *  addresses.  This is a macro that means, remove all the old interfaces
          666  *  and add a new one.
          667  */
          668 static char*
          669 ipifcconnect(Conv* c, char **argv, int argc)
          670 {
          671         char *err;
          672         Ipifc *ifc;
          673 
          674         ifc = (Ipifc*)c->ptcl;
          675 
          676         if(ifc->m == nil)
          677                  return "ipifc not yet bound to device";
          678 
          679         if(waserror()){
          680                 WUNLOCK(ifc);
          681                 nexterror();
          682         }
          683         WLOCK(ifc);
          684         while(ifc->lifc){
          685                 err = ipifcremlifc(ifc, ifc->lifc);
          686                 if(err)
          687                         error(err);
          688         }
          689         WUNLOCK(ifc);
          690         poperror();
          691 
          692         err = ipifcadd(ifc, argv, argc, 0, nil);
          693         if(err)
          694                 return err;
          695 
          696         Fsconnected(c, nil);
          697         return nil;
          698 }
          699 
          700 char*
          701 ipifcra6(Ipifc *ifc, char **argv, int argc)
          702 {
          703         int i, argsleft, vmax = ifc->rp.maxraint, vmin = ifc->rp.minraint;
          704 
          705         argsleft = argc - 1;
          706         i = 1;
          707 
          708         if(argsleft % 2 != 0)
          709                 return Ebadarg;
          710 
          711         while (argsleft > 1) {
          712                 if(strcmp(argv[i], "recvra") == 0)
          713                         ifc->recvra6 = (atoi(argv[i+1]) != 0);
          714                 else if(strcmp(argv[i], "sendra") == 0)
          715                         ifc->sendra6 = (atoi(argv[i+1]) != 0);
          716                 else if(strcmp(argv[i], "mflag") == 0)
          717                         ifc->rp.mflag = (atoi(argv[i+1]) != 0);
          718                 else if(strcmp(argv[i], "oflag") == 0)
          719                         ifc->rp.oflag = (atoi(argv[i+1]) != 0);
          720                 else if(strcmp(argv[i], "maxraint") == 0)
          721                         ifc->rp.maxraint = atoi(argv[i+1]);
          722                 else if(strcmp(argv[i], "minraint") == 0)
          723                         ifc->rp.minraint = atoi(argv[i+1]);
          724                 else if(strcmp(argv[i], "linkmtu") == 0)
          725                         ifc->rp.linkmtu = atoi(argv[i+1]);
          726                 else if(strcmp(argv[i], "reachtime") == 0)
          727                         ifc->rp.reachtime = atoi(argv[i+1]);
          728                 else if(strcmp(argv[i], "rxmitra") == 0)
          729                         ifc->rp.rxmitra = atoi(argv[i+1]);
          730                 else if(strcmp(argv[i], "ttl") == 0)
          731                         ifc->rp.ttl = atoi(argv[i+1]);
          732                 else if(strcmp(argv[i], "routerlt") == 0)
          733                         ifc->rp.routerlt = atoi(argv[i+1]);
          734                 else
          735                         return Ebadarg;
          736 
          737                 argsleft -= 2;
          738                 i += 2;
          739         }
          740 
          741         /* consistency check */
          742         if(ifc->rp.maxraint < ifc->rp.minraint) {
          743                 ifc->rp.maxraint = vmax;
          744                 ifc->rp.minraint = vmin;
          745                 return Ebadarg;
          746         }
          747         return nil;
          748 }
          749 
          750 /*
          751  *  non-standard control messages.
          752  *  called with c->car locked.
          753  */
          754 static char*
          755 ipifcctl(Conv* c, char**argv, int argc)
          756 {
          757         Ipifc *ifc;
          758         int i;
          759 
          760         ifc = (Ipifc*)c->ptcl;
          761         if(strcmp(argv[0], "add") == 0)
          762                 return ipifcadd(ifc, argv, argc, 0, nil);
          763         else if(strcmp(argv[0], "try") == 0)
          764                 return ipifcadd(ifc, argv, argc, 1, nil);
          765         else if(strcmp(argv[0], "remove") == 0)
          766                 return ipifcrem(ifc, argv, argc);
          767         else if(strcmp(argv[0], "unbind") == 0)
          768                 return ipifcunbind(ifc);
          769         else if(strcmp(argv[0], "joinmulti") == 0)
          770                 return ipifcjoinmulti(ifc, argv, argc);
          771         else if(strcmp(argv[0], "leavemulti") == 0)
          772                 return ipifcleavemulti(ifc, argv, argc);
          773         else if(strcmp(argv[0], "mtu") == 0)
          774                 return ipifcsetmtu(ifc, argv, argc);
          775         else if(strcmp(argv[0], "reassemble") == 0){
          776                 ifc->reassemble = 1;
          777                 return nil;
          778         }
          779         else if(strcmp(argv[0], "iprouting") == 0){
          780                 i = 1;
          781                 if(argc > 1)
          782                         i = atoi(argv[1]);
          783                 iprouting(c->p->f, i);
          784                 return nil;
          785         }
          786         else if(strcmp(argv[0], "add6") == 0)
          787                 return ipifcadd6(ifc, argv, argc);
          788         else if(strcmp(argv[0], "ra6") == 0)
          789                 return ipifcra6(ifc, argv, argc);
          790         return "unsupported ctl";
          791 }
          792 
          793 int
          794 ipifcstats(Proto *ipifc, char *buf, int len)
          795 {
          796         return ipstats(ipifc->f, buf, len);
          797 }
          798 
          799 void
          800 ipifcinit(Fs *f)
          801 {
          802         Proto *ipifc;
          803 
          804         ipifc = smalloc(sizeof(Proto));
          805         ipifc->name = "ipifc";
          806         ipifc->connect = ipifcconnect;
          807         ipifc->announce = nil;
          808         ipifc->bind = ipifcbind;
          809         ipifc->state = ipifcstate;
          810         ipifc->create = ipifccreate;
          811         ipifc->close = ipifcclose;
          812         ipifc->rcv = nil;
          813         ipifc->ctl = ipifcctl;
          814         ipifc->advise = nil;
          815         ipifc->stats = ipifcstats;
          816         ipifc->inuse = ipifcinuse;
          817         ipifc->local = ipifclocal;
          818         ipifc->ipproto = -1;
          819         ipifc->nc = Maxmedia;
          820         ipifc->ptclsize = sizeof(Ipifc);
          821 
          822         f->ipifc = ipifc;        /* hack for ipifcremroute, findipifc, ... */
          823         f->self = smalloc(sizeof(Ipselftab));        /* hack for ipforme */
          824 
          825         Fsproto(f, ipifc);
          826 }
          827 
          828 /*
          829  *  add to self routing cache
          830  *        called with c->car locked
          831  */
          832 static void
          833 addselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a, int type)
          834 {
          835         Ipself *p;
          836         Iplink *lp;
          837         int h;
          838 
          839         QLOCK(f->self);
          840 
          841         /* see if the address already exists */
          842         h = hashipa(a);
          843         for(p = f->self->hash[h]; p; p = p->next)
          844                 if(memcmp(a, p->a, IPaddrlen) == 0)
          845                         break;
          846 
          847         /* allocate a local address and add to hash chain */
          848         if(p == nil){
          849                 p = smalloc(sizeof(*p));
          850                 ipmove(p->a, a);
          851                 p->type = type;
          852                 p->next = f->self->hash[h];
          853                 f->self->hash[h] = p;
          854 
          855                 /* if the null address, accept all packets */
          856                 if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
          857                         f->self->acceptall = 1;
          858         }
          859 
          860         /* look for a link for this lifc */
          861         for(lp = p->link; lp; lp = lp->selflink)
          862                 if(lp->lifc == lifc)
          863                         break;
          864 
          865         /* allocate a lifc-to-local link and link to both */
          866         if(lp == nil){
          867                 lp = smalloc(sizeof(*lp));
          868                 lp->ref = 1;
          869                 lp->lifc = lifc;
          870                 lp->self = p;
          871                 lp->selflink = p->link;
          872                 p->link = lp;
          873                 lp->lifclink = lifc->link;
          874                 lifc->link = lp;
          875 
          876                 /* add to routing table */
          877                 if(isv4(a))
          878                         v4addroute(f, tifc, a+IPv4off, IPallbits+IPv4off,
          879                                 a+IPv4off, type);
          880                 else
          881                         v6addroute(f, tifc, a, IPallbits, a, type);
          882 
          883                 if((type & Rmulti) && ifc->m->addmulti != nil)
          884                         (*ifc->m->addmulti)(ifc, a, lifc->local);
          885         } else
          886                 lp->ref++;
          887 
          888         QUNLOCK(f->self);
          889 }
          890 
          891 /*
          892  *  These structures are unlinked from their chains while
          893  *  other threads may be using them.  To avoid excessive locking,
          894  *  just put them aside for a while before freeing them.
          895  *        called with f->self locked
          896  */
          897 static Iplink *freeiplink;
          898 static Ipself *freeipself;
          899 
          900 static void
          901 iplinkfree(Iplink *p)
          902 {
          903         Iplink **l, *np;
          904         ulong now = NOW;
          905 
          906         l = &freeiplink;
          907         for(np = *l; np; np = *l){
          908                 if(np->expire > now){
          909                         *l = np->next;
          910                         free(np);
          911                         continue;
          912                 }
          913                 l = &np->next;
          914         }
          915         p->expire = now + 5000;        /* give other threads 5 secs to get out */
          916         p->next = nil;
          917         *l = p;
          918 }
          919 
          920 static void
          921 ipselffree(Ipself *p)
          922 {
          923         Ipself **l, *np;
          924         ulong now = NOW;
          925 
          926         l = &freeipself;
          927         for(np = *l; np; np = *l){
          928                 if(np->expire > now){
          929                         *l = np->next;
          930                         free(np);
          931                         continue;
          932                 }
          933                 l = &np->next;
          934         }
          935         p->expire = now + 5000;        /* give other threads 5 secs to get out */
          936         p->next = nil;
          937         *l = p;
          938 }
          939 
          940 /*
          941  *  Decrement reference for this address on this link.
          942  *  Unlink from selftab if this is the last ref.
          943  *        called with c->car locked
          944  */
          945 static void
          946 remselfcache(Fs *f, Ipifc *ifc, Iplifc *lifc, uchar *a)
          947 {
          948         Ipself *p, **l;
          949         Iplink *link, **l_self, **l_lifc;
          950 
          951         QLOCK(f->self);
          952 
          953         /* find the unique selftab entry */
          954         l = &f->self->hash[hashipa(a)];
          955         for(p = *l; p; p = *l){
          956                 if(ipcmp(p->a, a) == 0)
          957                         break;
          958                 l = &p->next;
          959         }
          960 
          961         if(p == nil)
          962                 goto out;
          963 
          964         /*
          965          *  walk down links from an ifc looking for one
          966          *  that matches the selftab entry
          967          */
          968         l_lifc = &lifc->link;
          969         for(link = *l_lifc; link; link = *l_lifc){
          970                 if(link->self == p)
          971                         break;
          972                 l_lifc = &link->lifclink;
          973         }
          974 
          975         if(link == nil)
          976                 goto out;
          977 
          978         /*
          979          *  walk down the links from the selftab looking for
          980          *  the one we just found
          981          */
          982         l_self = &p->link;
          983         for(link = *l_self; link; link = *l_self){
          984                 if(link == *l_lifc)
          985                         break;
          986                 l_self = &link->selflink;
          987         }
          988 
          989         if(link == nil)
          990                 panic("remselfcache");
          991 
          992         if(--(link->ref) != 0)
          993                 goto out;
          994 
          995         if((p->type & Rmulti) && ifc->m->remmulti != nil)
          996                 (*ifc->m->remmulti)(ifc, a, lifc->local);
          997 
          998         /* ref == 0, remove from both chains and free the link */
          999         *l_lifc = link->lifclink;
         1000         *l_self = link->selflink;
         1001         iplinkfree(link);
         1002 
         1003         if(p->link != nil)
         1004                 goto out;
         1005 
         1006         /* remove from routing table */
         1007         if(isv4(a))
         1008                 v4delroute(f, a+IPv4off, IPallbits+IPv4off, 1);
         1009         else
         1010                 v6delroute(f, a, IPallbits, 1);
         1011 
         1012         /* no more links, remove from hash and free */
         1013         *l = p->next;
         1014         ipselffree(p);
         1015 
         1016         /* if IPnoaddr, forget */
         1017         if(ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0)
         1018                 f->self->acceptall = 0;
         1019 
         1020 out:
         1021         QUNLOCK(f->self);
         1022 }
         1023 
         1024 static char *stformat = "%-44.44I %2.2d %4.4s\n";
         1025 enum
         1026 {
         1027         Nstformat= 41,
         1028 };
         1029 
         1030 long
         1031 ipselftabread(Fs *f, char *cp, ulong offset, int n)
         1032 {
         1033         int i, m, nifc, off;
         1034         Ipself *p;
         1035         Iplink *link;
         1036         char state[8];
         1037 
         1038         m = 0;
         1039         off = offset;
         1040         QLOCK(f->self);
         1041         for(i = 0; i < NHASH && m < n; i++){
         1042                 for(p = f->self->hash[i]; p != nil && m < n; p = p->next){
         1043                         nifc = 0;
         1044                         for(link = p->link; link; link = link->selflink)
         1045                                 nifc++;
         1046                         routetype(p->type, state);
         1047                         m += snprint(cp + m, n - m, stformat, p->a, nifc, state);
         1048                         if(off > 0){
         1049                                 off -= m;
         1050                                 m = 0;
         1051                         }
         1052                 }
         1053         }
         1054         QUNLOCK(f->self);
         1055         return m;
         1056 }
         1057 
         1058 int
         1059 iptentative(Fs *f, uchar *addr)
         1060 {
         1061          Ipself *p;
         1062 
         1063         p = f->self->hash[hashipa(addr)];
         1064         for(; p; p = p->next){
         1065                 if(ipcmp(addr, p->a) == 0)
         1066                         return p->link->lifc->tentative;
         1067         }
         1068         return 0;
         1069 }
         1070 
         1071 /*
         1072  *  returns
         1073  *        0                - no match
         1074  *        Runi
         1075  *        Rbcast
         1076  *        Rmcast
         1077  */
         1078 int
         1079 ipforme(Fs *f, uchar *addr)
         1080 {
         1081         Ipself *p;
         1082 
         1083         p = f->self->hash[hashipa(addr)];
         1084         for(; p; p = p->next){
         1085                 if(ipcmp(addr, p->a) == 0)
         1086                         return p->type;
         1087         }
         1088 
         1089         /* hack to say accept anything */
         1090         if(f->self->acceptall)
         1091                 return Runi;
         1092         return 0;
         1093 }
         1094 
         1095 /*
         1096  *  find the ifc on same net as the remote system.  If none,
         1097  *  return nil.
         1098  */
         1099 Ipifc*
         1100 findipifc(Fs *f, uchar *remote, int type)
         1101 {
         1102         Ipifc *ifc, *x;
         1103         Iplifc *lifc;
         1104         Conv **cp, **e;
         1105         uchar gnet[IPaddrlen], xmask[IPaddrlen];
         1106 
         1107         x = nil;
         1108         memset(xmask, 0, IPaddrlen);
         1109 
         1110         /* find most specific match */
         1111         e = &f->ipifc->conv[f->ipifc->nc];
         1112         for(cp = f->ipifc->conv; cp < e; cp++){
         1113                 if(*cp == 0)
         1114                         continue;
         1115                 ifc = (Ipifc*)(*cp)->ptcl;
         1116                 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
         1117                         maskip(remote, lifc->mask, gnet);
         1118                         if(ipcmp(gnet, lifc->net) == 0){
         1119                                 if(x == nil || ipcmp(lifc->mask, xmask) > 0){
         1120                                         x = ifc;
         1121                                         ipmove(xmask, lifc->mask);
         1122                                 }
         1123                         }
         1124                 }
         1125         }
         1126         if(x != nil)
         1127                 return x;
         1128 
         1129         /* for now for broadcast and multicast, just use first interface */
         1130         if(type & (Rbcast|Rmulti)){
         1131                 for(cp = f->ipifc->conv; cp < e; cp++){
         1132                         if(*cp == 0)
         1133                                 continue;
         1134                         ifc = (Ipifc*)(*cp)->ptcl;
         1135                         if(ifc->lifc != nil)
         1136                                 return ifc;
         1137                 }
         1138         }
         1139         return nil;
         1140 }
         1141 
         1142 enum {
         1143         unknownv6,                /* UGH */
         1144 //        multicastv6,
         1145         unspecifiedv6,
         1146         linklocalv6,
         1147         globalv6,
         1148 };
         1149 
         1150 int
         1151 v6addrtype(uchar *addr)
         1152 {
         1153         if(islinklocal(addr) ||
         1154             (isv6mcast(addr) && (addr[1] & 0xF) <= Link_local_scop))
         1155                 return linklocalv6;
         1156         else
         1157                 return globalv6;
         1158 }
         1159 
         1160 #define v6addrcurr(lifc) ((lifc)->preflt == ~0L || \
         1161                         (lifc)->origint + (lifc)->preflt >= NOW/1000)
         1162 
         1163 static void
         1164 findprimaryipv6(Fs *f, uchar *local)
         1165 {
         1166         int atype, atypel;
         1167         Conv **cp, **e;
         1168         Ipifc *ifc;
         1169         Iplifc *lifc;
         1170 
         1171         ipmove(local, v6Unspecified);
         1172         atype = unspecifiedv6;
         1173 
         1174         /*
         1175          * find "best" (global > link local > unspecified)
         1176          * local address; address must be current.
         1177          */
         1178         e = &f->ipifc->conv[f->ipifc->nc];
         1179         for(cp = f->ipifc->conv; cp < e; cp++){
         1180                 if(*cp == 0)
         1181                         continue;
         1182                 ifc = (Ipifc*)(*cp)->ptcl;
         1183                 for(lifc = ifc->lifc; lifc; lifc = lifc->next){
         1184                         atypel = v6addrtype(lifc->local);
         1185                         if(atypel > atype && v6addrcurr(lifc)) {
         1186                                 ipmove(local, lifc->local);
         1187                                 atype = atypel;
         1188                                 if(atype == globalv6)
         1189                                         return;
         1190                         }
         1191                 }
         1192         }
         1193 }
         1194 
         1195 /*
         1196  *  returns first ip address configured
         1197  */
         1198 static void
         1199 findprimaryipv4(Fs *f, uchar *local)
         1200 {
         1201         Conv **cp, **e;
         1202         Ipifc *ifc;
         1203         Iplifc *lifc;
         1204 
         1205         /* find first ifc local address */
         1206         e = &f->ipifc->conv[f->ipifc->nc];
         1207         for(cp = f->ipifc->conv; cp < e; cp++){
         1208                 if(*cp == 0)
         1209                         continue;
         1210                 ifc = (Ipifc*)(*cp)->ptcl;
         1211                 if((lifc = ifc->lifc) != nil){
         1212                         ipmove(local, lifc->local);
         1213                         return;
         1214                 }
         1215         }
         1216 }
         1217 
         1218 /*
         1219  *  find the local address 'closest' to the remote system, copy it to
         1220  *  local and return the ifc for that address
         1221  */
         1222 void
         1223 findlocalip(Fs *f, uchar *local, uchar *remote)
         1224 {
         1225         int version, atype = unspecifiedv6, atypel = unknownv6;
         1226         int atyper, deprecated;
         1227         uchar gate[IPaddrlen], gnet[IPaddrlen];
         1228         Ipifc *ifc;
         1229         Iplifc *lifc;
         1230         Route *r;
         1231 
         1232         QLOCK(f->ipifc);
         1233         r = v6lookup(f, remote, nil);
         1234          version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
         1235 
         1236         if(r != nil){
         1237                 ifc = r->ifc;
         1238                 if(r->type & Rv4)
         1239                         v4tov6(gate, r->v4.gate);
         1240                 else {
         1241                         ipmove(gate, r->v6.gate);
         1242                         ipmove(local, v6Unspecified);
         1243                 }
         1244 
         1245                 switch(version) {
         1246                 case V4:
         1247                         /* find ifc address closest to the gateway to use */
         1248                         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
         1249                                 maskip(gate, lifc->mask, gnet);
         1250                                 if(ipcmp(gnet, lifc->net) == 0){
         1251                                         ipmove(local, lifc->local);
         1252                                         goto out;
         1253                                 }
         1254                         }
         1255                         break;
         1256                 case V6:
         1257                         /* find ifc address with scope matching the destination */
         1258                         atyper = v6addrtype(remote);
         1259                         deprecated = 0;
         1260                         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
         1261                                 atypel = v6addrtype(lifc->local);
         1262                                 /* prefer appropriate scope */
         1263                                 if((atypel > atype && atype < atyper) ||
         1264                                    (atypel < atype && atype > atyper)){
         1265                                         ipmove(local, lifc->local);
         1266                                         deprecated = !v6addrcurr(lifc);
         1267                                         atype = atypel;
         1268                                 } else if(atypel == atype){
         1269                                         /* avoid deprecated addresses */
         1270                                         if(deprecated && v6addrcurr(lifc)){
         1271                                                 ipmove(local, lifc->local);
         1272                                                 atype = atypel;
         1273                                                 deprecated = 0;
         1274                                         }
         1275                                 }
         1276                                 if(atype == atyper && !deprecated)
         1277                                         goto out;
         1278                         }
         1279                         if(atype >= atyper)
         1280                                 goto out;
         1281                         break;
         1282                 default:
         1283                         panic("findlocalip: version %d", version);
         1284                 }
         1285         }
         1286 
         1287         switch(version){
         1288         case V4:
         1289                 findprimaryipv4(f, local);
         1290                 break;
         1291         case V6:
         1292                 findprimaryipv6(f, local);
         1293                 break;
         1294         default:
         1295                 panic("findlocalip2: version %d", version);
         1296         }
         1297 
         1298 out:
         1299         QUNLOCK(f->ipifc);
         1300 }
         1301 
         1302 /*
         1303  *  return first v4 address associated with an interface
         1304  */
         1305 int
         1306 ipv4local(Ipifc *ifc, uchar *addr)
         1307 {
         1308         Iplifc *lifc;
         1309 
         1310         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
         1311                 if(isv4(lifc->local)){
         1312                         memmove(addr, lifc->local+IPv4off, IPv4addrlen);
         1313                         return 1;
         1314                 }
         1315         }
         1316         return 0;
         1317 }
         1318 
         1319 /*
         1320  *  return first v6 address associated with an interface
         1321  */
         1322 int
         1323 ipv6local(Ipifc *ifc, uchar *addr)
         1324 {
         1325         Iplifc *lifc;
         1326 
         1327         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
         1328                 if(!isv4(lifc->local) && !(lifc->tentative)){
         1329                         ipmove(addr, lifc->local);
         1330                         return 1;
         1331                 }
         1332         }
         1333         return 0;
         1334 }
         1335 
         1336 int
         1337 ipv6anylocal(Ipifc *ifc, uchar *addr)
         1338 {
         1339         Iplifc *lifc;
         1340 
         1341         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
         1342                 if(!isv4(lifc->local)){
         1343                         ipmove(addr, lifc->local);
         1344                         return SRC_UNI;
         1345                 }
         1346         }
         1347         return SRC_UNSPEC;
         1348 }
         1349 
         1350 /*
         1351  *  see if this address is bound to the interface
         1352  */
         1353 Iplifc*
         1354 iplocalonifc(Ipifc *ifc, uchar *ip)
         1355 {
         1356         Iplifc *lifc;
         1357 
         1358         for(lifc = ifc->lifc; lifc; lifc = lifc->next)
         1359                 if(ipcmp(ip, lifc->local) == 0)
         1360                         return lifc;
         1361         return nil;
         1362 }
         1363 
         1364 
         1365 /*
         1366  *  See if we're proxying for this address on this interface
         1367  */
         1368 int
         1369 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
         1370 {
         1371         Route *r;
         1372         uchar net[IPaddrlen];
         1373         Iplifc *lifc;
         1374 
         1375         /* see if this is a direct connected pt to pt address */
         1376         r = v6lookup(f, ip, nil);
         1377         if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
         1378                 return 0;
         1379 
         1380         /* see if this is on the right interface */
         1381         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
         1382                 maskip(ip, lifc->mask, net);
         1383                 if(ipcmp(net, lifc->remote) == 0)
         1384                         return 1;
         1385         }
         1386         return 0;
         1387 }
         1388 
         1389 /*
         1390  *  return multicast version if any
         1391  */
         1392 int
         1393 ipismulticast(uchar *ip)
         1394 {
         1395         if(isv4(ip)){
         1396                 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
         1397                         return V4;
         1398         }
         1399         else if(ip[0] == 0xff)
         1400                 return V6;
         1401         return 0;
         1402 }
         1403 int
         1404 ipisbm(uchar *ip)
         1405 {
         1406         if(isv4(ip)){
         1407                 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
         1408                         return V4;
         1409                 else if(ipcmp(ip, IPv4bcast) == 0)
         1410                         return V4;
         1411         }
         1412         else if(ip[0] == 0xff)
         1413                 return V6;
         1414         return 0;
         1415 }
         1416 
         1417 
         1418 /*
         1419  *  add a multicast address to an interface, called with c->car locked
         1420  */
         1421 void
         1422 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
         1423 {
         1424         Ipifc *ifc;
         1425         Iplifc *lifc;
         1426         Conv **p;
         1427         Ipmulti *multi, **l;
         1428         Fs *f;
         1429 
         1430         f = c->p->f;
         1431 
         1432         for(l = &c->multi; *l; l = &(*l)->next)
         1433                 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
         1434                         return;                /* it's already there */
         1435 
         1436         multi = *l = smalloc(sizeof(*multi));
         1437         ipmove(multi->ma, ma);
         1438         ipmove(multi->ia, ia);
         1439         multi->next = nil;
         1440 
         1441         for(p = f->ipifc->conv; *p; p++){
         1442                 if((*p)->inuse == 0)
         1443                         continue;
         1444                 ifc = (Ipifc*)(*p)->ptcl;
         1445                 if(waserror()){
         1446                         WUNLOCK(ifc);
         1447                         nexterror();
         1448                 }
         1449                 WLOCK(ifc);
         1450                 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
         1451                         if(ipcmp(ia, lifc->local) == 0)
         1452                                 addselfcache(f, ifc, lifc, ma, Rmulti);
         1453                 WUNLOCK(ifc);
         1454                 poperror();
         1455         }
         1456 }
         1457 
         1458 
         1459 /*
         1460  *  remove a multicast address from an interface, called with c->car locked
         1461  */
         1462 void
         1463 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
         1464 {
         1465         Ipmulti *multi, **l;
         1466         Iplifc *lifc;
         1467         Conv **p;
         1468         Ipifc *ifc;
         1469         Fs *f;
         1470 
         1471         f = c->p->f;
         1472 
         1473         for(l = &c->multi; *l; l = &(*l)->next)
         1474                 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
         1475                         break;
         1476 
         1477         multi = *l;
         1478         if(multi == nil)
         1479                 return;         /* we don't have it open */
         1480 
         1481         *l = multi->next;
         1482 
         1483         for(p = f->ipifc->conv; *p; p++){
         1484                 if((*p)->inuse == 0)
         1485                         continue;
         1486 
         1487                 ifc = (Ipifc*)(*p)->ptcl;
         1488                 if(waserror()){
         1489                         WUNLOCK(ifc);
         1490                         nexterror();
         1491                 }
         1492                 WLOCK(ifc);
         1493                 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
         1494                         if(ipcmp(ia, lifc->local) == 0)
         1495                                 remselfcache(f, ifc, lifc, ma);
         1496                 WUNLOCK(ifc);
         1497                 poperror();
         1498         }
         1499 
         1500         free(multi);
         1501 }
         1502 
         1503 /*
         1504  *  make lifc's join and leave multicast groups
         1505  */
         1506 static char*
         1507 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
         1508 {
         1509         return nil;
         1510 }
         1511 
         1512 static char*
         1513 ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
         1514 {
         1515         return nil;
         1516 }
         1517 
         1518 static void
         1519 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
         1520 {
         1521         Conv **cp, **e;
         1522         Ipifc *nifc;
         1523         Iplifc *lifc;
         1524         Medium *m;
         1525         uchar net[IPaddrlen];
         1526 
         1527         /* register the address on any network that will proxy for us */
         1528         e = &f->ipifc->conv[f->ipifc->nc];
         1529 
         1530         if(!isv4(ip)) {                                /* V6 */
         1531                 for(cp = f->ipifc->conv; cp < e; cp++){
         1532                         if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
         1533                                 continue;
         1534                         RLOCK(nifc);
         1535                         m = nifc->m;
         1536                         if(m == nil || m->addmulti == nil) {
         1537                                 RUNLOCK(nifc);
         1538                                 continue;
         1539                         }
         1540                         for(lifc = nifc->lifc; lifc; lifc = lifc->next){
         1541                                 maskip(ip, lifc->mask, net);
         1542                                 if(ipcmp(net, lifc->remote) == 0) {
         1543                                         /* add solicited-node multicast addr */
         1544                                         ipv62smcast(net, ip);
         1545                                         addselfcache(f, nifc, lifc, net, Rmulti);
         1546                                         arpenter(f, V6, ip, nifc->mac, 6, 0);
         1547                                         // (*m->addmulti)(nifc, net, ip);
         1548                                         break;
         1549                                 }
         1550                         }
         1551                         RUNLOCK(nifc);
         1552                 }
         1553         }
         1554         else {                                        /* V4 */
         1555                 for(cp = f->ipifc->conv; cp < e; cp++){
         1556                         if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
         1557                                 continue;
         1558                         RLOCK(nifc);
         1559                         m = nifc->m;
         1560                         if(m == nil || m->areg == nil){
         1561                                 RUNLOCK(nifc);
         1562                                 continue;
         1563                         }
         1564                         for(lifc = nifc->lifc; lifc; lifc = lifc->next){
         1565                                 maskip(ip, lifc->mask, net);
         1566                                 if(ipcmp(net, lifc->remote) == 0){
         1567                                         (*m->areg)(nifc, ip);
         1568                                         break;
         1569                                 }
         1570                         }
         1571                         RUNLOCK(nifc);
         1572                 }
         1573         }
         1574 }
         1575 
         1576 
         1577 /* added for new v6 mesg types */
         1578 static void
         1579 adddefroute6(Fs *f, uchar *gate, int force)
         1580 {
         1581         Route *r;
         1582 
         1583         r = v6lookup(f, v6Unspecified, nil);
         1584         /*
         1585          * route entries generated by all other means take precedence
         1586          * over router announcements.
         1587          */
         1588         if (r && !force && strcmp(r->tag, "ra") != 0)
         1589                 return;
         1590 
         1591         v6delroute(f, v6Unspecified, v6Unspecified, 1);
         1592         v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
         1593 }
         1594 
         1595 enum {
         1596         Ngates = 3,
         1597 };
         1598 
         1599 char*
         1600 ipifcadd6(Ipifc *ifc, char**argv, int argc)
         1601 {
         1602         int plen = 64;
         1603         long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
         1604         char addr[40], preflen[6];
         1605         char *params[3];
         1606         uchar autoflag = 1, onlink = 1;
         1607         uchar prefix[IPaddrlen];
         1608         Iplifc *lifc;
         1609 
         1610         switch(argc) {
         1611         case 7:
         1612                 preflt = atoi(argv[6]);
         1613                 /* fall through */
         1614         case 6:
         1615                 validlt = atoi(argv[5]);
         1616                 /* fall through */
         1617         case 5:
         1618                 autoflag = atoi(argv[4]);
         1619                 /* fall through */
         1620         case 4:
         1621                 onlink = atoi(argv[3]);
         1622                 /* fall through */
         1623         case 3:
         1624                 plen = atoi(argv[2]);
         1625                 /* fall through */
         1626         case 2:
         1627                 break;
         1628         default:
         1629                 return Ebadarg;
         1630         }
         1631 
         1632         if (parseip(prefix, argv[1]) != 6 || validlt < preflt || plen < 0 ||
         1633             plen > 64 || islinklocal(prefix))
         1634                 return Ebadarg;
         1635 
         1636         lifc = smalloc(sizeof(Iplifc));
         1637         lifc->onlink = (onlink != 0);
         1638         lifc->autoflag = (autoflag != 0);
         1639         lifc->validlt = validlt;
         1640         lifc->preflt = preflt;
         1641         lifc->origint = origint;
         1642 
         1643         /* issue "add" ctl msg for v6 link-local addr and prefix len */
         1644         if(!ifc->m->pref2addr)
         1645                 return Ebadarg;
         1646         ifc->m->pref2addr(prefix, ifc->mac);        /* mac → v6 link-local addr */
         1647         sprint(addr, "%I", prefix);
         1648         sprint(preflen, "/%d", plen);
         1649         params[0] = "add";
         1650         params[1] = addr;
         1651         params[2] = preflen;
         1652 
         1653         return ipifcadd(ifc, params, 3, 0, lifc);
         1654 }