File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dnsmasq / src / dhcp6.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 29 19:37:40 2013 UTC (10 years, 11 months ago) by misho
Branches: elwix, dnsmasq, MAIN
CVS tags: v2_66p0, v2_66, HEAD
dnsmasq

    1: /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
    2: 
    3:    This program is free software; you can redistribute it and/or modify
    4:    it under the terms of the GNU General Public License as published by
    5:    the Free Software Foundation; version 2 dated June, 1991, or
    6:    (at your option) version 3 dated 29 June, 2007.
    7:  
    8:    This program is distributed in the hope that it will be useful,
    9:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   10:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   11:    GNU General Public License for more details.
   12:      
   13:    You should have received a copy of the GNU General Public License
   14:    along with this program.  If not, see <http://www.gnu.org/licenses/>.
   15: */
   16: 
   17: #include "dnsmasq.h"
   18: 
   19: #ifdef HAVE_DHCP6
   20: 
   21: struct iface_param {
   22:   struct dhcp_context *current;
   23:   struct in6_addr fallback;
   24:   int ind, addr_match;
   25: };
   26: 
   27: static int complete_context6(struct in6_addr *local,  int prefix,
   28: 			     int scope, int if_index, int flags, 
   29: 			     unsigned int preferred, unsigned int valid, void *vparam);
   30: 
   31: static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm); 
   32: 
   33: void dhcp6_init(void)
   34: {
   35:   int fd;
   36:   struct sockaddr_in6 saddr;
   37: #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
   38:   int class = IPTOS_CLASS_CS6;
   39: #endif
   40:   int oneopt = 1;
   41: 
   42:   if ((fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) == -1 ||
   43: #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
   44:       setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
   45: #endif
   46:       setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &oneopt, sizeof(oneopt)) == -1 ||
   47:       !fix_fd(fd) ||
   48:       !set_ipv6pktinfo(fd))
   49:     die (_("cannot create DHCPv6 socket: %s"), NULL, EC_BADNET);
   50:   
   51:  /* When bind-interfaces is set, there might be more than one dnmsasq
   52:      instance binding port 547. That's OK if they serve different networks.
   53:      Need to set REUSEADDR|REUSEPORT to make this posible.
   54:      Handle the case that REUSEPORT is defined, but the kernel doesn't 
   55:      support it. This handles the introduction of REUSEPORT on Linux. */
   56:   if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
   57:     {
   58:       int rc = -1, porterr = 0;
   59: 
   60: #ifdef SO_REUSEPORT
   61:       if ((rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &oneopt, sizeof(oneopt))) == -1 &&
   62: 	  errno != ENOPROTOOPT)
   63: 	porterr = 1;
   64: #endif
   65:       
   66:       if (rc == -1 && !porterr)
   67: 	rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &oneopt, sizeof(oneopt));
   68:       
   69:       if (rc == -1)
   70: 	die(_("failed to set SO_REUSE{ADDR|PORT} on DHCPv6 socket: %s"), NULL, EC_BADNET);
   71:     }
   72:   
   73:   memset(&saddr, 0, sizeof(saddr));
   74: #ifdef HAVE_SOCKADDR_SA_LEN
   75:   saddr.sin6_len = sizeof(struct sockaddr_in6);
   76: #endif
   77:   saddr.sin6_family = AF_INET6;
   78:   saddr.sin6_addr = in6addr_any;
   79:   saddr.sin6_port = htons(DHCPV6_SERVER_PORT);
   80:   
   81:   if (bind(fd, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in6)))
   82:     die(_("failed to bind DHCPv6 server socket: %s"), NULL, EC_BADNET);
   83:   
   84:   daemon->dhcp6fd = fd;
   85: }
   86: 
   87: void dhcp6_packet(time_t now)
   88: {
   89:   struct dhcp_context *context;
   90:   struct iface_param parm;
   91:   struct cmsghdr *cmptr;
   92:   struct msghdr msg;
   93:   int if_index = 0;
   94:   union {
   95:     struct cmsghdr align; /* this ensures alignment */
   96:     char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
   97:   } control_u;
   98:   struct sockaddr_in6 from;
   99:   ssize_t sz; 
  100:   struct ifreq ifr;
  101:   struct iname *tmp;
  102:   unsigned short port;
  103: 
  104:   msg.msg_control = control_u.control6;
  105:   msg.msg_controllen = sizeof(control_u);
  106:   msg.msg_flags = 0;
  107:   msg.msg_name = &from;
  108:   msg.msg_namelen = sizeof(from);
  109:   msg.msg_iov =  &daemon->dhcp_packet;
  110:   msg.msg_iovlen = 1;
  111:   
  112:   if ((sz = recv_dhcp_packet(daemon->dhcp6fd, &msg)) == -1)
  113:     return;
  114:   
  115:   for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
  116:     if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
  117:       {
  118: 	union {
  119: 	  unsigned char *c;
  120: 	  struct in6_pktinfo *p;
  121: 	} p;
  122: 	p.c = CMSG_DATA(cmptr);
  123:         
  124: 	if_index = p.p->ipi6_ifindex;
  125:       }
  126: 
  127:   if (!indextoname(daemon->dhcp6fd, if_index, ifr.ifr_name))
  128:     return;
  129:     
  130:   for (tmp = daemon->if_except; tmp; tmp = tmp->next)
  131:     if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
  132:       return;
  133: 
  134:   for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
  135:     if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
  136:       return;
  137:  
  138:   parm.current = NULL;
  139:   parm.ind = if_index;
  140:   parm.addr_match = 0;
  141:   memset(&parm.fallback, 0, IN6ADDRSZ);
  142: 
  143:   for (context = daemon->dhcp6; context; context = context->next)
  144:     if (IN6_IS_ADDR_UNSPECIFIED(&context->start6) && context->prefix == 0)
  145:       {
  146: 	/* wildcard context for DHCP-stateless only */
  147: 	parm.current = context;
  148: 	context->current = NULL;
  149:       }
  150:     else
  151:       {
  152: 	/* unlinked contexts are marked by context->current == context */
  153: 	context->current = context;
  154: 	memset(&context->local6, 0, IN6ADDRSZ);
  155:       }
  156:   
  157:   if (!iface_enumerate(AF_INET6, &parm, complete_context6))
  158:     return;
  159:   
  160:   if (daemon->if_names || daemon->if_addrs)
  161:     {
  162:       
  163:       for (tmp = daemon->if_names; tmp; tmp = tmp->next)
  164: 	if (tmp->name && wildcard_match(tmp->name, ifr.ifr_name))
  165: 	  break;
  166: 
  167:       if (!tmp && !parm.addr_match)
  168: 	return;
  169:     }
  170: 
  171:   lease_prune(NULL, now); /* lose any expired leases */
  172: 
  173:   port = dhcp6_reply(parm.current, if_index, ifr.ifr_name, &parm.fallback, 
  174: 		     sz, IN6_IS_ADDR_MULTICAST(&from.sin6_addr), now);
  175:   
  176:   lease_update_file(now);
  177:   lease_update_dns(0);
  178:   
  179:   /* The port in the source address of the original request should
  180:      be correct, but at least once client sends from the server port,
  181:      so we explicitly send to the client port to a client, and the
  182:      server port to a relay. */
  183:   if (port != 0)
  184:     {
  185:       from.sin6_port = htons(port);
  186:       while (sendto(daemon->dhcp6fd, daemon->outpacket.iov_base, save_counter(0), 
  187: 		    0, (struct sockaddr *)&from, sizeof(from)) == -1 &&
  188: 	   retry_send());
  189:     }
  190: }
  191: 
  192: static int complete_context6(struct in6_addr *local,  int prefix,
  193: 			     int scope, int if_index, int flags, unsigned int preferred, 
  194: 			     unsigned int valid, void *vparam)
  195: {
  196:   struct dhcp_context *context;
  197:   struct iface_param *param = vparam;
  198:   struct iname *tmp;
  199:  
  200:   (void)scope; /* warning */
  201:   
  202:   if (if_index == param->ind &&
  203:       !IN6_IS_ADDR_LOOPBACK(local) &&
  204:       !IN6_IS_ADDR_LINKLOCAL(local) &&
  205:       !IN6_IS_ADDR_MULTICAST(local))
  206:     {
  207:       /* if we have --listen-address config, see if the 
  208: 	 arrival interface has a matching address. */
  209:       for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
  210: 	if (tmp->addr.sa.sa_family == AF_INET6 &&
  211: 	    IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, local))
  212: 	  param->addr_match = 1;
  213:       
  214:       /* Determine a globally address on the arrival interface, even
  215: 	 if we have no matching dhcp-context, because we're only
  216: 	 allocating on remote subnets via relays. This
  217: 	 is used as a default for the DNS server option. */
  218:       param->fallback = *local;
  219:       
  220:       for (context = daemon->dhcp6; context; context = context->next)
  221: 	{
  222: 	  if ((context->flags & CONTEXT_DHCP) &&
  223: 	      !(context->flags & CONTEXT_TEMPLATE) &&
  224: 	      prefix == context->prefix &&
  225: 	      is_same_net6(local, &context->start6, prefix) &&
  226: 	      is_same_net6(local, &context->end6, prefix))
  227: 	    {
  228: 
  229: 
  230: 	      /* link it onto the current chain if we've not seen it before */
  231: 	      if (context->current == context)
  232: 		{
  233: 		  struct dhcp_context *tmp, **up;
  234: 		  
  235: 		  /* use interface values only for contructed contexts */
  236: 		  if (!(context->flags & CONTEXT_CONSTRUCTED))
  237: 		    preferred = valid = 0xffffffff;
  238: 		  else if (flags & IFACE_DEPRECATED)
  239: 		    preferred = 0;
  240: 
  241: 		  if (context->flags & CONTEXT_DEPRECATE)
  242: 		    preferred = 0;
  243: 		  
  244: 		  /* order chain, longest preferred time first */
  245: 		  for (up = &param->current, tmp = param->current; tmp; tmp = tmp->current)
  246: 		    if (tmp->preferred <= preferred)
  247: 		      break;
  248: 		    else
  249: 		      up = &tmp->current;
  250: 		  
  251: 		  context->current = *up;
  252: 		  *up = context;
  253: 		  context->local6 = *local;
  254: 		  context->preferred = preferred;
  255: 		  context->valid = valid;
  256: 		}
  257: 	    }
  258: 	}
  259:     }          
  260:   return 1;
  261: }
  262: 
  263: struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr)
  264: {
  265:   struct dhcp_config *config;
  266:   
  267:   for (config = configs; config; config = config->next)
  268:     if ((config->flags & CONFIG_ADDR6) &&
  269: 	is_same_net6(&config->addr6, net, prefix) &&
  270: 	(prefix == 128 || addr6part(&config->addr6) == addr))
  271:       return config;
  272:   
  273:   return NULL;
  274: }
  275: 
  276: struct dhcp_context *address6_allocate(struct dhcp_context *context,  unsigned char *clid, int clid_len, 
  277: 				       int iaid, int serial, struct dhcp_netid *netids, int plain_range, struct in6_addr *ans)   
  278: {
  279:   /* Find a free address: exclude anything in use and anything allocated to
  280:      a particular hwaddr/clientid/hostname in our configuration.
  281:      Try to return from contexts which match netids first. 
  282:      
  283:      Note that we assume the address prefix lengths are 64 or greater, so we can
  284:      get by with 64 bit arithmetic.
  285: */
  286: 
  287:   u64 start, addr;
  288:   struct dhcp_context *c, *d;
  289:   int i, pass;
  290:   u64 j; 
  291: 
  292:   /* hash hwaddr: use the SDBM hashing algorithm.  This works
  293:      for MAC addresses, let's see how it manages with client-ids! */
  294:   for (j = iaid, i = 0; i < clid_len; i++)
  295:     j += clid[i] + (j << 6) + (j << 16) - j;
  296:   
  297:   for (pass = 0; pass <= plain_range ? 1 : 0; pass++)
  298:     for (c = context; c; c = c->current)
  299:       if (c->flags & (CONTEXT_DEPRECATE | CONTEXT_STATIC | CONTEXT_RA_STATELESS | CONTEXT_USED))
  300: 	continue;
  301:       else if (!match_netid(c->filter, netids, pass))
  302: 	continue;
  303:       else
  304: 	{ 
  305: 	  if (option_bool(OPT_CONSEC_ADDR))
  306: 	    /* seed is largest extant lease addr in this context */
  307: 	    start = lease_find_max_addr6(c) + serial;
  308: 	  else
  309: 	    start = addr6part(&c->start6) + ((j + c->addr_epoch) % (1 + addr6part(&c->end6) - addr6part(&c->start6)));
  310: 
  311: 	  /* iterate until we find a free address. */
  312: 	  addr = start;
  313: 	  
  314: 	  do {
  315: 	    /* eliminate addresses in use by the server. */
  316: 	    for (d = context; d; d = d->current)
  317: 	      if (addr == addr6part(&d->local6))
  318: 		break;
  319: 
  320: 	    if (!d &&
  321: 		!lease6_find_by_addr(&c->start6, c->prefix, addr) && 
  322: 		!config_find_by_address6(daemon->dhcp_conf, &c->start6, c->prefix, addr))
  323: 	      {
  324: 		*ans = c->start6;
  325: 		setaddr6part (ans, addr);
  326: 		return c;
  327: 	      }
  328: 	
  329: 	    addr++;
  330: 	    
  331: 	    if (addr  == addr6part(&c->end6) + 1)
  332: 	      addr = addr6part(&c->start6);
  333: 	    
  334: 	  } while (addr != start);
  335: 	}
  336: 	   
  337:   return NULL;
  338: }
  339: 
  340: /* can dynamically allocate addr */
  341: struct dhcp_context *address6_available(struct dhcp_context *context, 
  342: 					struct in6_addr *taddr,
  343: 					struct dhcp_netid *netids,
  344: 					int plain_range)
  345: {
  346:   u64 start, end, addr = addr6part(taddr);
  347:   struct dhcp_context *tmp;
  348:  
  349:   for (tmp = context; tmp; tmp = tmp->current)
  350:     {
  351:       start = addr6part(&tmp->start6);
  352:       end = addr6part(&tmp->end6);
  353: 
  354:       if (!(tmp->flags & (CONTEXT_STATIC | CONTEXT_RA_STATELESS)) &&
  355:           is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
  356: 	  is_same_net6(&tmp->end6, taddr, tmp->prefix) &&
  357: 	  addr >= start &&
  358:           addr <= end &&
  359:           match_netid(tmp->filter, netids, plain_range))
  360:         return tmp;
  361:     }
  362: 
  363:   return NULL;
  364: }
  365: 
  366: /* address OK if configured */
  367: struct dhcp_context *address6_valid(struct dhcp_context *context, 
  368: 				    struct in6_addr *taddr,
  369: 				    struct dhcp_netid *netids,
  370: 				    int plain_range)
  371: {
  372:   struct dhcp_context *tmp;
  373:  
  374:   for (tmp = context; tmp; tmp = tmp->current)
  375:     if (is_same_net6(&tmp->start6, taddr, tmp->prefix) &&
  376: 	match_netid(tmp->filter, netids, plain_range))
  377:       return tmp;
  378: 
  379:   return NULL;
  380: }
  381: 
  382: int config_valid(struct dhcp_config *config, struct dhcp_context *context, struct in6_addr *addr)
  383: {
  384:   if (!config || !(config->flags & CONFIG_ADDR6))
  385:     return 0;
  386: 
  387:   if ((config->flags & CONFIG_WILDCARD) && context->prefix == 64)
  388:     {
  389:       *addr = context->start6;
  390:       setaddr6part(addr, addr6part(&config->addr6));
  391:       return 1;
  392:     }
  393:   
  394:   if (is_same_net6(&context->start6, &config->addr6, context->prefix))
  395:     {
  396:       *addr = config->addr6;
  397:       return 1;
  398:     }
  399:   
  400:   return 0;
  401: }
  402: 
  403: static int is_config_in_context6(struct dhcp_context *context, struct dhcp_config *config)
  404: {
  405:   if (!(config->flags & CONFIG_ADDR6) || 
  406:       (config->flags & CONFIG_WILDCARD))
  407: 
  408:     return 1;
  409:   
  410:   for (; context; context = context->current)
  411:     if (is_same_net6(&config->addr6, &context->start6, context->prefix))
  412:       return 1;
  413:       
  414:   return 0;
  415: }
  416: 
  417: 
  418: struct dhcp_config *find_config6(struct dhcp_config *configs,
  419: 				 struct dhcp_context *context,
  420: 				 unsigned char *duid, int duid_len,
  421: 				 char *hostname)
  422: {
  423:   struct dhcp_config *config; 
  424:       
  425:   if (duid)
  426:     for (config = configs; config; config = config->next)
  427:       if (config->flags & CONFIG_CLID)
  428: 	{
  429: 	  if (config->clid_len == duid_len && 
  430: 	      memcmp(config->clid, duid, duid_len) == 0 &&
  431: 	      is_config_in_context6(context, config))
  432: 	    return config;
  433: 	}
  434:     
  435:   if (hostname && context)
  436:     for (config = configs; config; config = config->next)
  437:       if ((config->flags & CONFIG_NAME) && 
  438:           hostname_isequal(config->hostname, hostname) &&
  439:           is_config_in_context6(context, config))
  440:         return config;
  441: 
  442:   return NULL;
  443: }
  444: 
  445: void make_duid(time_t now)
  446: {
  447:   if (daemon->duid_config)
  448:     {
  449:       unsigned char *p;
  450:       
  451:       daemon->duid = p = safe_malloc(daemon->duid_config_len + 6);
  452:       daemon->duid_len = daemon->duid_config_len + 6;
  453:       PUTSHORT(2, p); /* DUID_EN */
  454:       PUTLONG(daemon->duid_enterprise, p);
  455:       memcpy(p, daemon->duid_config, daemon->duid_config_len);
  456:     }
  457:   else
  458:     {
  459:       /* rebase epoch to 1/1/2000 */
  460:       time_t newnow = now - 946684800;
  461:       
  462:       iface_enumerate(AF_LOCAL, &newnow, make_duid1);
  463:       
  464:       if(!daemon->duid)
  465: 	die("Cannot create DHCPv6 server DUID: %s", NULL, EC_MISC);
  466:     }
  467: }
  468: 
  469: static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm)
  470: {
  471:   /* create DUID as specified in RFC3315. We use the MAC of the
  472:      first interface we find that isn't loopback or P-to-P and
  473:      has address-type < 256. Address types above 256 are things like 
  474:      tunnels which don't have usable MAC addresses. */
  475:   
  476:   unsigned char *p;
  477:   (void)index;
  478: 
  479:   if (type >= 256)
  480:     return 1;
  481: 
  482: #ifdef HAVE_BROKEN_RTC
  483:   daemon->duid = p = safe_malloc(maclen + 4);
  484:   daemon->duid_len = maclen + 4;
  485:   PUTSHORT(3, p); /* DUID_LL */
  486:   PUTSHORT(type, p); /* address type */
  487: #else
  488:   daemon->duid = p = safe_malloc(maclen + 8);
  489:   daemon->duid_len = maclen + 8;
  490:   PUTSHORT(1, p); /* DUID_LLT */
  491:   PUTSHORT(type, p); /* address type */
  492:   PUTLONG(*((time_t *)parm), p); /* time */
  493: #endif
  494: 
  495:   memcpy(p, mac, maclen);
  496: 
  497:   return 0;
  498: }
  499: 
  500: struct cparam {
  501:   time_t now;
  502:   int newone, newname;
  503: };
  504: 
  505: static int construct_worker(struct in6_addr *local, int prefix, 
  506: 			    int scope, int if_index, int flags, 
  507: 			    int preferred, int valid, void *vparam)
  508: {
  509:   char ifrn_name[IFNAMSIZ];
  510:   struct in6_addr start6, end6;
  511:   struct dhcp_context *template, *context;
  512: 
  513:   (void)scope;
  514:   (void)flags;
  515:   (void)valid;
  516:   (void)preferred;
  517: 
  518:   struct cparam *param = vparam;
  519: 
  520:   if (IN6_IS_ADDR_LOOPBACK(local) ||
  521:       IN6_IS_ADDR_LINKLOCAL(local) ||
  522:       IN6_IS_ADDR_MULTICAST(local))
  523:     return 1;
  524: 
  525:   if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name))
  526:     return 0;
  527:   
  528:   for (template = daemon->dhcp6; template; template = template->next)
  529:     if (!(template->flags & CONTEXT_TEMPLATE))
  530:       {
  531: 	/* non-template entries, just fill in interface and local addresses */
  532: 	if (prefix == template->prefix &&
  533: 	    is_same_net6(local, &template->start6, prefix) &&
  534: 	    is_same_net6(local, &template->end6, prefix))
  535: 	  {
  536: 	    template->if_index = if_index;
  537: 	    template->local6 = *local;
  538: 	  }
  539: 	
  540:       }
  541:     else if (addr6part(local) == addr6part(&template->start6) && wildcard_match(template->template_interface, ifrn_name))
  542:       {
  543: 	start6 = *local;
  544: 	setaddr6part(&start6, addr6part(&template->start6));
  545: 	end6 = *local;
  546: 	setaddr6part(&end6, addr6part(&template->end6));
  547: 	
  548: 	for (context = daemon->dhcp6; context; context = context->next)
  549: 	  if ((context->flags & CONTEXT_CONSTRUCTED) &&
  550: 	      IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
  551: 	      IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
  552: 	    {
  553: 	      context->flags &= ~CONTEXT_GC;
  554: 	      break;
  555: 	    }
  556: 	
  557: 	if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
  558: 	  {
  559: 	    *context = *template;
  560: 	    context->start6 = start6;
  561: 	    context->end6 = end6;
  562: 	    context->flags &= ~CONTEXT_TEMPLATE;
  563: 	    context->flags |= CONTEXT_CONSTRUCTED;
  564: 	    context->if_index = if_index;
  565: 	    context->local6 = *local;
  566: 	    
  567: 	    context->next = daemon->dhcp6;
  568: 	    daemon->dhcp6 = context;
  569: 
  570: 	    ra_start_unsolicted(param->now, context);
  571: 	    /* we created a new one, need to call
  572: 	       lease_update_file to get periodic functions called */
  573: 	    param->newone = 1; 
  574: 
  575: 	    /* Will need to add new putative SLAAC addresses to existing leases */
  576: 	    if (context->flags & CONTEXT_RA_NAME)
  577: 	      param->newname = 1;
  578: 	    
  579: 	    log_context(AF_INET6, context);
  580: 	  } 
  581:       }
  582:   
  583:   return 1;
  584: }
  585: 
  586: void dhcp_construct_contexts(time_t now)
  587: { 
  588:   struct dhcp_context *tmp, *context, **up;
  589:   struct cparam param;
  590:   param.newone = 0;
  591:   param.newname = 0;
  592:   param.now = now;
  593: 
  594:   for (context = daemon->dhcp6; context; context = context->next)
  595:     {
  596:       context->if_index = 0;
  597:       if (context->flags & CONTEXT_CONSTRUCTED)
  598:       	context->flags |= CONTEXT_GC;
  599:     }
  600:  
  601:   iface_enumerate(AF_INET6, &param, construct_worker);
  602: 
  603:   for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
  604:     {
  605:       tmp = context->next;
  606:       
  607:       if (context->flags & CONTEXT_GC)
  608: 	{
  609: 	  *up = context->next;
  610: 	  param.newone = 1; /* include deletion */ 
  611: 	  if (context->flags & CONTEXT_RA_NAME)
  612: 	    param.newname = 1; 
  613: 	  free(context);
  614: 	}
  615:       else
  616: 	up = &context->next;
  617:     }
  618:   
  619:   if (param.newone)
  620:     {
  621:       if (daemon->dhcp || daemon->doing_dhcp6)
  622: 	{
  623: 	  if (param.newname)
  624: 	    lease_update_slaac(now);
  625: 	  lease_update_file(now);
  626: 	}
  627:       else 
  628: 	/* Not doing DHCP, so no lease system, manage alarms for ra only */
  629: 	send_alarm(periodic_ra(now), now);
  630:     }
  631: }
  632: 
  633: #endif
  634: 
  635: 

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