Annotation of embedaddon/dnsmasq/src/radv.c, revision 1.1.1.1

1.1       misho       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: 
                     18: /* NB. This code may be called during a DHCPv4 or transaction which is in ping-wait
                     19:    It therefore cannot use any DHCP buffer resources except outpacket, which is
                     20:    not used by DHCPv4 code. This code may also be called when DHCP 4 or 6 isn't
                     21:    active, so we ensure that outpacket is allocated here too */
                     22: 
                     23: #include "dnsmasq.h"
                     24: 
                     25: #ifdef HAVE_DHCP6
                     26: 
                     27: #include <netinet/icmp6.h>
                     28: 
                     29: struct ra_param {
                     30:   time_t now;
                     31:   int ind, managed, other, found_context, first;
                     32:   char *if_name;
                     33:   struct dhcp_netid *tags;
                     34:   struct in6_addr link_local, link_global;
                     35:   unsigned int pref_time;
                     36: };
                     37: 
                     38: struct search_param {
                     39:   time_t now; int iface;
                     40: };
                     41: 
                     42: static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
                     43: static int add_prefixes(struct in6_addr *local,  int prefix,
                     44:                        int scope, int if_index, int flags, 
                     45:                        unsigned int preferred, unsigned int valid, void *vparam);
                     46: static int iface_search(struct in6_addr *local,  int prefix,
                     47:                        int scope, int if_index, int flags, 
                     48:                        int prefered, int valid, void *vparam);
                     49: static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
                     50: 
                     51: static int hop_limit;
                     52: 
                     53: void ra_init(time_t now)
                     54: {
                     55:   struct icmp6_filter filter;
                     56:   int fd;
                     57: #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
                     58:   int class = IPTOS_CLASS_CS6;
                     59: #endif
                     60:   int val = 255; /* radvd uses this value */
                     61:   socklen_t len = sizeof(int);
                     62:   struct dhcp_context *context;
                     63:   
                     64:   /* ensure this is around even if we're not doing DHCPv6 */
                     65:   expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
                     66:  
                     67:   /* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
                     68:   for (context = daemon->dhcp6; context; context = context->next)
                     69:     if ((context->flags & CONTEXT_RA_NAME))
                     70:       break;
                     71:   
                     72:   ICMP6_FILTER_SETBLOCKALL(&filter);
                     73:   ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
                     74:   if (context)
                     75:     ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filter);
                     76:   
                     77:   if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1 ||
                     78:       getsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hop_limit, &len) ||
                     79: #if defined(IPV6_TCLASS) && defined(IPTOS_CLASS_CS6)
                     80:       setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &class, sizeof(class)) == -1 ||
                     81: #endif
                     82:       !fix_fd(fd) ||
                     83:       !set_ipv6pktinfo(fd) ||
                     84:       setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val)) ||
                     85:       setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &val, sizeof(val)) ||
                     86:       setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) == -1)
                     87:     die (_("cannot create ICMPv6 socket: %s"), NULL, EC_BADNET);
                     88:   
                     89:    daemon->icmp6fd = fd;
                     90:    
                     91:    ra_start_unsolicted(now, NULL);
                     92: }
                     93: 
                     94: void ra_start_unsolicted(time_t now, struct dhcp_context *context)
                     95: {   
                     96:    /* init timers so that we do ra's for some/all soon. some ra_times will end up zeroed
                     97:      if it's not appropriate to advertise those contexts.
                     98:      This gets re-called on a netlink route-change to re-do the advertisement
                     99:      and pick up new interfaces */
                    100:   
                    101:   if (context)
                    102:     context->ra_short_period_start = context->ra_time = now;
                    103:   else
                    104:     for (context = daemon->dhcp6; context; context = context->next)
                    105:       if (!(context->flags & CONTEXT_TEMPLATE))
                    106:        {
                    107:          context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
                    108:          /* re-do frequently for a minute or so, in case the first gets lost. */
                    109:          context->ra_short_period_start = now;
                    110:        }
                    111: }
                    112: 
                    113: void icmp6_packet(time_t now)
                    114: {
                    115:   char interface[IF_NAMESIZE+1];
                    116:   ssize_t sz; 
                    117:   int if_index = 0;
                    118:   struct cmsghdr *cmptr;
                    119:   struct msghdr msg;
                    120:   union {
                    121:     struct cmsghdr align; /* this ensures alignment */
                    122:     char control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
                    123:   } control_u;
                    124:   struct sockaddr_in6 from;
                    125:   unsigned char *packet;
                    126:   struct iname *tmp;
                    127: 
                    128:   /* Note: use outpacket for input buffer */
                    129:   msg.msg_control = control_u.control6;
                    130:   msg.msg_controllen = sizeof(control_u);
                    131:   msg.msg_flags = 0;
                    132:   msg.msg_name = &from;
                    133:   msg.msg_namelen = sizeof(from);
                    134:   msg.msg_iov = &daemon->outpacket;
                    135:   msg.msg_iovlen = 1;
                    136:   
                    137:   if ((sz = recv_dhcp_packet(daemon->icmp6fd, &msg)) == -1 || sz < 8)
                    138:     return;
                    139:    
                    140:   packet = (unsigned char *)daemon->outpacket.iov_base;
                    141:   
                    142:   for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
                    143:     if (cmptr->cmsg_level == IPPROTO_IPV6 && cmptr->cmsg_type == daemon->v6pktinfo)
                    144:       {
                    145:        union {
                    146:          unsigned char *c;
                    147:          struct in6_pktinfo *p;
                    148:        } p;
                    149:        p.c = CMSG_DATA(cmptr);
                    150:         
                    151:        if_index = p.p->ipi6_ifindex;
                    152:       }
                    153:   
                    154:   if (!indextoname(daemon->icmp6fd, if_index, interface))
                    155:     return;
                    156:     
                    157:   if (!iface_check(AF_LOCAL, NULL, interface, NULL))
                    158:     return;
                    159:   
                    160:   for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
                    161:     if (tmp->name && wildcard_match(tmp->name, interface))
                    162:       return;
                    163:  
                    164:   if (packet[1] != 0)
                    165:     return;
                    166:   
                    167:   if (packet[0] == ICMP6_ECHO_REPLY)
                    168:     lease_ping_reply(&from.sin6_addr, packet, interface); 
                    169:   else if (packet[0] == ND_ROUTER_SOLICIT)
                    170:     {
                    171:       char *mac = "";
                    172:       
                    173:       /* look for link-layer address option for logging */
                    174:       if (sz >= 16 && packet[8] == ICMP6_OPT_SOURCE_MAC && (packet[9] * 8) + 8 <= sz)
                    175:        {
                    176:          print_mac(daemon->namebuff, &packet[10], (packet[9] * 8) - 2);
                    177:          mac = daemon->namebuff;
                    178:        }
                    179:          
                    180:       my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
                    181:       /* source address may not be valid in solicit request. */
                    182:       send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
                    183:     }
                    184: }
                    185: 
                    186: static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
                    187: {
                    188:   struct ra_packet *ra;
                    189:   struct ra_param parm;
                    190:   struct ifreq ifr;
                    191:   struct sockaddr_in6 addr;
                    192:   struct dhcp_context *context;
                    193:   struct dhcp_netid iface_id;
                    194:   struct dhcp_opt *opt_cfg;
                    195:   int done_dns = 0;
                    196: #ifdef HAVE_LINUX_NETWORK
                    197:   FILE *f;
                    198: #endif
                    199: 
                    200:   save_counter(0);
                    201:   ra = expand(sizeof(struct ra_packet));
                    202:   
                    203:   ra->type = ND_ROUTER_ADVERT;
                    204:   ra->code = 0;
                    205:   ra->hop_limit = hop_limit;
                    206:   ra->flags = 0x00;
                    207:   ra->lifetime = htons(RA_INTERVAL * 3); /* AdvDefaultLifetime * 3 */
                    208:   ra->reachable_time = 0;
                    209:   ra->retrans_time = 0;
                    210: 
                    211:   parm.ind = iface;
                    212:   parm.managed = 0;
                    213:   parm.other = 0;
                    214:   parm.found_context = 0;
                    215:   parm.if_name = iface_name;
                    216:   parm.first = 1;
                    217:   parm.now = now;
                    218:   parm.pref_time = 0;
                    219:   
                    220:   /* set tag with name == interface */
                    221:   iface_id.net = iface_name;
                    222:   iface_id.next = NULL;
                    223:   parm.tags = &iface_id; 
                    224:   
                    225:   for (context = daemon->dhcp6; context; context = context->next)
                    226:     {
                    227:       context->flags &= ~CONTEXT_RA_DONE;
                    228:       context->netid.next = &context->netid;
                    229:     }
                    230: 
                    231:   if (!iface_enumerate(AF_INET6, &parm, add_prefixes) ||
                    232:       !parm.found_context)
                    233:     return;
                    234: 
                    235:   strncpy(ifr.ifr_name, iface_name, IF_NAMESIZE);
                    236: 
                    237: #ifdef HAVE_LINUX_NETWORK
                    238:   /* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
                    239:      available from SIOCGIFMTU */
                    240:   sprintf(daemon->namebuff, "/proc/sys/net/ipv6/conf/%s/mtu", iface_name);
                    241:   if ((f = fopen(daemon->namebuff, "r")))
                    242:     {
                    243:       if (fgets(daemon->namebuff, MAXDNAME, f))
                    244:        {
                    245:          put_opt6_char(ICMP6_OPT_MTU);
                    246:          put_opt6_char(1);
                    247:          put_opt6_short(0);
                    248:          put_opt6_long(atoi(daemon->namebuff));
                    249:        }
                    250:       fclose(f);
                    251:     }
                    252: #endif
                    253:      
                    254:   iface_enumerate(AF_LOCAL, &iface, add_lla);
                    255:  
                    256:   /* RDNSS, RFC 6106, use relevant DHCP6 options */
                    257:   (void)option_filter(parm.tags, NULL, daemon->dhcp_opts6);
                    258:   
                    259:   for (opt_cfg = daemon->dhcp_opts6; opt_cfg; opt_cfg = opt_cfg->next)
                    260:     {
                    261:       int i;
                    262:       
                    263:       /* netids match and not encapsulated? */
                    264:       if (!(opt_cfg->flags & DHOPT_TAGOK))
                    265:         continue;
                    266:       
                    267:       if (opt_cfg->opt == OPTION6_DNS_SERVER)
                    268:         {
                    269:          struct in6_addr *a = (struct in6_addr *)opt_cfg->val;
                    270: 
                    271:          done_dns = 1;
                    272:           if (opt_cfg->len == 0)
                    273:             continue;
                    274:          
                    275:          put_opt6_char(ICMP6_OPT_RDNSS);
                    276:          put_opt6_char((opt_cfg->len/8) + 1);
                    277:          put_opt6_short(0);
                    278:          put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
                    279:          /* zero means "self" */
                    280:          for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
                    281:            if (IN6_IS_ADDR_UNSPECIFIED(a))
                    282:              put_opt6(&parm.link_global, IN6ADDRSZ);
                    283:            else
                    284:              put_opt6(a, IN6ADDRSZ);
                    285:        }
                    286:       
                    287:       if (opt_cfg->opt == OPTION6_DOMAIN_SEARCH && opt_cfg->len != 0)
                    288:        {
                    289:          int len = ((opt_cfg->len+7)/8);
                    290:          
                    291:          put_opt6_char(ICMP6_OPT_DNSSL);
                    292:          put_opt6_char(len + 1);
                    293:          put_opt6_short(0);
                    294:          put_opt6_long(1800); /* lifetime - twice RA retransmit */
                    295:          put_opt6(opt_cfg->val, opt_cfg->len);
                    296:          
                    297:          /* pad */
                    298:          for (i = opt_cfg->len; i < len * 8; i++)
                    299:            put_opt6_char(0);
                    300:        }
                    301:     }
                    302:        
                    303:   if (!done_dns)
                    304:     {
                    305:       /* default == us. */
                    306:       put_opt6_char(ICMP6_OPT_RDNSS);
                    307:       put_opt6_char(3);
                    308:       put_opt6_short(0);
                    309:       put_opt6_long(RA_INTERVAL * 2); /* lifetime - twice RA retransmit */
                    310:       put_opt6(&parm.link_global, IN6ADDRSZ);
                    311:     }
                    312: 
                    313:   /* set managed bits unless we're providing only RA on this link */
                    314:   if (parm.managed)
                    315:     ra->flags |= 0x80; /* M flag, managed, */
                    316:    if (parm.other)
                    317:     ra->flags |= 0x40; /* O flag, other */ 
                    318:                        
                    319:   /* decide where we're sending */
                    320:   memset(&addr, 0, sizeof(addr));
                    321: #ifdef HAVE_SOCKADDR_SA_LEN
                    322:   addr.sin6_len = sizeof(struct sockaddr_in6);
                    323: #endif
                    324:   addr.sin6_family = AF_INET6;
                    325:   addr.sin6_port = htons(IPPROTO_ICMPV6);
                    326:   if (dest)
                    327:     {
                    328:       addr.sin6_addr = *dest;
                    329:       if (IN6_IS_ADDR_LINKLOCAL(dest) ||
                    330:          IN6_IS_ADDR_MC_LINKLOCAL(dest))
                    331:        addr.sin6_scope_id = iface;
                    332:     }
                    333:   else
                    334:     inet_pton(AF_INET6, ALL_NODES, &addr.sin6_addr); 
                    335:   
                    336:   send_from(daemon->icmp6fd, 0, daemon->outpacket.iov_base, save_counter(0),
                    337:            (union mysockaddr *)&addr, (struct all_addr *)&parm.link_local, iface); 
                    338:   
                    339: }
                    340: 
                    341: static int add_prefixes(struct in6_addr *local,  int prefix,
                    342:                        int scope, int if_index, int flags, 
                    343:                        unsigned int preferred, unsigned int valid, void *vparam)
                    344: {
                    345:   struct ra_param *param = vparam;
                    346: 
                    347:   (void)scope; /* warning */
                    348:   
                    349:   if (if_index == param->ind)
                    350:     {
                    351:       if (IN6_IS_ADDR_LINKLOCAL(local))
                    352:        param->link_local = *local;
                    353:       else if (!IN6_IS_ADDR_LOOPBACK(local) &&
                    354:               !IN6_IS_ADDR_MULTICAST(local))
                    355:        {
                    356:          int do_prefix = 0;
                    357:          int do_slaac = 0;
                    358:          int deprecate  = 0;
                    359:          int constructed = 0;
                    360:          unsigned int time = 0xffffffff;
                    361:          struct dhcp_context *context;
                    362:          
                    363:          for (context = daemon->dhcp6; context; context = context->next)
                    364:            if (!(context->flags & CONTEXT_TEMPLATE) &&
                    365:                prefix == context->prefix &&
                    366:                is_same_net6(local, &context->start6, prefix) &&
                    367:                is_same_net6(local, &context->end6, prefix))
                    368:              {
                    369:                if ((context->flags & 
                    370:                     (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
                    371:                  {
                    372:                    do_slaac = 1;
                    373:                    if (context->flags & CONTEXT_DHCP)
                    374:                      {
                    375:                        param->other = 1; 
                    376:                        if (!(context->flags & CONTEXT_RA_STATELESS))
                    377:                          param->managed = 1;
                    378:                      }
                    379:                  }
                    380:                else
                    381:                  {
                    382:                    /* don't do RA for non-ra-only unless --enable-ra is set */
                    383:                    if (!option_bool(OPT_RA))
                    384:                      continue;
                    385:                    param->managed = 1;
                    386:                    param->other = 1;
                    387:                  }
                    388:                
                    389:                /* find floor time, don't reduce below RA interval. */
                    390:                if (time > context->lease_time)
                    391:                  {
                    392:                    time = context->lease_time;
                    393:                    if (time < ((unsigned int)RA_INTERVAL))
                    394:                      time = RA_INTERVAL;
                    395:                  }
                    396: 
                    397:                if (context->flags & CONTEXT_DEPRECATE)
                    398:                  deprecate = 1;
                    399:                
                    400:                if (context->flags & CONTEXT_CONSTRUCTED)
                    401:                  constructed = 1;
                    402: 
                    403: 
                    404:                /* collect dhcp-range tags */
                    405:                if (context->netid.next == &context->netid && context->netid.net)
                    406:                  {
                    407:                    context->netid.next = param->tags;
                    408:                    param->tags = &context->netid;
                    409:                  }
                    410:                  
                    411:                /* subsequent prefixes on the same interface 
                    412:                   and subsequent instances of this prefix don't need timers.
                    413:                   Be careful not to find the same prefix twice with different
                    414:                   addresses. */
                    415:                if (!(context->flags & CONTEXT_RA_DONE))
                    416:                  {
                    417:                    if (!param->first)
                    418:                      context->ra_time = 0;
                    419:                    context->flags |= CONTEXT_RA_DONE;
                    420:                    do_prefix = 1;
                    421:                  }
                    422: 
                    423:                param->first = 0;       
                    424:                param->found_context = 1;
                    425:              }
                    426: 
                    427:          /* configured time is ceiling */
                    428:          if (!constructed || valid > time)
                    429:            valid = time;
                    430:          
                    431:          if (flags & IFACE_DEPRECATED)
                    432:            preferred = 0;
                    433:          
                    434:          if (deprecate)
                    435:            time = 0;
                    436:          
                    437:          /* configured time is ceiling */
                    438:          if (!constructed || preferred > time)
                    439:            preferred = time;
                    440:                  
                    441:          if (preferred > param->pref_time)
                    442:            {
                    443:              param->pref_time = preferred;
                    444:              param->link_global = *local;
                    445:            }
                    446:          
                    447:          if (do_prefix)
                    448:            {
                    449:              struct prefix_opt *opt;
                    450:                      
                    451:              if ((opt = expand(sizeof(struct prefix_opt))))
                    452:                {
                    453:                  /* zero net part of address */
                    454:                  setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU));
                    455:                  
                    456:                  opt->type = ICMP6_OPT_PREFIX;
                    457:                  opt->len = 4;
                    458:                  opt->prefix_len = prefix;
                    459:                  /* autonomous only if we're not doing dhcp, always set "on-link" */
                    460:                  opt->flags = do_slaac ? 0xC0 : 0x80;
                    461:                  opt->valid_lifetime = htonl(valid);
                    462:                  opt->preferred_lifetime = htonl(preferred);
                    463:                  opt->reserved = 0; 
                    464:                  opt->prefix = *local;
                    465:                  
                    466:                  inet_ntop(AF_INET6, local, daemon->addrbuff, ADDRSTRLEN);
                    467:                  my_syslog(MS_DHCP | LOG_INFO, "RTR-ADVERT(%s) %s", param->if_name, daemon->addrbuff);                     
                    468:                }
                    469:            }
                    470:        }
                    471:     }          
                    472:   return 1;
                    473: }
                    474: 
                    475: static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm)
                    476: {
                    477:   (void)type;
                    478: 
                    479:   if (index == *((int *)parm))
                    480:     {
                    481:       /* size is in units of 8 octets and includes type and length (2 bytes)
                    482:         add 7 to round up */
                    483:       int len = (maclen + 9) >> 3;
                    484:       unsigned char *p = expand(len << 3);
                    485:       memset(p, 0, len << 3);
                    486:       *p++ = ICMP6_OPT_SOURCE_MAC;
                    487:       *p++ = len;
                    488:       memcpy(p, mac, maclen);
                    489: 
                    490:       return 0;
                    491:     }
                    492: 
                    493:   return 1;
                    494: }
                    495: 
                    496: time_t periodic_ra(time_t now)
                    497: {
                    498:   struct search_param param;
                    499:   struct dhcp_context *context;
                    500:   time_t next_event;
                    501:   char interface[IF_NAMESIZE+1];
                    502:   
                    503:   param.now = now;
                    504:   param.iface = 0;
                    505: 
                    506:   while (1)
                    507:     {
                    508:       /* find overdue events, and time of first future event */
                    509:       for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
                    510:        if (context->ra_time != 0)
                    511:          {
                    512:            if (difftime(context->ra_time, now) <= 0.0)
                    513:              break; /* overdue */
                    514:            
                    515:            if (next_event == 0 || difftime(next_event, context->ra_time) > 0.0)
                    516:              next_event = context->ra_time;
                    517:          }
                    518:       
                    519:       /* none overdue */
                    520:       if (!context)
                    521:        break;
                    522:       
                    523:       /* There's a context overdue, but we can't find an interface
                    524:         associated with it, because it's for a subnet we dont 
                    525:         have an interface on. Probably we're doing DHCP on
                    526:         a remote subnet via a relay. Zero the timer, since we won't
                    527:         ever be able to send ra's and satistfy it. */
                    528:       if (iface_enumerate(AF_INET6, &param, iface_search))
                    529:        context->ra_time = 0;
                    530:       else if (param.iface != 0 &&
                    531:               indextoname(daemon->icmp6fd, param.iface, interface) &&
                    532:               iface_check(AF_LOCAL, NULL, interface, NULL))
                    533:        {
                    534:          struct iname *tmp;
                    535:          for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
                    536:            if (tmp->name && wildcard_match(tmp->name, interface))
                    537:              break;
                    538:          if (!tmp)
                    539:            send_ra(now, param.iface, interface, NULL); 
                    540:        }
                    541:     }      
                    542:   return next_event;
                    543: }
                    544:   
                    545: static int iface_search(struct in6_addr *local,  int prefix,
                    546:                        int scope, int if_index, int flags, 
                    547:                        int preferred, int valid, void *vparam)
                    548: {
                    549:   struct search_param *param = vparam;
                    550:   struct dhcp_context *context;
                    551: 
                    552:   (void)scope;
                    553:   (void)preferred;
                    554:   (void)valid;
                    555:  
                    556:   for (context = daemon->dhcp6; context; context = context->next)
                    557:     if (!(context->flags & CONTEXT_TEMPLATE) &&
                    558:        prefix == context->prefix &&
                    559:        is_same_net6(local, &context->start6, prefix) &&
                    560:        is_same_net6(local, &context->end6, prefix) &&
                    561:        context->ra_time != 0 && 
                    562:        difftime(context->ra_time, param->now) <= 0.0)
                    563:       {
                    564:        /* found an interface that's overdue for RA determine new 
                    565:           timeout value and arrange for RA to be sent unless interface is
                    566:           still doing DAD.*/
                    567:        
                    568:        if (!(flags & IFACE_TENTATIVE))
                    569:          param->iface = if_index;
                    570:        
                    571:        if (difftime(param->now, context->ra_short_period_start) < 60.0)
                    572:          /* range 5 - 20 */
                    573:          context->ra_time = param->now + 5 + (rand16()/4400);
                    574:        else
                    575:          /* range 3/4 - 1 times RA_INTERVAL */
                    576:          context->ra_time = param->now + (3 * RA_INTERVAL)/4 + ((RA_INTERVAL * (unsigned int)rand16()) >> 18);
                    577:        
                    578:        /* zero timers for other contexts on the same subnet, so they don't timeout 
                    579:           independently */
                    580:        for (context = context->next; context; context = context->next)
                    581:          if (prefix == context->prefix &&
                    582:              is_same_net6(local, &context->start6, prefix) &&
                    583:              is_same_net6(local, &context->end6, prefix))
                    584:            context->ra_time = 0;
                    585:        
                    586:        return 0; /* found, abort */
                    587:       }
                    588:   
                    589:   return 1; /* keep searching */
                    590: }
                    591: 
                    592: 
                    593: #endif

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