Diff for /embedaddon/dnsmasq/src/dhcp6.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2013/07/29 19:37:40 version 1.1.1.2, 2014/06/15 16:31:38
Line 1 Line 1
/* dnsmasq is Copyright (c) 2000-2013 Simon Kelley/* dnsmasq is Copyright (c) 2000-2014 Simon Kelley
   
    This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
Line 18 Line 18
   
 #ifdef HAVE_DHCP6  #ifdef HAVE_DHCP6
   
   #include <netinet/icmp6.h>
   
 struct iface_param {  struct iface_param {
   struct dhcp_context *current;    struct dhcp_context *current;
  struct in6_addr fallback;  struct dhcp_relay *relay;
   struct in6_addr fallback, relay_local, ll_addr, ula_addr;
   int ind, addr_match;    int ind, addr_match;
 };  };
   
   struct mac_param {
     struct in6_addr *target;
     unsigned char *mac;
     unsigned int maclen;
   };
   
   
 static int complete_context6(struct in6_addr *local,  int prefix,  static int complete_context6(struct in6_addr *local,  int prefix,
                              int scope, int if_index, int flags,                                int scope, int if_index, int flags, 
                              unsigned int preferred, unsigned int valid, void *vparam);                               unsigned int preferred, unsigned int valid, void *vparam);
static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv);
 static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);   static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm); 
   
 void dhcp6_init(void)  void dhcp6_init(void)
Line 55  void dhcp6_init(void) Line 65  void dhcp6_init(void)
      support it. This handles the introduction of REUSEPORT on Linux. */       support it. This handles the introduction of REUSEPORT on Linux. */
   if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))    if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
     {      {
      int rc = -1, porterr = 0;      int rc = 0;
   
 #ifdef SO_REUSEPORT  #ifdef SO_REUSEPORT
       if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&        if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
          errno != ENOPROTOOPT)          errno == ENOPROTOOPT)
        porterr = 1;        rc = 0;
 #endif  #endif
               
      if (rc == -1 && !porterr)      if (rc != -1)
         rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));          rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
               
       if (rc == -1)        if (rc == -1)
