diff --git a/src/dhcp6.c b/src/dhcp6.c index 1428aa6..f708af5 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -26,7 +26,7 @@ struct iface_param { static int complete_context6(struct in6_addr *local, int prefix, int scope, int if_index, int flags, - int preferred, int valid, void *vparam); + unsigned int preferred, unsigned int valid, void *vparam); static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm); @@ -182,18 +182,15 @@ void dhcp6_packet(time_t now) } static int complete_context6(struct in6_addr *local, int prefix, - int scope, int if_index, int flags, int preferred, - int valid, void *vparam) + int scope, int if_index, int flags, unsigned int preferred, + unsigned int valid, void *vparam) { struct dhcp_context *context; struct iface_param *param = vparam; struct iname *tmp; (void)scope; /* warning */ - (void)flags; - (void)preferred; - (void)valid; - + if (if_index == param->ind && !IN6_IS_ADDR_LOOPBACK(local) && !IN6_IS_ADDR_LINKLOCAL(local) && @@ -219,12 +216,32 @@ static int complete_context6(struct in6_addr *local, int prefix, is_same_net6(local, &context->start6, prefix) && is_same_net6(local, &context->end6, prefix)) { + + /* link it onto the current chain if we've not seen it before */ if (context->current == context) { - context->current = param->current; - param->current = context; + 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 */ + for (up = ¶m->current, tmp = param->current; tmp; tmp = tmp->current) + if (tmp->preferred <= preferred) + break; + + context->current = *up; + *up = context; context->local6 = *local; + context->preferred = preferred; + context->valid = valid; } } } diff --git a/src/dnsmasq.h b/src/dnsmasq.h index be062f6..3181db6 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -683,6 +683,7 @@ struct dhcp_context { struct in6_addr start6, end6; /* range of available addresses */ struct in6_addr local6; int prefix, if_index; + unsigned int valid, preferred; time_t ra_time, ra_short_period_start; char *template_interface; #endif diff --git a/src/radv.c b/src/radv.c index c552c52..668d56f 100644 --- a/src/radv.c +++ b/src/radv.c @@ -344,6 +344,7 @@ static int add_prefixes(struct in6_addr *local, int prefix, int do_prefix = 0; int do_slaac = 0; int deprecate = 0; + int constructed = 0; unsigned int time = 0xffffffff; struct dhcp_context *context; @@ -383,6 +384,10 @@ static int add_prefixes(struct in6_addr *local, int prefix, if (context->flags & CONTEXT_DEPRECATE) deprecate = 1; + + if (context->flags & CONTEXT_CONSTRUCTED) + constructed = 1; + /* collect dhcp-range tags */ if (context->netid.next == &context->netid && context->netid.net) @@ -408,18 +413,19 @@ static int add_prefixes(struct in6_addr *local, int prefix, } /* configured time is ceiling */ - if (valid > time) + if (!constructed || valid > time) valid = time; - if ((flags & IFACE_DEPRECATED) || deprecate) + if (flags & IFACE_DEPRECATED) preferred = 0; - else - { - /* configured time is ceiling */ - if (preferred > time) - preferred = time; - } + if (deprecate) + time = 0; + + /* configured time is ceiling */ + if (!constructed || preferred > time) + preferred = time; + if (preferred > param->pref_time) { param->pref_time = preferred; diff --git a/src/rfc3315.c b/src/rfc3315.c index 8c3cae0..560fdc1 100644 --- a/src/rfc3315.c +++ b/src/rfc3315.c @@ -625,10 +625,16 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh hostname = NULL; } } + + if (have_config(valid_config, CONFIG_TIME)) + lease_time = valid_config->lease_time; + else + lease_time = this_context->lease_time; - lease_time = have_config(valid_config, CONFIG_TIME) ? valid_config->lease_time : this_context->lease_time; + if (this_context->valid < lease_time) + lease_time = this_context->valid; - if (ia_option) + if (ia_option) { if (requested_time < 120u ) requested_time = 120u; /* sanity */ @@ -740,7 +746,8 @@ static int dhcp6_no_relay(int msg_type, struct in6_addr *link_address, struct dh o1 = new_opt6(OPTION6_IAADDR); put_opt6(addrp, sizeof(*addrp)); /* preferred lifetime */ - put_opt6_long(this_context && (this_context->flags & CONTEXT_DEPRECATE) ? 0 : lease_time); + put_opt6_long(this_context && (this_context->preferred < lease_time) ? + this_context->preferred : lease_time); put_opt6_long(lease_time); /* valid lifetime */ end_opt6(o1);