The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ip/ipifc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include "u.h"
    2 #include "../port/lib.h"
    3 #include "mem.h"
    4 #include "dat.h"
    5 #include "fns.h"
    6 #include "../port/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;
   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) ( ( ((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         USED(atype);
 1233         USED(atypel);
 1234         qlock(f->ipifc);
 1235         r = v6lookup(f, remote, nil);
 1236         version = (memcmp(remote, v4prefix, IPv4off) == 0)? V4: V6;
 1237 
 1238         if(r != nil){
 1239                 ifc = r->ifc;
 1240                 if(r->type & Rv4)
 1241                         v4tov6(gate, r->v4.gate);
 1242                 else {
 1243                         ipmove(gate, r->v6.gate);
 1244                         ipmove(local, v6Unspecified);
 1245                 }
 1246 
 1247                 switch(version) {
 1248                 case V4:
 1249                         /* find ifc address closest to the gateway to use */
 1250                         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
 1251                                 maskip(gate, lifc->mask, gnet);
 1252                                 if(ipcmp(gnet, lifc->net) == 0){
 1253                                         ipmove(local, lifc->local);
 1254                                         goto out;
 1255                                 }
 1256                         }
 1257                         break;
 1258                 case V6:
 1259                         /* find ifc address with scope matching the destination */
 1260                         atyper = v6addrtype(remote);
 1261                         deprecated = 0;
 1262                         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
 1263                                 atypel = v6addrtype(lifc->local);
 1264                                 /* prefer appropriate scope */
 1265                                 if(atypel > atype && atype < atyper ||
 1266                                    atypel < atype && atype > atyper){
 1267                                         ipmove(local, lifc->local);
 1268                                         deprecated = !v6addrcurr(lifc);
 1269                                         atype = atypel;
 1270                                 } else if(atypel == atype){
 1271                                         /* avoid deprecated addresses */
 1272                                         if(deprecated && v6addrcurr(lifc)){
 1273                                                 ipmove(local, lifc->local);
 1274                                                 atype = atypel;
 1275                                                 deprecated = 0;
 1276                                         }
 1277                                 }
 1278                                 if(atype == atyper && !deprecated)
 1279                                         goto out;
 1280                         }
 1281                         if(atype >= atyper)
 1282                                 goto out;
 1283                         break;
 1284                 default:
 1285                         panic("findlocalip: version %d", version);
 1286                 }
 1287         }
 1288 
 1289         switch(version){
 1290         case V4:
 1291                 findprimaryipv4(f, local);
 1292                 break;
 1293         case V6:
 1294                 findprimaryipv6(f, local);
 1295                 break;
 1296         default:
 1297                 panic("findlocalip2: version %d", version);
 1298         }
 1299 
 1300 out:
 1301         qunlock(f->ipifc);
 1302 }
 1303 
 1304 /*
 1305  *  return first v4 address associated with an interface
 1306  */
 1307 int
 1308 ipv4local(Ipifc *ifc, uchar *addr)
 1309 {
 1310         Iplifc *lifc;
 1311 
 1312         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
 1313                 if(isv4(lifc->local)){
 1314                         memmove(addr, lifc->local+IPv4off, IPv4addrlen);
 1315                         return 1;
 1316                 }
 1317         }
 1318         return 0;
 1319 }
 1320 
 1321 /*
 1322  *  return first v6 address associated with an interface
 1323  */
 1324 int
 1325 ipv6local(Ipifc *ifc, uchar *addr)
 1326 {
 1327         Iplifc *lifc;
 1328 
 1329         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
 1330                 if(!isv4(lifc->local) && !(lifc->tentative)){
 1331                         ipmove(addr, lifc->local);
 1332                         return 1;
 1333                 }
 1334         }
 1335         return 0;
 1336 }
 1337 
 1338 int
 1339 ipv6anylocal(Ipifc *ifc, uchar *addr)
 1340 {
 1341         Iplifc *lifc;
 1342 
 1343         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
 1344                 if(!isv4(lifc->local)){
 1345                         ipmove(addr, lifc->local);
 1346                         return SRC_UNI;
 1347                 }
 1348         }
 1349         return SRC_UNSPEC;
 1350 }
 1351 
 1352 /*
 1353  *  see if this address is bound to the interface
 1354  */
 1355 Iplifc*
 1356 iplocalonifc(Ipifc *ifc, uchar *ip)
 1357 {
 1358         Iplifc *lifc;
 1359 
 1360         for(lifc = ifc->lifc; lifc; lifc = lifc->next)
 1361                 if(ipcmp(ip, lifc->local) == 0)
 1362                         return lifc;
 1363         return nil;
 1364 }
 1365 
 1366 
 1367 /*
 1368  *  See if we're proxying for this address on this interface
 1369  */
 1370 int
 1371 ipproxyifc(Fs *f, Ipifc *ifc, uchar *ip)
 1372 {
 1373         Route *r;
 1374         uchar net[IPaddrlen];
 1375         Iplifc *lifc;
 1376 
 1377         /* see if this is a direct connected pt to pt address */
 1378         r = v6lookup(f, ip, nil);
 1379         if(r == nil || (r->type & (Rifc|Rproxy)) != (Rifc|Rproxy))
 1380                 return 0;
 1381 
 1382         /* see if this is on the right interface */
 1383         for(lifc = ifc->lifc; lifc; lifc = lifc->next){
 1384                 maskip(ip, lifc->mask, net);
 1385                 if(ipcmp(net, lifc->remote) == 0)
 1386                         return 1;
 1387         }
 1388         return 0;
 1389 }
 1390 
 1391 /*
 1392  *  return multicast version if any
 1393  */
 1394 int
 1395 ipismulticast(uchar *ip)
 1396 {
 1397         if(isv4(ip)){
 1398                 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
 1399                         return V4;
 1400         }
 1401         else if(ip[0] == 0xff)
 1402                 return V6;
 1403         return 0;
 1404 }
 1405 int
 1406 ipisbm(uchar *ip)
 1407 {
 1408         if(isv4(ip)){
 1409                 if(ip[IPv4off] >= 0xe0 && ip[IPv4off] < 0xf0)
 1410                         return V4;
 1411                 else if(ipcmp(ip, IPv4bcast) == 0)
 1412                         return V4;
 1413         }
 1414         else if(ip[0] == 0xff)
 1415                 return V6;
 1416         return 0;
 1417 }
 1418 
 1419 
 1420 /*
 1421  *  add a multicast address to an interface, called with c->car locked
 1422  */
 1423 void
 1424 ipifcaddmulti(Conv *c, uchar *ma, uchar *ia)
 1425 {
 1426         Ipifc *ifc;
 1427         Iplifc *lifc;
 1428         Conv **p;
 1429         Ipmulti *multi, **l;
 1430         Fs *f;
 1431 
 1432         f = c->p->f;
 1433 
 1434         for(l = &c->multi; *l; l = &(*l)->next)
 1435                 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
 1436                         return;         /* it's already there */
 1437 
 1438         multi = *l = smalloc(sizeof(*multi));
 1439         ipmove(multi->ma, ma);
 1440         ipmove(multi->ia, ia);
 1441         multi->next = nil;
 1442 
 1443         for(p = f->ipifc->conv; *p; p++){
 1444                 if((*p)->inuse == 0)
 1445                         continue;
 1446                 ifc = (Ipifc*)(*p)->ptcl;
 1447                 if(waserror()){
 1448                         wunlock(ifc);
 1449                         nexterror();
 1450                 }
 1451                 wlock(ifc);
 1452                 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
 1453                         if(ipcmp(ia, lifc->local) == 0)
 1454                                 addselfcache(f, ifc, lifc, ma, Rmulti);
 1455                 wunlock(ifc);
 1456                 poperror();
 1457         }
 1458 }
 1459 
 1460 
 1461 /*
 1462  *  remove a multicast address from an interface, called with c->car locked
 1463  */
 1464 void
 1465 ipifcremmulti(Conv *c, uchar *ma, uchar *ia)
 1466 {
 1467         Ipmulti *multi, **l;
 1468         Iplifc *lifc;
 1469         Conv **p;
 1470         Ipifc *ifc;
 1471         Fs *f;
 1472 
 1473         f = c->p->f;
 1474 
 1475         for(l = &c->multi; *l; l = &(*l)->next)
 1476                 if(ipcmp(ma, (*l)->ma) == 0 && ipcmp(ia, (*l)->ia) == 0)
 1477                         break;
 1478 
 1479         multi = *l;
 1480         if(multi == nil)
 1481                 return;         /* we don't have it open */
 1482 
 1483         *l = multi->next;
 1484 
 1485         for(p = f->ipifc->conv; *p; p++){
 1486                 if((*p)->inuse == 0)
 1487                         continue;
 1488 
 1489                 ifc = (Ipifc*)(*p)->ptcl;
 1490                 if(waserror()){
 1491                         wunlock(ifc);
 1492                         nexterror();
 1493                 }
 1494                 wlock(ifc);
 1495                 for(lifc = ifc->lifc; lifc; lifc = lifc->next)
 1496                         if(ipcmp(ia, lifc->local) == 0)
 1497                                 remselfcache(f, ifc, lifc, ma);
 1498                 wunlock(ifc);
 1499                 poperror();
 1500         }
 1501 
 1502         free(multi);
 1503 }
 1504 
 1505 /*
 1506  *  make lifc's join and leave multicast groups
 1507  */
 1508 static char*
 1509 ipifcjoinmulti(Ipifc *ifc, char **argv, int argc)
 1510 {
 1511         USED(ifc, argv, argc);
 1512         return nil;
 1513 }
 1514 
 1515 static char*
 1516 ipifcleavemulti(Ipifc *ifc, char **argv, int argc)
 1517 {
 1518         USED(ifc, argv, argc);
 1519         return nil;
 1520 }
 1521 
 1522 static void
 1523 ipifcregisterproxy(Fs *f, Ipifc *ifc, uchar *ip)
 1524 {
 1525         Conv **cp, **e;
 1526         Ipifc *nifc;
 1527         Iplifc *lifc;
 1528         Medium *m;
 1529         uchar net[IPaddrlen];
 1530 
 1531         /* register the address on any network that will proxy for us */
 1532         e = &f->ipifc->conv[f->ipifc->nc];
 1533 
 1534         if(!isv4(ip)) {                         /* V6 */
 1535                 for(cp = f->ipifc->conv; cp < e; cp++){
 1536                         if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
 1537                                 continue;
 1538                         rlock(nifc);
 1539                         m = nifc->m;
 1540                         if(m == nil || m->addmulti == nil) {
 1541                                 runlock(nifc);
 1542                                 continue;
 1543                         }
 1544                         for(lifc = nifc->lifc; lifc; lifc = lifc->next){
 1545                                 maskip(ip, lifc->mask, net);
 1546                                 if(ipcmp(net, lifc->remote) == 0) {
 1547                                         /* add solicited-node multicast addr */
 1548                                         ipv62smcast(net, ip);
 1549                                         addselfcache(f, nifc, lifc, net, Rmulti);
 1550                                         arpenter(f, V6, ip, nifc->mac, 6, 0);
 1551                                         // (*m->addmulti)(nifc, net, ip);
 1552                                         break;
 1553                                 }
 1554                         }
 1555                         runlock(nifc);
 1556                 }
 1557         }
 1558         else {                                  /* V4 */
 1559                 for(cp = f->ipifc->conv; cp < e; cp++){
 1560                         if(*cp == nil || (nifc = (Ipifc*)(*cp)->ptcl) == ifc)
 1561                                 continue;
 1562                         rlock(nifc);
 1563                         m = nifc->m;
 1564                         if(m == nil || m->areg == nil){
 1565                                 runlock(nifc);
 1566                                 continue;
 1567                         }
 1568                         for(lifc = nifc->lifc; lifc; lifc = lifc->next){
 1569                                 maskip(ip, lifc->mask, net);
 1570                                 if(ipcmp(net, lifc->remote) == 0){
 1571                                         (*m->areg)(nifc, ip);
 1572                                         break;
 1573                                 }
 1574                         }
 1575                         runlock(nifc);
 1576                 }
 1577         }
 1578 }
 1579 
 1580 
 1581 /* added for new v6 mesg types */
 1582 static void
 1583 adddefroute6(Fs *f, uchar *gate, int force)
 1584 {
 1585         Route *r;
 1586 
 1587         r = v6lookup(f, v6Unspecified, nil);
 1588         /*
 1589          * route entries generated by all other means take precedence
 1590          * over router announcements.
 1591          */
 1592         if (r && !force && strcmp(r->tag, "ra") != 0)
 1593                 return;
 1594 
 1595         v6delroute(f, v6Unspecified, v6Unspecified, 1);
 1596         v6addroute(f, "ra", v6Unspecified, v6Unspecified, gate, 0);
 1597 }
 1598 
 1599 enum {
 1600         Ngates = 3,
 1601 };
 1602 
 1603 char*
 1604 ipifcadd6(Ipifc *ifc, char**argv, int argc)
 1605 {
 1606         int plen = 64;
 1607         long origint = NOW / 1000, preflt = ~0L, validlt = ~0L;
 1608         char addr[40], preflen[6];
 1609         char *params[3];
 1610         uchar autoflag = 1, onlink = 1;
 1611         uchar prefix[IPaddrlen];
 1612         Iplifc *lifc;
 1613 
 1614         switch(argc) {
 1615         case 7:
 1616                 preflt = atoi(argv[6]);
 1617                 /* fall through */
 1618         case 6:
 1619                 validlt = atoi(argv[5]);
 1620                 /* fall through */
 1621         case 5:
 1622                 autoflag = atoi(argv[4]);
 1623                 /* fall through */
 1624         case 4:
 1625                 onlink = atoi(argv[3]);
 1626                 /* fall through */
 1627         case 3:
 1628                 plen = atoi(argv[2]);
 1629                 /* fall through */
 1630         case 2:
 1631                 break;
 1632         default:
 1633                 return Ebadarg;
 1634         }
 1635 
 1636         if (parseip(prefix, argv[1]) != 6 || validlt < preflt || plen < 0 ||
 1637             plen > 64 || islinklocal(prefix))
 1638                 return Ebadarg;
 1639 
 1640         lifc = smalloc(sizeof(Iplifc));
 1641         lifc->onlink = (onlink != 0);
 1642         lifc->autoflag = (autoflag != 0);
 1643         lifc->validlt = validlt;
 1644         lifc->preflt = preflt;
 1645         lifc->origint = origint;
 1646 
 1647         /* issue "add" ctl msg for v6 link-local addr and prefix len */
 1648         if(!ifc->m->pref2addr)
 1649                 return Ebadarg;
 1650         ifc->m->pref2addr(prefix, ifc->mac);    /* mac → v6 link-local addr */
 1651         sprint(addr, "%I", prefix);
 1652         sprint(preflen, "/%d", plen);
 1653         params[0] = "add";
 1654         params[1] = addr;
 1655         params[2] = preflen;
 1656 
 1657         return ipifcadd(ifc, params, 3, 0, lifc);
 1658 }

Cache object: eacbf15cdec031d1bb7779464eaa85ff


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.