diff options
Diffstat (limited to 'package/network/services/dnsmasq/patches/0046-Add-shared-network-DHCP-configuration.patch')
-rw-r--r-- | package/network/services/dnsmasq/patches/0046-Add-shared-network-DHCP-configuration.patch | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/package/network/services/dnsmasq/patches/0046-Add-shared-network-DHCP-configuration.patch b/package/network/services/dnsmasq/patches/0046-Add-shared-network-DHCP-configuration.patch new file mode 100644 index 0000000000..637a027f6b --- /dev/null +++ b/package/network/services/dnsmasq/patches/0046-Add-shared-network-DHCP-configuration.patch @@ -0,0 +1,626 @@ +From ae5b7e04a1025167f1b80840e61432a3cea9625c Mon Sep 17 00:00:00 2001 +From: Simon Kelley <simon@thekelleys.org.uk> +Date: Wed, 27 Mar 2019 22:33:28 +0000 +Subject: [PATCH 46/57] Add --shared-network DHCP configuration. + +Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> +--- + CHANGELOG | 5 ++ + man/dnsmasq.8 | 21 ++++++ + src/dhcp.c | 76 ++++++++++++++++++---- + src/dhcp6.c | 175 ++++++++++++++++++++++++++++---------------------- + src/dnsmasq.h | 11 ++++ + src/option.c | 41 ++++++++++++ + src/rfc2131.c | 97 +++++++++++++++++----------- + src/rfc3315.c | 40 +++++++++--- + 8 files changed, 332 insertions(+), 134 deletions(-) + +--- a/CHANGELOG ++++ b/CHANGELOG +@@ -34,6 +34,11 @@ version 2.81 + tries not to request capabilities not required by its + configuration. + ++ Add --shared-network config. This enables allocation of addresses ++ the DHCP server in subnets where the server (or relay) doesn't ++ have an interface on the network in that subnet. Many thanks to ++ plank.de for sponsoring this feature. ++ + + version 2.80 + Add support for RFC 4039 DHCP rapid commit. Thanks to Ashram Method +--- a/man/dnsmasq.8 ++++ b/man/dnsmasq.8 +@@ -1741,6 +1741,27 @@ It is permissible to add more than one a + \fB--bridge-interface=int1,alias1,alias2\fP is exactly equivalent to + \fB--bridge-interface=int1,alias1 --bridge-interface=int1,alias2\fP + .TP ++.B --shared-network=<interface>|<addr>,<addr> ++The DHCP server determines which dhcp ranges are useable for allocating and ++address to a DHCP client based on the network from which the DHCP request arrives, ++and the IP configuration of the server's interface on that network. The shared-network ++option extends the available subnets (and therefore dhcp ranges) beyond the ++subnets configured on the arrival interface. The first argument is either the ++name of an interface or an address which is configured on a local interface, and the ++second argument is an address which defines another subnet on which addresses can be allocated. ++To be useful, there must be suitable dhcp-range which allows address allocation on this subnet ++and this dhcp-range MUST include the netmask. Use shared-network also needs extra ++consideration of routing. Dnsmasq doesn't have the usual information which it uses to ++determine the default route, so the default route option (or other routing) MUST be ++manually configured. The client must have a route to the server: if the two-address form ++of shared-network is used, this will be to the first specified address. If the interface,address ++form is used, there must be a route to all of the addresses configured on the interface. ++ ++The two-address form of shared-network is also usable with a DHCP relay: the first address ++is the address of the relay and the second, as before, specifies an extra subnet which ++may be allocated. ++ ++.TP + .B \-s, --domain=<domain>[,<address range>[,local]] + Specifies DNS domains for the DHCP server. Domains may be be given + unconditionally (without the IP range) or for limited IP ranges. This has two effects; +--- a/src/dhcp.c ++++ b/src/dhcp.c +@@ -507,33 +507,83 @@ static int check_listen_addrs(struct in_ + + Note that the current chain may be superseded later for configured hosts or those coming via gateways. */ + +-static int complete_context(struct in_addr local, int if_index, char *label, +- struct in_addr netmask, struct in_addr broadcast, void *vparam) ++static void guess_range_netmask(struct in_addr addr, struct in_addr netmask) + { + struct dhcp_context *context; +- struct dhcp_relay *relay; +- struct iface_param *param = vparam; + +- (void)label; +- + for (context = daemon->dhcp; context; context = context->next) +- { +- if (!(context->flags & CONTEXT_NETMASK) && +- (is_same_net(local, context->start, netmask) || +- is_same_net(local, context->end, netmask))) ++ if (!(context->flags & CONTEXT_NETMASK) && ++ (is_same_net(addr, context->start, netmask) || ++ is_same_net(addr, context->end, netmask))) + { + if (context->netmask.s_addr != netmask.s_addr && +- !(is_same_net(local, context->start, netmask) && +- is_same_net(local, context->end, netmask))) ++ !(is_same_net(addr, context->start, netmask) && ++ is_same_net(addr, context->end, netmask))) + { + strcpy(daemon->dhcp_buff, inet_ntoa(context->start)); + strcpy(daemon->dhcp_buff2, inet_ntoa(context->end)); + my_syslog(MS_DHCP | LOG_WARNING, _("DHCP range %s -- %s is not consistent with netmask %s"), + daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(netmask)); + } +- context->netmask = netmask; ++ context->netmask = netmask; + } ++} ++ ++static int complete_context(struct in_addr local, int if_index, char *label, ++ struct in_addr netmask, struct in_addr broadcast, void *vparam) ++{ ++ struct dhcp_context *context; ++ struct dhcp_relay *relay; ++ struct iface_param *param = vparam; ++ struct shared_network *share; ++ ++ (void)label; ++ ++ for (share = daemon->shared_networks; share; share = share->next) ++ { + ++#ifdef HAVE_DHCP6 ++ if (share->shared_addr.s_addr == 0) ++ continue; ++#endif ++ ++ if (share->if_index != 0) ++ { ++ if (share->if_index != if_index) ++ continue; ++ } ++ else ++ { ++ if (share->match_addr.s_addr != local.s_addr) ++ continue; ++ } ++ ++ for (context = daemon->dhcp; context; context = context->next) ++ { ++ if (context->netmask.s_addr != 0 && ++ is_same_net(share->shared_addr, context->start, context->netmask) && ++ is_same_net(share->shared_addr, context->end, context->netmask)) ++ { ++ /* link it onto the current chain if we've not seen it before */ ++ if (context->current == context) ++ { ++ /* For a shared network, we have no way to guess what the default route should be. */ ++ context->router.s_addr = 0; ++ context->local = local; /* Use configured address for Server Identifier */ ++ context->current = param->current; ++ param->current = context; ++ } ++ ++ if (!(context->flags & CONTEXT_BRDCAST)) ++ context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr; ++ } ++ } ++ } ++ ++ guess_range_netmask(local, netmask); ++ ++ for (context = daemon->dhcp; context; context = context->next) ++ { + if (context->netmask.s_addr != 0 && + is_same_net(local, context->start, context->netmask) && + is_same_net(local, context->end, context->netmask)) +--- a/src/dhcp6.c ++++ b/src/dhcp6.c +@@ -299,89 +299,114 @@ static int complete_context6(struct in6_ + unsigned int valid, void *vparam) + { + struct dhcp_context *context; ++ struct shared_network *share; + struct dhcp_relay *relay; + struct iface_param *param = vparam; + struct iname *tmp; + + (void)scope; /* warning */ + +- if (if_index == param->ind) +- { +- if (IN6_IS_ADDR_LINKLOCAL(local)) +- param->ll_addr = *local; +- else if (IN6_IS_ADDR_ULA(local)) +- param->ula_addr = *local; +- +- if (!IN6_IS_ADDR_LOOPBACK(local) && +- !IN6_IS_ADDR_LINKLOCAL(local) && +- !IN6_IS_ADDR_MULTICAST(local)) +- { +- /* if we have --listen-address config, see if the +- arrival interface has a matching address. */ +- for (tmp = daemon->if_addrs; tmp; tmp = tmp->next) +- if (tmp->addr.sa.sa_family == AF_INET6 && +- 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)) && +- prefix <= context->prefix && +- is_same_net6(local, &context->start6, context->prefix) && +- is_same_net6(local, &context->end6, context->prefix)) +- { +- +- +- /* link it onto the current chain if we've not seen it before */ +- if (context->current == context) +- { +- struct dhcp_context *tmp, **up; +- +- /* use interface values only for constructed 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; +- 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.addr6) && relay->current == relay && +- (IN6_IS_ADDR_UNSPECIFIED(¶m->relay_local) || IN6_ARE_ADDR_EQUAL(local, ¶m->relay_local))) ++ if (if_index != param->ind) ++ return 1; ++ ++ if (IN6_IS_ADDR_LINKLOCAL(local)) ++ param->ll_addr = *local; ++ else if (IN6_IS_ADDR_ULA(local)) ++ param->ula_addr = *local; ++ ++ if (IN6_IS_ADDR_LOOPBACK(local) || ++ IN6_IS_ADDR_LINKLOCAL(local) || ++ IN6_IS_ADDR_MULTICAST(local)) ++ return 1; ++ ++ /* if we have --listen-address config, see if the ++ arrival interface has a matching address. */ ++ for (tmp = daemon->if_addrs; tmp; tmp = tmp->next) ++ if (tmp->addr.sa.sa_family == AF_INET6 && ++ 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)) && ++ prefix <= context->prefix && ++ context->current == context) ++ { ++ if (is_same_net6(local, &context->start6, context->prefix) && ++ is_same_net6(local, &context->end6, context->prefix)) + { +- relay->current = param->relay; +- param->relay = relay; +- param->relay_local = *local; ++ struct dhcp_context *tmp, **up; ++ ++ /* use interface values only for constructed 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; ++ else ++ up = &tmp->current; ++ ++ context->current = *up; ++ *up = context; ++ context->local6 = *local; ++ context->preferred = preferred; ++ context->valid = valid; + } +- +- } +- +- return 1; ++ else ++ { ++ for (share = daemon->shared_networks; share; share = share->next) ++ { ++ /* IPv4 shared_address - ignore */ ++ if (share->shared_addr.s_addr != 0) ++ continue; ++ ++ if (share->if_index != 0) ++ { ++ if (share->if_index != if_index) ++ continue; ++ } ++ else ++ { ++ if (!IN6_ARE_ADDR_EQUAL(&share->match_addr6, local)) ++ continue; ++ } ++ ++ if (is_same_net6(&share->shared_addr6, &context->start6, context->prefix) && ++ is_same_net6(&share->shared_addr6, &context->end6, context->prefix)) ++ { ++ context->current = param->current; ++ param->current = context; ++ context->local6 = *local; ++ context->preferred = context->flags & CONTEXT_DEPRECATE ? 0 :0xffffffff; ++ context->valid = 0xffffffff; ++ } ++ } ++ } ++ } ++ ++ for (relay = daemon->relay6; relay; relay = relay->next) ++ if (IN6_ARE_ADDR_EQUAL(local, &relay->local.addr6) && relay->current == relay && ++ (IN6_IS_ADDR_UNSPECIFIED(¶m->relay_local) || IN6_ARE_ADDR_EQUAL(local, ¶m->relay_local))) ++ { ++ relay->current = param->relay; ++ param->relay = relay; ++ param->relay_local = *local; ++ } ++ ++ return 1; + } + + struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net, int prefix, u64 addr) +--- a/src/dnsmasq.h ++++ b/src/dnsmasq.h +@@ -910,6 +910,16 @@ struct dhcp_context { + struct dhcp_context *next, *current; + }; + ++struct shared_network { ++ int if_index; ++ struct in_addr match_addr, shared_addr; ++#ifdef HAVE_DHCP6 ++ /* shared_addr == 0 for IP6 entries. */ ++ struct in6_addr match_addr6, shared_addr6; ++#endif ++ struct shared_network *next; ++}; ++ + #define CONTEXT_STATIC (1u<<0) + #define CONTEXT_NETMASK (1u<<1) + #define CONTEXT_BRDCAST (1u<<2) +@@ -1107,6 +1117,7 @@ extern struct daemon { + struct ping_result *ping_results; + FILE *lease_stream; + struct dhcp_bridge *bridges; ++ struct shared_network *shared_networks; + #ifdef HAVE_DHCP6 + int duid_len; + unsigned char *duid; +--- a/src/option.c ++++ b/src/option.c +@@ -166,6 +166,7 @@ struct myoption { + #define LOPT_UBUS 354 + #define LOPT_NAME_MATCH 355 + #define LOPT_CAA 356 ++#define LOPT_SHARED_NET 357 + + #ifdef HAVE_GETOPT_LONG + static const struct option opts[] = +@@ -259,6 +260,7 @@ static const struct myoption opts[] = + { "ptr-record", 1, 0, LOPT_PTR }, + { "naptr-record", 1, 0, LOPT_NAPTR }, + { "bridge-interface", 1, 0 , LOPT_BRIDGE }, ++ { "shared-network", 1, 0, LOPT_SHARED_NET }, + { "dhcp-option-force", 1, 0, LOPT_FORCE }, + { "tftp-no-blocksize", 0, 0, LOPT_NOBLOCK }, + { "log-dhcp", 0, 0, LOPT_LOG_OPTS }, +@@ -431,6 +433,7 @@ static struct { + { '3', ARG_DUP, "[=tag:<tag>]...", gettext_noop("Enable dynamic address allocation for bootp."), NULL }, + { '4', ARG_DUP, "set:<tag>,<mac address>", gettext_noop("Map MAC address (with wildcards) to option set."), NULL }, + { LOPT_BRIDGE, ARG_DUP, "<iface>,<alias>..", gettext_noop("Treat DHCP requests on aliases as arriving from interface."), NULL }, ++ { LOPT_SHARED_NET, ARG_DUP, "<iface>|<addr>,<addr>", gettext_noop("Specify extra networks sharing a broadcast domain for DHCP"), NULL}, + { '5', OPT_NO_PING, NULL, gettext_noop("Disable ICMP echo address checking in the DHCP server."), NULL }, + { '6', ARG_ONE, "<path>", gettext_noop("Shell script to run on DHCP lease creation and destruction."), NULL }, + { LOPT_LUASCRIPT, ARG_DUP, "path", gettext_noop("Lua script to run on DHCP lease creation and destruction."), NULL }, +@@ -2873,6 +2876,44 @@ static int one_opt(int option, char *arg + } + + #ifdef HAVE_DHCP ++ case LOPT_SHARED_NET: /* --shared-network */ ++ { ++ struct shared_network *new = opt_malloc(sizeof(struct shared_network)); ++ ++#ifdef HAVE_DHCP6 ++ new->shared_addr.s_addr = 0; ++#endif ++ new->if_index = 0; ++ ++ if (!(comma = split(arg))) ++ { ++ snerr: ++ free(new); ++ ret_err(_("bad shared-network")); ++ } ++ ++ if (inet_pton(AF_INET, comma, &new->shared_addr)) ++ { ++ if (!inet_pton(AF_INET, arg, &new->match_addr) && ++ !(new->if_index = if_nametoindex(arg))) ++ goto snerr; ++ } ++#ifdef HAVE_DHCP6 ++ else if (inet_pton(AF_INET6, comma, &new->shared_addr6)) ++ { ++ if (!inet_pton(AF_INET6, arg, &new->match_addr6) && ++ !(new->if_index = if_nametoindex(arg))) ++ goto snerr; ++ } ++#endif ++ else ++ goto snerr; ++ ++ new->next = daemon->shared_networks; ++ daemon->shared_networks = new; ++ break; ++ } ++ + case 'F': /* --dhcp-range */ + { + int k, leasepos = 2; +--- a/src/rfc2131.c ++++ b/src/rfc2131.c +@@ -274,8 +274,9 @@ size_t dhcp_reply(struct dhcp_context *c + if (mess->giaddr.s_addr || subnet_addr.s_addr || mess->ciaddr.s_addr) + { + struct dhcp_context *context_tmp, *context_new = NULL; ++ struct shared_network *share = NULL; + struct in_addr addr; +- int force = 0; ++ int force = 0, via_relay = 0; + + if (subnet_addr.s_addr) + { +@@ -286,6 +287,7 @@ size_t dhcp_reply(struct dhcp_context *c + { + addr = mess->giaddr; + force = 1; ++ via_relay = 1; + } + else + { +@@ -302,42 +304,65 @@ size_t dhcp_reply(struct dhcp_context *c + } + + if (!context_new) +- for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next) +- { +- struct in_addr netmask = context_tmp->netmask; ++ { ++ for (context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next) ++ { ++ struct in_addr netmask = context_tmp->netmask; ++ ++ /* guess the netmask for relayed networks */ ++ if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0) ++ { ++ if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr))) ++ netmask.s_addr = htonl(0xff000000); ++ else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr))) ++ netmask.s_addr = htonl(0xffff0000); ++ else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr))) ++ netmask.s_addr = htonl(0xffffff00); ++ } + +- /* guess the netmask for relayed networks */ +- if (!(context_tmp->flags & CONTEXT_NETMASK) && context_tmp->netmask.s_addr == 0) +- { +- if (IN_CLASSA(ntohl(context_tmp->start.s_addr)) && IN_CLASSA(ntohl(context_tmp->end.s_addr))) +- netmask.s_addr = htonl(0xff000000); +- else if (IN_CLASSB(ntohl(context_tmp->start.s_addr)) && IN_CLASSB(ntohl(context_tmp->end.s_addr))) +- netmask.s_addr = htonl(0xffff0000); +- else if (IN_CLASSC(ntohl(context_tmp->start.s_addr)) && IN_CLASSC(ntohl(context_tmp->end.s_addr))) +- netmask.s_addr = htonl(0xffffff00); +- } +- +- /* This section fills in context mainly when a client which is on a remote (relayed) +- network renews a lease without using the relay, after dnsmasq has restarted. */ +- if (netmask.s_addr != 0 && +- is_same_net(addr, context_tmp->start, netmask) && +- is_same_net(addr, context_tmp->end, netmask)) +- { +- context_tmp->netmask = netmask; +- if (context_tmp->local.s_addr == 0) +- context_tmp->local = fallback; +- if (context_tmp->router.s_addr == 0) +- context_tmp->router = mess->giaddr; +- +- /* fill in missing broadcast addresses for relayed ranges */ +- if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 ) +- context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr; +- +- context_tmp->current = context_new; +- context_new = context_tmp; +- } +- } +- ++ /* check to see is a context is OK because of a shared address on ++ the relayed subnet. */ ++ if (via_relay) ++ for (share = daemon->shared_networks; share; share = share->next) ++ { ++#ifdef HAVE_DHCP6 ++ if (share->shared_addr.s_addr == 0) ++ continue; ++#endif ++ if (share->if_index != 0 || ++ share->match_addr.s_addr != mess->giaddr.s_addr) ++ continue; ++ ++ if (netmask.s_addr != 0 && ++ is_same_net(share->shared_addr, context_tmp->start, netmask) && ++ is_same_net(share->shared_addr, context_tmp->end, netmask)) ++ break; ++ } ++ ++ /* This section fills in context mainly when a client which is on a remote (relayed) ++ network renews a lease without using the relay, after dnsmasq has restarted. */ ++ if (share || ++ (netmask.s_addr != 0 && ++ is_same_net(addr, context_tmp->start, netmask) && ++ is_same_net(addr, context_tmp->end, netmask))) ++ { ++ context_tmp->netmask = netmask; ++ if (context_tmp->local.s_addr == 0) ++ context_tmp->local = fallback; ++ if (context_tmp->router.s_addr == 0 && !share) ++ context_tmp->router = mess->giaddr; ++ ++ /* fill in missing broadcast addresses for relayed ranges */ ++ if (!(context_tmp->flags & CONTEXT_BRDCAST) && context_tmp->broadcast.s_addr == 0 ) ++ context_tmp->broadcast.s_addr = context_tmp->start.s_addr | ~context_tmp->netmask.s_addr; ++ ++ context_tmp->current = context_new; ++ context_new = context_tmp; ++ } ++ ++ } ++ } ++ + if (context_new || force) + context = context_new; + } +--- a/src/rfc3315.c ++++ b/src/rfc3315.c +@@ -134,21 +134,41 @@ static int dhcp6_maybe_relay(struct stat + else + { + struct dhcp_context *c; ++ struct shared_network *share = NULL; + state->context = NULL; +- ++ + if (!IN6_IS_ADDR_LOOPBACK(state->link_address) && + !IN6_IS_ADDR_LINKLOCAL(state->link_address) && + !IN6_IS_ADDR_MULTICAST(state->link_address)) + for (c = daemon->dhcp6; c; c = c->next) +- if ((c->flags & CONTEXT_DHCP) && +- !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && +- is_same_net6(state->link_address, &c->start6, c->prefix) && +- is_same_net6(state->link_address, &c->end6, c->prefix)) +- { +- c->preferred = c->valid = 0xffffffff; +- c->current = state->context; +- state->context = c; +- } ++ { ++ for (share = daemon->shared_networks; share; share = share->next) ++ { ++ if (share->shared_addr.s_addr != 0) ++ continue; ++ ++ if (share->if_index != 0 || ++ !IN6_ARE_ADDR_EQUAL(state->link_address, &share->match_addr6)) ++ continue; ++ ++ if ((c->flags & CONTEXT_DHCP) && ++ !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && ++ is_same_net6(&share->shared_addr6, &c->start6, c->prefix) && ++ is_same_net6(&share->shared_addr6, &c->end6, c->prefix)) ++ break; ++ } ++ ++ if (share || ++ ((c->flags & CONTEXT_DHCP) && ++ !(c->flags & (CONTEXT_TEMPLATE | CONTEXT_OLD)) && ++ is_same_net6(state->link_address, &c->start6, c->prefix) && ++ is_same_net6(state->link_address, &c->end6, c->prefix))) ++ { ++ c->preferred = c->valid = 0xffffffff; ++ c->current = state->context; ++ state->context = c; ++ } ++ } + + if (!state->context) + { |