summaryrefslogtreecommitdiff
path: root/src/radv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/radv.c')
-rw-r--r--src/radv.c44
1 files changed, 35 insertions, 9 deletions
diff --git a/src/radv.c b/src/radv.c
index 84d4a3e..f5b517b 100644
--- a/src/radv.c
+++ b/src/radv.c
@@ -28,7 +28,7 @@
struct ra_param {
time_t now;
- int ind, managed, other, found_context, first;
+ int ind, managed, other, found_context, first, adv_router;
char *if_name;
struct dhcp_netid *tags;
struct in6_addr link_local, link_global, ula;
@@ -226,6 +226,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
parm.managed = 0;
parm.other = 0;
parm.found_context = 0;
+ parm.adv_router = 0;
parm.if_name = iface_name;
parm.first = 1;
parm.now = now;
@@ -286,8 +287,7 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
setaddr6part(&local, addr6part(&local) & ~((context->prefix == 64) ? (u64)-1LL : (1LLU << (128 - context->prefix)) - 1LLU));
- if ((context->flags &
- (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
+ if (context->flags & CONTEXT_RA)
{
do_slaac = 1;
if (context->flags & CONTEXT_DHCP)
@@ -339,6 +339,17 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
if (!old_prefix && !parm.found_context)
return;
+ /* If we're sending router address instead of prefix in at least on prefix,
+ include the advertisement interval option. */
+ if (parm.adv_router)
+ {
+ put_opt6_char(ICMP6_OPT_ADV_INTERVAL);
+ put_opt6_char(1);
+ put_opt6_short(0);
+ /* interval value is in milliseconds */
+ put_opt6_long(1000 * calc_interval(find_iface_param(iface_name)));
+ }
+
#ifdef HAVE_LINUX_NETWORK
/* Note that IPv6 MTU is not necessarilly the same as the IPv4 MTU
available from SIOCGIFMTU */
@@ -500,6 +511,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
int do_slaac = 0;
int deprecate = 0;
int constructed = 0;
+ int adv_router = 0;
unsigned int time = 0xffffffff;
struct dhcp_context *context;
@@ -511,8 +523,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
{
context->saved_valid = valid;
- if ((context->flags &
- (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
+ if (context->flags & CONTEXT_RA)
{
do_slaac = 1;
if (context->flags & CONTEXT_DHCP)
@@ -530,7 +541,17 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->managed = 1;
param->other = 1;
}
-
+
+ /* Configured to advertise router address, not prefix. See RFC 3775 7.2
+ In this case we do all addresses associated with a context,
+ hence the real_prefix setting here. */
+ if (context->flags & CONTEXT_RA_ROUTER)
+ {
+ adv_router = 1;
+ param->adv_router = 1;
+ real_prefix = context->prefix;
+ }
+
/* find floor time, don't reduce below 3 * RA interval. */
if (time > context->lease_time)
{
@@ -556,7 +577,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
/* subsequent prefixes on the same interface
and subsequent instances of this prefix don't need timers.
Be careful not to find the same prefix twice with different
- addresses. */
+ addresses unless we're advertising the actual addresses. */
if (!(context->flags & CONTEXT_RA_DONE))
{
if (!param->first)
@@ -607,13 +628,18 @@ static int add_prefixes(struct in6_addr *local, int prefix,
if ((opt = expand(sizeof(struct prefix_opt))))
{
/* zero net part of address */
- setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
+ if (!adv_router)
+ setaddr6part(local, addr6part(local) & ~((real_prefix == 64) ? (u64)-1LL : (1LLU << (128 - real_prefix)) - 1LLU));
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = real_prefix;
/* autonomous only if we're not doing dhcp, always set "on-link" */
- opt->flags = do_slaac ? 0xC0 : 0x80;
+ opt->flags = 0x80;
+ if (do_slaac)
+ opt->flags |= 0x40;
+ if (adv_router)
+ opt->flags |= 0x20;
opt->valid_lifetime = htonl(valid);
opt->preferred_lifetime = htonl(preferred);
opt->reserved = 0;