Line 87  void dhcp6_init(void) Line 97  void dhcp6_init(void)
 void dhcp6_packet(time_t now)  void dhcp6_packet(time_t now)
 {  {
   struct dhcp_context *context;    struct dhcp_context *context;
     struct dhcp_relay *relay;
   struct iface_param parm;    struct iface_param parm;
   struct cmsghdr *cmptr;    struct cmsghdr *cmptr;
   struct msghdr msg;    struct msghdr msg;
Line 100  void dhcp6_packet(time_t now) Line 111  void dhcp6_packet(time_t now)
   struct ifreq ifr;    struct ifreq ifr;
   struct iname *tmp;    struct iname *tmp;
   unsigned short port;    unsigned short port;
     struct in6_addr dst_addr;
   
     memset(&dst_addr, 0, sizeof(dst_addr));
   
   msg.msg_control = control_u.control6;    msg.msg_control = control_u.control6;
   msg.msg_controllen = sizeof(control_u);    msg.msg_controllen = sizeof(control_u);
   msg.msg_flags = 0;    msg.msg_flags = 0;
Line 122  void dhcp6_packet(time_t now) Line 136  void dhcp6_packet(time_t now)
         p.c = CMSG_DATA(cmptr);          p.c = CMSG_DATA(cmptr);
                   
         if_index = p.p->ipi6_ifindex;          if_index = p.p->ipi6_ifindex;
           dst_addr = p.p->ipi6_addr;
       }        }
   
   if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))    if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
     return;      return;
       
   for (tmp = daemon->if_except; tmp; tmp = tmp->next)  
     if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))  
       return;  
   
  for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)  if ((port = relay_reply6(&from, sz, ifr.ifr_name)) == 0)
    if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name)) 
      return; 
  
  parm.current = NULL; 
  parm.ind = if_index; 
  parm.addr_match = 0; 
  memset(&parm.fallback, 0, IN6ADDRSZ); 
 
  for (context = daemon->dhcp6; context; context = context->next) 
    if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0) 
      { 
        /* wildcard context for DHCP-stateless only */ 
        parm.current = context; 
        context->current = NULL; 
      } 
    else 
      { 
        /* unlinked contexts are marked by context->current == context */ 
        context->current = context; 
        memset(&context->local6, 0, IN6ADDRSZ); 
      } 
   
  if (!iface_enumerate(AF_INET6, &parm, complete_context6)) 
    return; 
   
  if (daemon->if_names || daemon->if_addrs) 
     {      {
         for (tmp = daemon->if_except; tmp; tmp = tmp->next)
           if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
             return;
               
      for (tmp = daemon->if_names; tmp; tmp = tmp->next)      for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
         if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))          if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
          break;          return;
       
       parm.current = NULL;
       parm.relay = NULL;
       memset(&parm.relay_local, 0, IN6ADDRSZ);
       parm.ind = if_index;
       parm.addr_match = 0;
       memset(&parm.fallback, 0, IN6ADDRSZ);
       memset(&parm.ll_addr, 0, IN6ADDRSZ);
       memset(&parm.ula_addr, 0, IN6ADDRSZ);
       
       for (context = daemon->dhcp6; context; context = context->next)
         if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
           {
             /* wildcard context for DHCP-stateless only */
             parm.current = context;
             context->current = NULL;
           }
         else
           {
             /* unlinked contexts are marked by context->current == context */
             context->current = context;
             memset(&context->local6, 0, IN6ADDRSZ);
           }
   
      if (!tmp && !parm.addr_match)      for (relay = daemon->relay6; relay; relay = relay->next)
         relay->current = relay;
       
       if (!iface_enumerate(AF_INET6, &parm, complete_context6))
         return;          return;
     }  
   
  lease_prune(NULL, now); /* lose any expired leases */      if (daemon->if_names || daemon->if_addrs)
        {
  port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback,           
                     sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);          for (tmp = daemon->if_names; tmp; tmp = tmp->next)
              if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
  lease_update_file(now);              break;
  lease_update_dns(0);          
            if (!tmp && !parm.addr_match)
             return;
         }
       
       if (parm.relay)
         {
           /* Ignore requests sent to the ALL_SERVERS multicast address for relay when
              we're listening there for DHCPv6 server reasons. */
           struct in6_addr all_servers;
           
           inet_pton(AF_INET6, ALL_SERVERS, &all_servers);
           
           if (!IN6_ARE_ADDR_EQUAL(&dst_addr, &all_servers))
             relay_upstream6(parm.relay, sz, &from.sin6_addr, from.sin6_scope_id);
           return;
         }
       
       /* May have configured relay, but not DHCP server */
       if (!daemon->doing_dhcp6)
         return;
       
       lease_prune(NULL, now); /* lose any expired leases */
       
       port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, 
                          &parm.ll_addr, &parm.ula_addr, sz, &from.sin6_addr, now);
       
       lease_update_file(now);
       lease_update_dns(0);
     }
                           
   /* The port in the source address of the original request should    /* The port in the source address of the original request should
      be correct, but at least once client sends from the server port,       be correct, but at least once client sends from the server port,
      so we explicitly send to the client port to a client, and the       so we explicitly send to the client port to a client, and the
Line 189  void dhcp6_packet(time_t now) Line 231  void dhcp6_packet(time_t now)
     }      }
 }  }
   
   void get_client_mac(struct in6_addr *client, int iface, unsigned char *mac, unsigned int *maclenp, unsigned int *mactypep)
   {
     /* Recieving a packet from a host does not populate the neighbour
        cache, so we send a neighbour discovery request if we can't 
        find the sender. Repeat a few times in case of packet loss. */
     
     struct neigh_packet neigh;
     struct sockaddr_in6 addr;
     struct mac_param mac_param;
     int i;
   
     neigh.type = ND_NEIGHBOR_SOLICIT;
     neigh.code = 0;
     neigh.reserved = 0;
     neigh.target = *client;
     
     memset(&addr, 0, sizeof(addr));
   #ifdef HAVE_SOCKADDR_SA_LEN
     addr.sin6_len = sizeof(struct sockaddr_in6);
   #endif
     addr.sin6_family = AF_INET6;
     addr.sin6_port = htons(IPPROTO_ICMPV6);
     addr.sin6_addr = *client;
     addr.sin6_scope_id = iface;
     
     mac_param.target = client;
     mac_param.maclen = 0;
     mac_param.mac = mac;
     
     for (i = 0; i < 5; i++)
       {
         struct timespec ts;
         
         iface_enumerate(AF_UNSPEC, &mac_param, find_mac);
         
         if (mac_param.maclen != 0)
           break;
         
         sendto(daemon->icmp6fd, &neigh, sizeof(neigh), 0, (struct sockaddr *)&addr, sizeof(addr));
         
         ts.tv_sec = 0;
         ts.tv_nsec = 100000000; /* 100ms */
         nanosleep(&ts, NULL);
       }
   
     *maclenp = mac_param.maclen;
     *mactypep = ARPHRD_ETHER;
   }
       
   static int find_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)
   {
     struct mac_param *parm = parmv;
     
     if (family == AF_INET6 && IN6_ARE_ADDR_EQUAL(parm->target, (struct in6_addr *)addrp))
       {
         if (maclen <= DHCP_CHADDR_MAX)
           {
             parm->maclen = maclen;
             memcpy(parm->mac, mac, maclen);
           }
         
         return 0; /* found, abort */
       }
     
     return 1;
   }
   
 static int complete_context6(struct in6_addr *local,  int prefix,  static int complete_context6(struct in6_addr *local,  int prefix,
                              int scope, int if_index, int flags, unsigned int preferred,                                int scope, int if_index, int flags, unsigned int preferred, 
                              unsigned int valid, void *vparam)                               unsigned int valid, void *vparam)
 {  {
   struct dhcp_context *context;    struct dhcp_context *context;
     struct dhcp_relay *relay;
   struct iface_param *param = vparam;    struct iface_param *param = vparam;
   struct iname *tmp;    struct iname *tmp;
     
   (void)scope; /* warning */    (void)scope; /* warning */
       
  if (if_index == param->ind &&  if (if_index == param->ind)
      !IN6_IS_ADDR_LOOPBACK(local) && 
      !IN6_IS_ADDR_LINKLOCAL(local) && 
      !IN6_IS_ADDR_MULTICAST(local)) 
     {      {
      /* if we have --listen-address config, see if the       if (IN6_IS_ADDR_LINKLOCAL(local))
         arrival interface has a matching address. */        param->ll_addr = *local;
      for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)      else if (IN6_IS_ADDR_ULA(local))
        if (tmp->addr.sa.sa_family == AF_INET6 &&        param->ula_addr = *local;
            IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
          param->addr_match = 1;      if (!IN6_IS_ADDR_LOOPBACK(local) &&
                !IN6_IS_ADDR_LINKLOCAL(local) &&
      /* Determine a globally address on the arrival interface, even          !IN6_IS_ADDR_MULTICAST(local))
         if we have no matching dhcp-context, because we're only 
         allocating on remote subnets via relays. This 
         is used as a default for the DNS server option. */ 
      param->fallback = *local; 
       
      for (context = daemon->dhcp6; context; context = context->next) 
         {          {
          if ((context->flags & CONTEXT_DHCP) &&          /* if we have --listen-address config, see if the 
              !(context->flags & CONTEXT_TEMPLATE) &&             arrival interface has a matching address. */
              prefix == context->prefix &&          for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
              is_same_net6(local, &context->start6, prefix) &&            if (tmp->addr.sa.sa_family == AF_INET6 &&
              is_same_net6(local, &context->end6, prefix))                IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
               param->addr_match = 1;
           
           /* Determine a globally address on the arrival interface, even
              if we have no matching dhcp-context, because we're only
              allocating on remote subnets via relays. This
              is used as a default for the DNS server option. */
           param->fallback = *local;
           
           for (context = daemon->dhcp6; context; context = context->next)
             {              {
              if ((context->flags & CONTEXT_DHCP) &&
                  !(context->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) &&
              /* link it onto the current chain if we've not seen it before */                  prefix <= context->prefix &&
              if (context->current == context)                  is_same_net6(local, &context->start6, context->prefix) &&
                   is_same_net6(local, &context->end6, context->prefix))
                 {                  {
                   struct dhcp_context *tmp, **up;  
                                       
                   /* use interface values only for contructed contexts */  
                   if (!(context->flags & CONTEXT_CONSTRUCTED))  
                     preferred = valid = 0xffffffff;  
                   else if (flags & IFACE_DEPRECATED)  
                     preferred = 0;  
   
                   if (context->flags & CONTEXT_DEPRECATE)  
                     preferred = 0;  
                                       
                  /* order chain, longest preferred time first */                  /* link it onto the current chain if we've not seen it before */
                  for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)                  if (context->current == context)
                    if (tmp->preferred <= preferred)                    {
                      break;                      struct dhcp_context *tmp, **up;
                    else                      
                      up = &tmp->current;                      /* use interface values only for contructed contexts */
                                        if (!(context->flags & CONTEXT_CONSTRUCTED))
                  context->current = *up;                        preferred = valid = 0xffffffff;
                  *up = context;                      else if (flags & IFACE_DEPRECATED)
                  context->local6 = *local;                        preferred = 0;
                  context->preferred = preferred;                      
                  context->valid = valid;                      if (context->flags & CONTEXT_DEPRECATE)
                         preferred = 0;
                       
                       /* order chain, longest preferred time first */
                       for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
                         if (tmp->preferred <= preferred)
                           break;
                         else
                           up = &tmp->current;
                       
                       context->current = *up;
                       *up = context;
                       context->local6 = *local;
                       context->preferred = preferred;
                       context->valid = valid;
                     }
                 }                  }
             }              }
         }          }
   
         for (relay = daemon->relay6; relay; relay = relay->next)
           if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr.addr6) && relay->current == relay &&
               (IN6_IS_ADDR_UNSPECIFIED(&param->relay_local) || IN6_ARE_ADDR_EQUAL(local, &param->relay_local)))
             {
               relay->current = param->relay;
               param->relay = relay;
               param->relay_local = *local;
             }
         
     }                }          
  return 1; 
  return 1;
 }  }
   
 struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)  struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
