summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2014-04-25 22:04:05 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2014-04-25 22:04:05 +0100
commit7ea3d3fdca34e026e3a0f83188733000fca3cf88 (patch)
tree26e811b03273d48dce518878494c481e9b7324e2
parent50f86ce8e42a1f93bb1fa759ebb883df96c5b078 (diff)
downloaddnsmasq-mobile-ra.tar.gz
ra-advrouter mode for RFC-3775 mobile IPv6 support.mobile-ra
-rw-r--r--CHANGELOG4
-rw-r--r--man/dnsmasq.87
-rw-r--r--src/dhcp6.c3
-rw-r--r--src/dnsmasq.h3
-rw-r--r--src/option.c6
-rw-r--r--src/radv-protocol.h1
-rw-r--r--src/radv.c44
7 files changed, 52 insertions, 16 deletions
diff --git a/CHANGELOG b/CHANGELOG
index e0d2fed..62019ff 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+version 2.71
+ Add ra-advrouter mode, for RFC-3775 mobile IPv6 support.
+
+
version 2.70
Fix crash, introduced in 2.69, on TCP request when dnsmasq
compiled with DNSSEC support, but running without DNSSEC
diff --git a/man/dnsmasq.8 b/man/dnsmasq.8
index 6658f16..f25119d 100644
--- a/man/dnsmasq.8
+++ b/man/dnsmasq.8
@@ -794,7 +794,7 @@ and
for details.)
For IPv6, the mode may be some combination of
-.B ra-only, slaac, ra-names, ra-stateless.
+.B ra-only, slaac, ra-names, ra-stateless, ra-advrouter.
.B ra-only
tells dnsmasq to offer Router Advertisement only on this subnet,
@@ -829,6 +829,11 @@ can be combined with
and
.B slaac.
+.B ra-advrouter
+enables a mode where router address(es) rather than prefix(es) are included in the advertisements.
+This is described in RFC-3775 section 7.2 and is used in mobile IPv6. In this mode the interval option
+is also included, as described in RFC-3775 section 7.3.
+
.TP
.B \-G, --dhcp-host=[<hwaddr>][,id:<client_id>|*][,set:<tag>][,<ipaddr>][,<hostname>][,<lease_time>][,ignore]
Specify per host parameters for the DHCP server. This allows a machine
diff --git a/src/dhcp6.c b/src/dhcp6.c
index 3a83c18..bc48fdd 100644
--- a/src/dhcp6.c
+++ b/src/dhcp6.c
@@ -727,8 +727,7 @@ void dhcp_construct_contexts(time_t now)
if (context->flags & CONTEXT_GC && !(context->flags & CONTEXT_OLD))
{
- if ((context->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) ||
- option_bool(OPT_RA))
+ if ((context->flags & CONTEXT_RA) || option_bool(OPT_RA))
{
/* previously constructed context has gone. advertise it's demise */
context->flags |= CONTEXT_OLD;
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index 3032546..e11fad4 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -823,7 +823,7 @@ struct dhcp_context {
#define CONTEXT_NETMASK (1u<<1)
#define CONTEXT_BRDCAST (1u<<2)
#define CONTEXT_PROXY (1u<<3)
-#define CONTEXT_RA_ONLY (1u<<4)
+#define CONTEXT_RA_ROUTER (1u<<4)
#define CONTEXT_RA_DONE (1u<<5)
#define CONTEXT_RA_NAME (1u<<6)
#define CONTEXT_RA_STATELESS (1u<<7)
@@ -838,7 +838,6 @@ struct dhcp_context {
#define CONTEXT_OLD (1u<<16)
#define CONTEXT_V6 (1u<<17)
-
struct ping_result {
struct in_addr addr;
time_t time;
diff --git a/src/option.c b/src/option.c
index daa728f..a0a6e46 100644
--- a/src/option.c
+++ b/src/option.c
@@ -2583,9 +2583,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (strcmp(a[leasepos], "static") == 0)
new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
- new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA;
+ new->flags |= CONTEXT_RA;
else if (strcmp(a[leasepos], "ra-names") == 0)
new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
+ else if (strcmp(a[leasepos], "ra-advrouter") == 0)
+ new->flags |= CONTEXT_RA_ROUTER | CONTEXT_RA;
else if (strcmp(a[leasepos], "ra-stateless") == 0)
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
@@ -2615,7 +2617,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (new->prefix != 64)
{
- if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
+ if (new->flags & CONTEXT_RA)
ret_err(_("prefix length must be exactly 64 for RA subnets"));
else if (new->flags & CONTEXT_TEMPLATE)
ret_err(_("prefix length must be exactly 64 for subnet constructors"));
diff --git a/src/radv-protocol.h b/src/radv-protocol.h
index 9e53d8e..e576012 100644
--- a/src/radv-protocol.h
+++ b/src/radv-protocol.h
@@ -49,6 +49,7 @@ struct prefix_opt {
#define ICMP6_OPT_SOURCE_MAC 1
#define ICMP6_OPT_PREFIX 3
#define ICMP6_OPT_MTU 5
+#define ICMP6_OPT_ADV_INTERVAL 7
#define ICMP6_OPT_RDNSS 25
#define ICMP6_OPT_DNSSL 31
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;