Hi all,
this patch series are my latest version for support 6CO in radvd.
Somebody wants to bring these patches into radvd upstream, see [0].
Nevertheless, I don't have any time to working on this currently so I want
to broadcast somehow my latest state. If there are no issues for radvd
maintainer, then this is great. :-)
Maybe somebody can also work on the ToDo's like C=0 handling at first and
then have some "mechanism" to switch to C=1.
How to setup:
Nodes which sends RA messages need to setup 6CO before.
This is the "lowpanco" field in the configuration.
All others nodes need to run radvd as well, but processing RA messages only.
To setup their 6CO fields, when receiving RA messages.
This can be done by a simple configuration with one entry for 6lowpan
interfaces with "AdvSendAdvert off;".
IMPORTANT NOTE:
This requires the patch which is not mainline yet, to set 6CO option fields
as userspace option. Otherwise the kernel will filter it. See [1]. As well,
you need the pending patches on the list for stateful compression, see [2].
- Alex
[0] https://github.com/reubenhwk/radvd/issues/50#issuecomment-183329181
[1] http://www.spinics.net/lists/linux-wpan/msg03364.html
[2] http://www.spinics.net/lists/linux-wpan/msg03453.html
Alexander Aring (2):
device-linux: replace ARPHRD_IEEE802154 to ARPHRD_6LOWPAN
radvd: rework 6CO handling
defaults.h | 3 ++
device-bsd44.c | 24 ++++++++++
device-linux.c | 43 +++++++++++++++--
gram.y | 72 ++++++++++++++++++++++------
pathnames.h | 4 ++
privsep-linux.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
process.c | 44 ++++++++++++++++++
radvd.h | 18 ++++++-
scanner.l | 2 +-
send.c | 32 ++++++++-----
10 files changed, 352 insertions(+), 32 deletions(-)
--
2.7.1
Current issues with the 6CO handling:
- Doesn't work on little endian at my side because forgotten
byteordering handling at bitfields.
- There can be multiple 6CO options. Up to 16 6CO options at maximum.
- It doesn't work as it should. Maybe for some use-case somebody need
that, but 6CO contains information for header parsing and this need
functionality to tell it the kernel. Currently we have a debugfs entry
for that.
As an example, RFC6775 describes the 6LBR should be configurated and
managed the context entries of RFC6282.
interface lowpan0
{
Adv6LBR on;
AdvSendAdvert on;
UnicastOnly on;
AdvCurHopLimit 255;
prefix 2001::/64 {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr on;
};
lowpanco {
ctx 0 {
AdvContextCompressionFlag on;
AdvContextLength 64;
AdvContextPrefix 2001::;
AdvLifeTime 1000;
};
ctx 1 {
...
};
... up to 16 ctx's ...
};
};
If we set "Adv6LBR" to on, then the "lowpanco" contexts will be setup
during startup of radvd, otherwise all contexts are empty (non active).
I changed the parsing of contexts:
- lowpanco contains up-to 16 contexts with _unique_ id's.
- The id is after "ctx" specified.
What doesn't work:
- Lifetime handling.
- AdvContextCompressionFlag should be 0 at first to propagate "safety"
the context inside the network. RFC6775 says here:
New context information SHOULD be introduced into the LoWPAN with C=0,
to ensure that it is known by all nodes that may have to perform header
decompression based on this context information. Only when it is
reasonable to assume that this information was successfully
disseminated SHOULD an option with C=1 be sent, enabling the actual
use of the context information for compression
I know what this means, but then don't know "when" we can do "C=1",
maybe this is out-of-scope in RFC6775.
Note:
I ignore the ABRO for now. The ABRO need to be included and the version
fields indicates if new context or old context information. This is
just to begin with something to handle 6CO.
ABRO must be included, so please add some dummy ABRO when using 6CO.
Signed-off-by: Alexander Aring <[email protected]>
---
defaults.h | 3 ++
device-bsd44.c | 24 ++++++++++
device-linux.c | 32 +++++++++++++
gram.y | 72 ++++++++++++++++++++++------
pathnames.h | 4 ++
privsep-linux.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
process.c | 44 ++++++++++++++++++
radvd.h | 18 ++++++-
scanner.l | 2 +-
send.c | 32 ++++++++-----
10 files changed, 344 insertions(+), 29 deletions(-)
diff --git a/defaults.h b/defaults.h
index fedd546..a328793 100644
--- a/defaults.h
+++ b/defaults.h
@@ -125,6 +125,9 @@
#define MAX_PrefixLen 128
+/* RFC6282 Constraints */
+#define MAX_CIDLen 16
+
/* SLAAC (RFC4862) Constants and Derived Values */
#define MIN_AdvValidLifetime 7200 /* 2 hours in secs */
diff --git a/device-bsd44.c b/device-bsd44.c
index f1aacca..1a22e26 100644
--- a/device-bsd44.c
+++ b/device-bsd44.c
@@ -143,6 +143,30 @@ int set_interface_retranstimer(const char *iface, uint32_t rettimer)
return -1;
}
+int set_interface_ctx_active(const char *iface, uint8_t id, uint8_t val)
+{
+ dlog(LOG_DEBUG, 4, "update 6LoWPAN context not supported");
+ return 0;
+}
+
+int set_interface_ctx_compression(const char *iface, uint8_t id, uint8_t val)
+{
+ dlog(LOG_DEBUG, 4, "update 6LoWPAN context not supported");
+ return 0;
+}
+
+int set_interface_ctx_plen(const char *iface, uint8_t id, uint8_t plen)
+{
+ dlog(LOG_DEBUG, 4, "update 6LoWPAN context not supported");
+ return 0;
+}
+
+int set_interface_ctx_pfx(const char *iface, uint8_t id, struct in6_addr pfx)
+{
+ dlog(LOG_DEBUG, 4, "update 6LoWPAN context not supported");
+ return 0;
+}
+
int check_ip6_forwarding(void)
{
dlog(LOG_DEBUG, 4, "checking ipv6 forwarding not supported");
diff --git a/device-linux.c b/device-linux.c
index 7301927..0a62634 100644
--- a/device-linux.c
+++ b/device-linux.c
@@ -86,6 +86,18 @@ int update_device_info(int sock, struct Interface *iface)
case ARPHRD_6LOWPAN:
iface->sllao.if_hwaddr_len = 64;
iface->sllao.if_prefix_len = 64;
+
+ if (iface->AdvLowpanCoList) {
+ for (int i = 0; i < MAX_CIDLen; i++)
+ set_interface_ctx_active(iface->props.name, i, 0);
+
+ for (struct AdvLowpanCo * current = iface->AdvLowpanCoList; current; current = current->next) {
+ set_interface_ctx_compression(iface->props.name, current->AdvContextID, current->ContextCompressionFlag);
+ set_interface_ctx_plen(iface->props.name, current->AdvContextID, current->ContextLength);
+ set_interface_ctx_pfx(iface->props.name, current->AdvContextID, current->AdvContextPrefix);
+ set_interface_ctx_active(iface->props.name, current->AdvContextID, 1);
+ }
+ }
break;
default:
iface->sllao.if_hwaddr_len = -1;
@@ -147,6 +159,26 @@ int setup_allrouters_membership(int sock, struct Interface *iface)
return 0;
}
+int set_interface_ctx_active(const char *iface, uint8_t id, uint8_t val)
+{
+ return privsep_interface_ctx_active(iface, id, val);
+}
+
+int set_interface_ctx_compression(const char *iface, uint8_t id, uint8_t val)
+{
+ return privsep_interface_ctx_compression(iface, id, val);
+}
+
+int set_interface_ctx_plen(const char *iface, uint8_t id, uint8_t plen)
+{
+ return privsep_interface_ctx_plen(iface, id, plen);
+}
+
+int set_interface_ctx_pfx(const char *iface, uint8_t id, struct in6_addr pfx)
+{
+ return privsep_interface_ctx_pfx(iface, id, pfx);
+}
+
int set_interface_linkmtu(const char *iface, uint32_t mtu)
{
return privsep_interface_linkmtu(iface, mtu);
diff --git a/gram.y b/gram.y
index 1ed4aa3..6b0af23 100644
--- a/gram.y
+++ b/gram.y
@@ -53,6 +53,7 @@ static struct in6_addr get_prefix6(struct in6_addr const *addr, struct in6_addr
%token T_DNSSL
%token T_CLIENTS
%token T_LOWPANCO
+%token T_CTX
%token T_ABRO
%token <str> STRING
@@ -113,7 +114,6 @@ static struct in6_addr get_prefix6(struct in6_addr const *addr, struct in6_addr
%token T_AdvContextLength
%token T_AdvContextCompressionFlag
-%token T_AdvContextID
%token T_AdvLifeTime
%token T_AdvContextPrefix
@@ -130,7 +130,7 @@ static struct in6_addr get_prefix6(struct in6_addr const *addr, struct in6_addr
%type <rinfo> routedef
%type <rdnssinfo> rdnssdef
%type <dnsslinfo> dnssldef
-%type <lowpancoinfo> lowpancodef
+%type <lowpancoinfo> lowpancolist ctxlist
%type <abroinfo> abrodef
%type <num> number_or_infinity
@@ -158,7 +158,7 @@ static struct AdvPrefix *prefix;
static struct AdvRoute *route;
static struct AdvRDNSS *rdnss;
static struct AdvDNSSL *dnssl;
-static struct AdvLowpanCo *lowpanco;
+static struct AdvLowpanCo *lowpanco, *lowpanco_head;
static struct AdvAbro *abro;
static void cleanup(void);
#define ABORT do { cleanup(); YYABORT; } while (0);
@@ -228,7 +228,7 @@ ifaceparam : ifaceval
| routedef { ADD_TO_LL(struct AdvRoute, AdvRouteList, $1); }
| rdnssdef { ADD_TO_LL(struct AdvRDNSS, AdvRDNSSList, $1); }
| dnssldef { ADD_TO_LL(struct AdvDNSSL, AdvDNSSLList, $1); }
- | lowpancodef { ADD_TO_LL(struct AdvLowpanCo, AdvLowpanCoList, $1); }
+ | lowpancolist { ADD_TO_LL(struct AdvLowpanCo, AdvLowpanCoList, $1); }
| abrodef { ADD_TO_LL(struct AdvAbro, AdvAbroList, $1); }
;
@@ -913,23 +913,55 @@ dnsslparms : T_AdvDNSSLLifetime number_or_infinity ';'
}
;
-lowpancodef : lowpancohead '{' optional_lowpancoplist '}' ';'
+lowpancolist : lowpancodef '{' ctxlist '}' ';'
+ {
+ $$ = $3;
+ }
+ ;
+
+lowpancodef : T_LOWPANCO
+ {
+ lowpanco_head = NULL;
+ }
+ ;
+
+ctxlist : ctxhead '{' optional_lowpancoplist '}' ';'
{
$$ = lowpanco;
- lowpanco = NULL;
+ }
+ | ctxlist ctxhead '{' optional_lowpancoplist '}' ';'
+ {
+
+ if (lowpanco_head == NULL)
+ lowpanco_head = lowpanco;
+
+ lowpanco->next = $1;
+ $$ = lowpanco;
}
;
-lowpancohead : T_LOWPANCO
+ctxhead : T_CTX NUMBER
{
- lowpanco = malloc(sizeof(struct AdvLowpanCo));
+ if ($2 > MAX_CIDLen - 1) {
+ flog(LOG_ERR, "invalid context id %d in %s, line %d", $2, filename, num_lines);
+ ABORT;
+ }
+ for (struct AdvLowpanCo * current = lowpanco_head; current; current = current->next) {
+ if ($2 == current->AdvContextID) {
+ flog(LOG_ERR, "context id %d already exists in %s, line %d", $2, filename, num_lines);
+ ABORT;
+ }
+ }
+
+ lowpanco = malloc(sizeof(struct AdvLowpanCo));
if (lowpanco == NULL) {
flog(LOG_CRIT, "malloc failed: %s", strerror(errno));
ABORT;
}
memset(lowpanco, 0, sizeof(struct AdvLowpanCo));
+ lowpanco->AdvContextID = $2;
}
;
@@ -943,20 +975,26 @@ lowpancoplist : lowpancoplist lowpancoparms
lowpancoparms : T_AdvContextLength NUMBER ';'
{
+ if ($2 > MAX_PrefixLen)
+ {
+ flog(LOG_ERR, "invalid context prefix length in %s, line %d", filename, num_lines);
+ ABORT;
+ }
+
lowpanco->ContextLength = $2;
}
| T_AdvContextCompressionFlag SWITCH ';'
{
lowpanco->ContextCompressionFlag = $2;
}
- | T_AdvContextID NUMBER ';'
- {
- lowpanco->AdvContextID = $2;
- }
| T_AdvLifeTime NUMBER ';'
{
lowpanco->AdvLifeTime = $2;
}
+ | T_AdvContextPrefix IPV6ADDR ';'
+ {
+ memcpy(&lowpanco->AdvContextPrefix, $2, sizeof(struct in6_addr));
+ }
;
abrodef : abrohead '{' optional_abroplist '}' ';'
@@ -1102,9 +1140,15 @@ static void cleanup(void)
dnssl = 0;
}
- if (lowpanco) {
- free(lowpanco);
+ if (lowpanco_head) {
+ struct AdvLowpanCo *c = lowpanco_head, *tmp;
+ while (!c) {
+ tmp = c;
+ c = c->next;
+ free(tmp);
+ }
lowpanco = 0;
+ lowpanco_head = 0;
}
if (abro) {
diff --git a/pathnames.h b/pathnames.h
index 580e2b2..c219c7e 100644
--- a/pathnames.h
+++ b/pathnames.h
@@ -40,6 +40,10 @@
#define PROC_SYS_IP6_BASEREACHTIME "/proc/sys/net/ipv6/neigh/%s/base_reachable_time"
#define PROC_SYS_IP6_RETRANSTIMER_MS "/proc/sys/net/ipv6/neigh/%s/retrans_time_ms"
#define PROC_SYS_IP6_RETRANSTIMER "/proc/sys/net/ipv6/neigh/%s/retrans_time"
+#define DEBUGFS_6LOWPAN_CTX_ACTIVE "/sys/kernel/debug/6lowpan/%s/contexts/%d/active"
+#define DEBUGFS_6LOWPAN_CTX_COMPRESSION "/sys/kernel/debug/6lowpan/%s/contexts/%d/compression"
+#define DEBUGFS_6LOWPAN_CTX_PREFIX "/sys/kernel/debug/6lowpan/%s/contexts/%d/prefix"
+#define DEBUGFS_6LOWPAN_CTX_PREFIX_LEN "/sys/kernel/debug/6lowpan/%s/contexts/%d/prefix_len"
#else /* BSD */
#define SYSCTL_IP6_FORWARDING CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_FORWARDING
#endif
diff --git a/privsep-linux.c b/privsep-linux.c
index a48f52a..bdaf94a 100644
--- a/privsep-linux.c
+++ b/privsep-linux.c
@@ -22,6 +22,9 @@
static int set_interface_var(const char *iface, const char *var, const char *name, uint32_t val);
static void privsep_read_loop(void);
+static int set_interface_ctx_var(const char *iface, const char *var, const char *name, uint32_t id, uint32_t val);
+static int __set_interface_ctx_pfx(const char *iface, const char *var, const char *name, uint32_t id, struct in6_addr pfx);
+
/* For reading or writing, depending on process */
static int pfd = -1;
@@ -36,6 +39,10 @@ enum privsep_type {
SET_INTERFACE_CURHLIM,
SET_INTERFACE_REACHTIME,
SET_INTERFACE_RETRANSTIMER,
+ SET_INTERFACE_CTX_ACTIVE,
+ SET_INTERFACE_CTX_COMPRESSION,
+ SET_INTERFACE_CTX_PFX,
+ SET_INTERFACE_CTX_PLEN,
};
/* Command sent over pipe is a fixed size binary structure. */
@@ -43,6 +50,9 @@ struct privsep_command {
int type;
char iface[IFNAMSIZ];
uint32_t val;
+ /* 6lowpan */
+ uint32_t id;
+ struct in6_addr pfx;
};
/* Privileged read loop */
@@ -112,6 +122,34 @@ static void privsep_read_loop(void)
set_interface_var(cmd.iface, PROC_SYS_IP6_RETRANSTIMER, "RetransTimer", cmd.val / 1000 * USER_HZ); /* XXX user_hz */
break;
+ case SET_INTERFACE_CTX_ACTIVE:
+ if (cmd.val != 0 && cmd.val != 1) {
+ flog(LOG_ERR, "(privsep) %s: 6CO %u active flag (%u) is not within the defined bounds, ignoring",
+ cmd.iface, cmd.id, cmd.val);
+ break;
+ }
+ ret = set_interface_ctx_var(cmd.iface, DEBUGFS_6LOWPAN_CTX_ACTIVE, "6CO active flag (bool)", cmd.id, cmd.val);
+ break;
+ case SET_INTERFACE_CTX_COMPRESSION:
+ if (cmd.val != 0 && cmd.val != 1) {
+ flog(LOG_ERR, "(privsep) %s: 6CO %u compression flag (%u) is not within the defined bounds, ignoring",
+ cmd.iface, cmd.id, cmd.val);
+ break;
+ }
+ ret = set_interface_ctx_var(cmd.iface, DEBUGFS_6LOWPAN_CTX_COMPRESSION, "6CO compression flag (bool)", cmd.id, cmd.val);
+ break;
+ case SET_INTERFACE_CTX_PFX:
+ ret = __set_interface_ctx_pfx(cmd.iface, DEBUGFS_6LOWPAN_CTX_PREFIX, "6CO prefix", cmd.id, cmd.pfx);
+ break;
+ case SET_INTERFACE_CTX_PLEN:
+ if (cmd.val > MAX_PrefixLen) {
+ flog(LOG_ERR, "(privsep) %s: 6CO %u prefix length (%u) is not within the defined bounds, ignoring",
+ cmd.iface, cmd.id, cmd.val);
+ break;
+ }
+ ret = set_interface_ctx_var(cmd.iface, DEBUGFS_6LOWPAN_CTX_PREFIX_LEN, "6CO prefix length", cmd.id, cmd.val);
+ break;
+
default:
/* Bad command */
break;
@@ -174,12 +212,59 @@ int privsep_interface_retranstimer(const char *iface, uint32_t rettimer)
return 0;
}
+int privsep_interface_ctx_active(const char *iface, uint32_t id, uint32_t active)
+{
+ struct privsep_command cmd;
+ cmd.type = SET_INTERFACE_CTX_ACTIVE;
+ strncpy(cmd.iface, iface, sizeof(cmd.iface));
+ cmd.id = id;
+ cmd.val = active;
+ if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
+ return -1;
+ return 0;
+}
+
+int privsep_interface_ctx_compression(const char *iface, uint32_t id, uint32_t c)
+{
+ struct privsep_command cmd;
+ cmd.type = SET_INTERFACE_CTX_COMPRESSION;
+ strncpy(cmd.iface, iface, sizeof(cmd.iface));
+ cmd.id = id;
+ cmd.val = c;
+ if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
+ return -1;
+ return 0;
+}
+
+int privsep_interface_ctx_pfx(const char *iface, uint32_t id, struct in6_addr pfx)
+{
+ struct privsep_command cmd;
+ cmd.type = SET_INTERFACE_CTX_PFX;
+ strncpy(cmd.iface, iface, sizeof(cmd.iface));
+ cmd.id = id;
+ cmd.pfx = pfx;
+ if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
+ return -1;
+ return 0;
+}
+
+int privsep_interface_ctx_plen(const char *iface, uint32_t id, uint32_t plen)
+{
+ struct privsep_command cmd;
+ cmd.type = SET_INTERFACE_CTX_PLEN;
+ strncpy(cmd.iface, iface, sizeof(cmd.iface));
+ cmd.id = id;
+ cmd.val = plen;
+ if (writen(pfd, &cmd, sizeof(cmd)) != sizeof(cmd))
+ return -1;
+ return 0;
+}
+
/* note: also called from the root context */
-static int set_interface_var(const char *iface, const char *var, const char *name, uint32_t val)
+static int __set_interface_var(char * spath, const char *iface, const char *var, const char *name, uint32_t val)
{
int retval = -1;
FILE * fp = 0;
- char * spath = strdupf(var, iface);
/* No path traversal */
if (!iface[0] || !strcmp(iface, ".") || !strcmp(iface, "..") || strchr(iface, '/'))
@@ -210,3 +295,56 @@ cleanup:
return retval;
}
+/* note: also called from the root context */
+static int set_interface_var(const char *iface, const char *var, const char *name, uint32_t val)
+{
+ char * spath = strdupf(var, iface);
+
+ return __set_interface_var(spath, iface, var, name, val);
+}
+
+/* note: also called from the root context */
+static int set_interface_ctx_var(const char *iface, const char *var, const char *name, uint32_t id, uint32_t val)
+{
+ char * spath = strdupf(var, iface, id);
+
+ return __set_interface_var(spath, iface, var, name, val);
+}
+
+/* note: also called from the root context */
+static int __set_interface_ctx_pfx(const char *iface, const char *var, const char *name, uint32_t id, struct in6_addr pfx)
+{
+ int retval = -1;
+ FILE * fp = 0;
+ char * spath = strdupf(var, iface, id);
+
+ /* No path traversal */
+ if (!iface[0] || !strcmp(iface, ".") || !strcmp(iface, "..") || strchr(iface, '/'))
+ goto cleanup;
+
+ if (access(spath, F_OK) != 0)
+ goto cleanup;
+
+ fp = fopen(spath, "w");
+ if (!fp) {
+ if (name)
+ flog(LOG_ERR, "failed to set %s (%pI6c) for %s: %s", name, &pfx, iface, strerror(errno));
+ goto cleanup;
+ }
+
+ if (0 > fprintf(fp, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+ be16toh(pfx.s6_addr16[0]), be16toh(pfx.s6_addr16[1]), be16toh(pfx.s6_addr16[2]), be16toh(pfx.s6_addr16[3]),
+ be16toh(pfx.s6_addr16[4]), be16toh(pfx.s6_addr16[5]), be16toh(pfx.s6_addr16[6]), be16toh(pfx.s6_addr16[7]))) {
+ goto cleanup;
+ }
+
+ retval = 0;
+
+cleanup:
+ if (fp)
+ fclose(fp);
+
+ free(spath);
+
+ return retval;
+}
diff --git a/process.c b/process.c
index a6050ad..68e27ea 100644
--- a/process.c
+++ b/process.c
@@ -385,6 +385,50 @@ static void process_ra(struct Interface *iface, unsigned char *msg, int len, str
}
break;
}
+ case ND_OPT_6CO: {
+ struct nd_opt_6co *ctxinfo = (struct nd_opt_6co *)opt_str;
+ struct in6_addr pfx = {};
+
+ /* check if we can evaluate the len field */
+ if (len < 2)
+ return;
+
+ switch (ctxinfo->nd_opt_6co_len) {
+ case 2:
+ if (len < (sizeof(*ctxinfo) - 8))
+ return;
+
+ memcpy(&pfx, &ctxinfo->nd_opt_6co_con_prefix, 8);
+ break;
+ case 3:
+ if (len < (sizeof(*ctxinfo)))
+ return;
+
+ memcpy(&pfx, &ctxinfo->nd_opt_6co_con_prefix, 16);
+ break;
+ default:
+ return;
+ }
+
+ if (ctxinfo->nd_opt_6co_cid > MAX_CIDLen - 1)
+ return;
+
+ /* If the Valid Lifetime field in the 6CO is zero, then the entry is immediately deleted. */
+ if (!ctxinfo->nd_opt_6co_valid_lifetime)
+ set_interface_ctx_active(iface->props.name, ctxinfo->nd_opt_6co_cid, 0);
+ else {
+ /* disable it while updating context */
+ set_interface_ctx_active(iface->props.name, ctxinfo->nd_opt_6co_cid, 0);
+
+ set_interface_ctx_pfx(iface->props.name, ctxinfo->nd_opt_6co_cid, pfx);
+ set_interface_ctx_plen(iface->props.name, ctxinfo->nd_opt_6co_cid, ctxinfo->nd_opt_6co_context_len);
+ set_interface_ctx_compression(iface->props.name, ctxinfo->nd_opt_6co_cid, ctxinfo->nd_opt_6co_c);
+
+ /* enable it again */
+ set_interface_ctx_active(iface->props.name, ctxinfo->nd_opt_6co_cid, 1);
+ }
+ break;
+ }
default:
dlog(LOG_DEBUG, 1, "unknown option %d in RA on %s from %s", (int)*opt_str, iface->props.name, addr_str);
break;
diff --git a/radvd.h b/radvd.h
index f557bf3..97b52d4 100644
--- a/radvd.h
+++ b/radvd.h
@@ -187,7 +187,7 @@ struct AdvDNSSL {
struct AdvDNSSL *next;
};
-/* Options for 6lopan configuration */
+/* Options for 6lowpan configuration */
struct AdvLowpanCo {
uint8_t ContextLength;
@@ -242,9 +242,17 @@ struct nd_opt_6co {
uint8_t nd_opt_6co_type;
uint8_t nd_opt_6co_len;
uint8_t nd_opt_6co_context_len;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ uint8_t nd_opt_6co_cid:4;
+ uint8_t nd_opt_6co_c:1;
+ uint8_t nd_opt_6co_res:3;
+#elif __BYTE_ORDER == __BIG_ENDIAN
uint8_t nd_opt_6co_res:3;
uint8_t nd_opt_6co_c:1;
uint8_t nd_opt_6co_cid:4;
+#else
+#error "no byte order specified!"
+#endif
uint16_t nd_opt_6co_reserved;
uint16_t nd_opt_6co_valid_lifetime;
struct in6_addr nd_opt_6co_con_prefix;
@@ -269,6 +277,10 @@ int set_interface_curhlim(const char *, uint8_t);
int set_interface_linkmtu(const char *, uint32_t);
int set_interface_reachtime(const char *, uint32_t);
int set_interface_retranstimer(const char *, uint32_t);
+int set_interface_ctx_active(const char *iface, uint8_t id, uint8_t val);
+int set_interface_ctx_compression(const char *iface, uint8_t id, uint8_t val);
+int set_interface_ctx_plen(const char *iface, uint8_t id, uint8_t plen);
+int set_interface_ctx_pfx(const char *iface, uint8_t id, struct in6_addr pfx);
int setup_allrouters_membership(int sock, struct Interface *);
int setup_linklocal_addr(struct Interface *);
int setup_linklocal_addr(struct Interface *iface);
@@ -321,6 +333,10 @@ int privsep_interface_curhlim(const char *iface, uint32_t hlim);
int privsep_interface_linkmtu(const char *iface, uint32_t mtu);
int privsep_interface_reachtime(const char *iface, uint32_t rtime);
int privsep_interface_retranstimer(const char *iface, uint32_t rettimer);
+int privsep_interface_ctx_active(const char *iface, uint32_t id, uint32_t active);
+int privsep_interface_ctx_compression(const char *iface, uint32_t id, uint32_t c);
+int privsep_interface_ctx_pfx(const char *iface, uint32_t id, struct in6_addr pfx);
+int privsep_interface_ctx_plen(const char *iface, uint32_t id, uint32_t plen);
void privsep_init(int);
void privsep_set_write_fd(int);
diff --git a/scanner.l b/scanner.l
index 164a834..07602bf 100644
--- a/scanner.l
+++ b/scanner.l
@@ -49,6 +49,7 @@ RDNSS { return T_RDNSS; }
DNSSL { return T_DNSSL; }
clients { return T_CLIENTS; }
lowpanco { return T_LOWPANCO; }
+ctx { return T_CTX; }
abro { return T_ABRO; }
IgnoreIfMissing { return T_IgnoreIfMissing; }
@@ -102,7 +103,6 @@ AdvMobRtrSupportFlag { return T_AdvMobRtrSupportFlag; }
AdvContextLength { return T_AdvContextLength; }
AdvContextCompressionFlag { return T_AdvContextCompressionFlag; }
-AdvContextID { return T_AdvContextID; }
AdvLifeTime { return T_AdvLifeTime; }
AdvContextPrefix { return T_AdvContextPrefix; }
diff --git a/send.c b/send.c
index 96ded05..06281c6 100644
--- a/send.c
+++ b/send.c
@@ -35,7 +35,7 @@ static void add_mtu(struct safe_buffer * sb, uint32_t AdvLinkMTU);
static void add_sllao(struct safe_buffer * sb, struct sllao const *sllao);
static void add_mipv6_rtr_adv_interval(struct safe_buffer * sb, double MaxRtrAdvInterval);
static void add_mipv6_home_agent_info(struct safe_buffer * sb, struct mipv6 const * mipv6);
-static void add_lowpanco(struct safe_buffer * sb, struct AdvLowpanCo const *lowpanco);
+static void add_lowpanco(struct safe_buffer * sb, struct AdvLowpanCo *lowpanco);
static void add_abro(struct safe_buffer * sb, struct AdvAbro const *abroo);
#ifdef UNIT_TEST
@@ -540,21 +540,31 @@ static void add_mipv6_home_agent_info(struct safe_buffer * sb, struct mipv6 cons
/*
* Add 6co option
*/
-static void add_lowpanco(struct safe_buffer * sb, struct AdvLowpanCo const *lowpanco)
+static void add_lowpanco(struct safe_buffer * sb, struct AdvLowpanCo *lowpanco)
{
struct nd_opt_6co co;
+ size_t nd_opt_6co_size;
- memset(&co, 0, sizeof(co));
+ for (struct AdvLowpanCo * current = lowpanco; current; current = current->next) {
+ memset(&co, 0, sizeof(co));
- co.nd_opt_6co_type = ND_OPT_6CO;
- co.nd_opt_6co_len = 3;
- co.nd_opt_6co_context_len = lowpanco->ContextLength;
- co.nd_opt_6co_c = lowpanco->ContextCompressionFlag;
- co.nd_opt_6co_cid = lowpanco->AdvContextID;
- co.nd_opt_6co_valid_lifetime = lowpanco->AdvLifeTime;
- co.nd_opt_6co_con_prefix = lowpanco->AdvContextPrefix;
+ co.nd_opt_6co_type = ND_OPT_6CO;
+ co.nd_opt_6co_context_len = current->ContextLength;
+ if (co.nd_opt_6co_context_len > 64) {
+ co.nd_opt_6co_len = 3;
+ nd_opt_6co_size = sizeof(co);
+ } else {
+ co.nd_opt_6co_len = 2;
+ nd_opt_6co_size = sizeof(co) - 8;
+ }
+ co.nd_opt_6co_c = current->ContextCompressionFlag;
+ co.nd_opt_6co_cid = current->AdvContextID;
+ co.nd_opt_6co_valid_lifetime = current->AdvLifeTime;
+ co.nd_opt_6co_con_prefix = current->AdvContextPrefix;
- safe_buffer_append(sb, &co, sizeof(co));
+ safe_buffer_append(sb, &co, nd_opt_6co_size);
+
+ }
}
static void add_abro(struct safe_buffer * sb, struct AdvAbro const *abroo)
--
2.7.1
This patch changes the ARPHRD_IEEE802154 to ARPHRD_6LOWPAN. The IEEE
802.15.4 6lowpan module changed the ARPHRD_IEEE802154 type to
ARPHRD_6LOWPAN. Nowadays it's use ARPHRD_6LOWPAN which is also used by
BTLE 6LoWPAN. Both interfaces uses an EUI64 address and the handling to
get the link-layer address should be the same.
There is no backward compatibility for 802.15.4 6LoWPAN before we
changed the ARPHRD. Anyway if somebody wants that it should be patched
manually. When the ARPHRD was ARPHRD_IEEE802154 the 802.15.4 6lowpan was
anyway in a somehow unusable state.
Signed-off-by: Alexander Aring <[email protected]>
---
device-linux.c | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/device-linux.c b/device-linux.c
index de83f2e..7301927 100644
--- a/device-linux.c
+++ b/device-linux.c
@@ -22,6 +22,10 @@
#define IPV6_ADDR_LINKLOCAL 0x0020U
#endif
+#ifndef ARPHRD_6LOWPAN
+#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */
+#endif
+
static char const *hwstr(unsigned short sa_family);
/*
@@ -79,12 +83,10 @@ int update_device_info(int sock, struct Interface *iface)
iface->sllao.if_maxmtu = -1;
break;
#endif /* ARPHDR_ARCNET */
-#ifdef ARPHRD_IEEE802154
- case ARPHRD_IEEE802154:
+ case ARPHRD_6LOWPAN:
iface->sllao.if_hwaddr_len = 64;
iface->sllao.if_prefix_len = 64;
break;
-#endif
default:
iface->sllao.if_hwaddr_len = -1;
iface->sllao.if_prefix_len = -1;
@@ -382,6 +384,9 @@ static char const *hwstr(unsigned short sa_family)
rc = "ARPHRD_IEEE802154_PHY";
break;
#endif
+ case ARPHRD_6LOWPAN:
+ rc = "ARPHRD_6LOWPAN";
+ break;
case ARPHRD_VOID:
rc = "ARPHRD_VOID";
break;
--
2.7.1