Line 273  struct dhcp_config *config_find_by_address6(struct dhc Line 401  struct dhcp_config *config_find_by_address6(struct dhc
   return NULL;    return NULL;
 }  }
   
struct dhcp_context *address6_allocate(struct dhcp_context *context,  unsigned char *clid, int clid_len, struct dhcp_context *address6_allocate(struct dhcp_context *context,  unsigned char *clid, int clid_len, int temp_addr,
                                        int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)                                            int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)   
 {  {
   /* Find a free address: exclude anything in use and anything allocated to    /* Find a free address: exclude anything in use and anything allocated to
Line 290  struct dhcp_context *address6_allocate(struct dhcp_con Line 418  struct dhcp_context *address6_allocate(struct dhcp_con
   u64 j;     u64 j; 
   
   /* hash hwaddr: use the SDBM hashing algorithm.  This works    /* hash hwaddr: use the SDBM hashing algorithm.  This works
     for MAC addresses, let's see how it manages with client-ids! */     for MAC addresses, let's see how it manages with client-ids! 
  for (j = iaid, i = 0; i < clid_len; i++)     For temporary addresses, we generate a new random one each time. */
    j += clid[i] + (j << 6) + (j << 16) - j;  if (temp_addr)
     j = rand64();
   else
     for (j = iaid, i = 0; i < clid_len; i++)
       j += clid[i] + (j << 6) + (j << 16) - j;
       
   for (pass = 0; pass <= plain_range ? 1 : 0; pass++)    for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
     for (c = context; c; c = c->current)      for (c = context; c; c = c->current)
Line 302  struct dhcp_context *address6_allocate(struct dhcp_con Line 434  struct dhcp_context *address6_allocate(struct dhcp_con
         continue;          continue;
       else        else
         {           { 
          if (option_bool(OPT_CONSEC_ADDR))          if (!temp_addr && option_bool(OPT_CONSEC_ADDR))
             /* seed is largest extant lease addr in this context */              /* seed is largest extant lease addr in this context */
             start = lease_find_max_addr6(c) + serial;              start = lease_find_max_addr6(c) + serial;
           else            else
Line 400  int config_valid(struct dhcp_config *config, struct dh Line 532  int config_valid(struct dhcp_config *config, struct dh
   return 0;    return 0;
 }  }
   
 static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)  
 {  
   if (!(config->flags & CONFIG_ADDR6) ||   
       (config->flags & CONFIG_WILDCARD))  
   
     return 1;  
     
   for (; context; context = context->current)  
     if (is_same_net6(&config->addr6, &context->start6, context->prefix))  
       return 1;  
         
   return 0;  
 }  
   
   
 struct dhcp_config *find_config6(struct dhcp_config *configs,  
                                  struct dhcp_context *context,  
                                  unsigned char *duid, int duid_len,  
                                  char *hostname)  
 {  
   struct dhcp_config *config;   
         
   if (duid)  
     for (config = configs; config; config = config->next)  
       if (config->flags & CONFIG_CLID)  
         {  
           if (config->clid_len == duid_len &&   
               memcmp(config->clid, duid, duid_len) == 0 &&  
               is_config_in_context6(context, config))  
             return config;  
         }  
       
   if (hostname && context)  
     for (config = configs; config; config = config->next)  
       if ((config->flags & CONFIG_NAME) &&   
           hostname_isequal(config->hostname, hostname) &&  
           is_config_in_context6(context, config))  
         return config;  
   
   return NULL;  
 }  
   
 void make_duid(time_t now)  void make_duid(time_t now)
 {  {
     (void)now;
   
   if (daemon->duid_config)    if (daemon->duid_config)
     {      {
       unsigned char *p;        unsigned char *p;
Line 456  void make_duid(time_t now) Line 548  void make_duid(time_t now)
     }      }
   else    else
     {      {
         time_t newnow = 0;
         
         /* If we have no persistent lease database, or a non-stable RTC, use DUID_LL (newnow == 0) */
   #ifndef HAVE_BROKEN_RTC
       /* rebase epoch to 1/1/2000 */        /* rebase epoch to 1/1/2000 */
      time_t newnow = now - 946684800;      if (!option_bool(OPT_LEASE_RO) || daemon->lease_change_command)
         newnow = now - 946684800;
 #endif      
               
       iface_enumerate(AF_LOCAL, &newnow, make_duid1);        iface_enumerate(AF_LOCAL, &newnow, make_duid1);
               
Line 475  static int make_duid1(int index, unsigned int type, ch Line 573  static int make_duid1(int index, unsigned int type, ch
       
   unsigned char *p;    unsigned char *p;
   (void)index;    (void)index;
  (void)parm;
   time_t newnow = *((time_t *)parm);
   
   if (type >= 256)    if (type >= 256)
     return 1;      return 1;
   
#ifdef HAVE_BROKEN_RTC  if (newnow == 0)
  daemon->duid = p = safe_malloc(maclen + 4);    {
  daemon->duid_len = maclen + 4;      daemon->duid = p = safe_malloc(maclen + 4);
  PUTSHORT(3, p); /* DUID_LL */      daemon->duid_len = maclen + 4;
  PUTSHORT(type, p); /* address type */      PUTSHORT(3, p); /* DUID_LL */
#else      PUTSHORT(type, p); /* address type */
  daemon->duid = p = safe_malloc(maclen + 8);    }
  daemon->duid_len = maclen + 8;  else
  PUTSHORT(1, p); /* DUID_LLT */    {
  PUTSHORT(type, p); /* address type */      daemon->duid = p = safe_malloc(maclen + 8);
  PUTLONG(*((time_t *)parm), p); /* time */      daemon->duid_len = maclen + 8;
#endif      PUTSHORT(1, p); /* DUID_LLT */
      PUTSHORT(type, p); /* address type */
       PUTLONG(*((time_t *)parm), p); /* time */
     }
   
   memcpy(p, mac, maclen);    memcpy(p, mac, maclen);
   
   return 0;    return 0;
Line 522  static int construct_worker(struct in6_addr *local, in Line 625  static int construct_worker(struct in6_addr *local, in
       IN6_IS_ADDR_MULTICAST(local))        IN6_IS_ADDR_MULTICAST(local))
     return 1;      return 1;
   
  if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name))  if (!(flags & IFACE_PERMANENT))
     return 1;
 
   if (flags & IFACE_DEPRECATED)
     return 1;
 
   if (!indextoname(daemon->icmp6fd, if_index, ifrn_name))
     return 0;      return 0;
       
   for (template = daemon->dhcp6; template; template = template->next)    for (template = daemon->dhcp6; template; template = template->next)
     if (!(template->flags & CONTEXT_TEMPLATE))      if (!(template->flags & CONTEXT_TEMPLATE))
       {        {
         /* non-template entries, just fill in interface and local addresses */          /* non-template entries, just fill in interface and local addresses */
        if (prefix == template->prefix &&        if (prefix <= template->prefix &&
            is_same_net6(local, &template->start6, prefix) &&            is_same_net6(local, &template->start6, template->prefix) &&
            is_same_net6(local, &template->end6, prefix))            is_same_net6(local, &template->end6, template->prefix))
           {            {
             template->if_index = if_index;              template->if_index = if_index;
             template->local6 = *local;              template->local6 = *local;
           }            }
                   
       }        }
    else if (addr6part(local) == addr6part(&template->start6) && wildcard_match(template->template_interface, ifrn_name))    else if (wildcard_match(template->template_interface, ifrn_name) &&
              template->prefix >= prefix)
       {        {
         start6 = *local;          start6 = *local;
         setaddr6part(&start6, addr6part(&template->start6));          setaddr6part(&start6, addr6part(&template->start6));
Line 550  static int construct_worker(struct in6_addr *local, in Line 660  static int construct_worker(struct in6_addr *local, in
               IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&                IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
               IN6_ARE_ADDR_EQUAL(&end6, &context->end6))                IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
             {              {
              context->flags &= ~CONTEXT_GC;              int flags = context->flags;
               context->flags &= ~(CONTEXT_GC | CONTEXT_OLD);
               if (flags & CONTEXT_OLD)
                 {
                   /* address went, now it's back */
                   log_context(AF_INET6, context); 
                   /* fast RAs for a while */
                   ra_start_unsolicted(param->now, context);
                   param->newone = 1; 
                   /* Add address to name again */
                   if (context->flags & CONTEXT_RA_NAME)
                     param->newname = 1;
                 }
               break;                break;
             }              }
                   
Line 563  static int construct_worker(struct in6_addr *local, in Line 685  static int construct_worker(struct in6_addr *local, in
             context->flags |= CONTEXT_CONSTRUCTED;              context->flags |= CONTEXT_CONSTRUCTED;
             context->if_index = if_index;              context->if_index = if_index;
             context->local6 = *local;              context->local6 = *local;
               context->saved_valid = 0;
                           
             context->next = daemon->dhcp6;              context->next = daemon->dhcp6;
             daemon->dhcp6 = context;              daemon->dhcp6 = context;
Line 585  static int construct_worker(struct in6_addr *local, in Line 708  static int construct_worker(struct in6_addr *local, in
   
 void dhcp_construct_contexts(time_t now)  void dhcp_construct_contexts(time_t now)
 {   { 
  struct dhcp_context *tmp, *context, **up;  struct dhcp_context *context, *tmp, **up;
   struct cparam param;    struct cparam param;
   param.newone = 0;    param.newone = 0;
   param.newname = 0;    param.newname = 0;
   param.now = now;    param.now = now;
   
   for (context = daemon->dhcp6; context; context = context->next)    for (context = daemon->dhcp6; context; context = context->next)
    {    if (context->flags & CONTEXT_CONSTRUCTED)
      context->if_index = 0;      context->flags |= CONTEXT_GC;
      if (context->flags & CONTEXT_CONSTRUCTED)   
        context->flags |= CONTEXT_GC; 
    } 
  
   iface_enumerate(AF_INET6, &param, construct_worker);    iface_enumerate(AF_INET6, &param, construct_worker);
   
   for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)    for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
     {      {
       tmp = context->next;  
               
      if (context->flags & CONTEXT_GC)      tmp = context->next; 
      
       if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
         {          {
          *up = context->next;          if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
          param.newone = 1; /* include deletion */               option_bool(OPT_RA))
          if (context->flags & CONTEXT_RA_NAME)            {
            param.newname = 1;               /* previously constructed context has gone. advertise it's demise */
          free(context);              context->flags |= CONTEXT_OLD;
               context->address_lost_time = now;
               /* Apply same ceiling of configured lease time as in radv.c */
               if (context->saved_valid > context->lease_time)
                 context->saved_valid = context->lease_time;
               /* maximum time is 2 hours, from RFC */
               if (context->saved_valid > 7200) /* 2 hours */
                 context->saved_valid = 7200;
               ra_start_unsolicted(now, context);
               param.newone = 1; /* include deletion */ 
               
               if (context->flags & CONTEXT_RA_NAME)
                 param.newname = 1; 
                               
               log_context(AF_INET6, context);
               
               up = &context->next;
             }
           else
             {
               /* we were never doing RA for this, so free now */
               *up = context->next;
               free(context);
             }
         }          }
       else        else
        up = &context->next;         up = &context->next;
     }      }
       
   if (param.newone)    if (param.newone)

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>