Add --shared-network DHCP configuration.
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 7e6e3df..5badc46 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -299,89 +299,114 @@
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)))
- {
- relay->current = param->relay;
- param->relay = relay;
- param->relay_local = *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;
- }
-
- return 1;
+ 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))
+ {
+ 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;
+ }
+ 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)