@@ -127,6 +127,8 @@
/* RFC6282 Constraints */
#define MAX_CIDLen 16
+#define SHORT_ADDR_UNSPEC 0xfffe
+#define SHORT_ADDR_BITS_LEN 16
/* SLAAC (RFC4862) Constants and Derived Values */
#define MIN_AdvValidLifetime 7200 /* 2 hours in secs */
@@ -29,6 +29,37 @@
static char const *hwstr(unsigned short sa_family);
/*
+ * this function gets the short address which is available on 802,15.4
+ * 6lowpan only. All others will return an invalid address which is the
+ * broadcast address. If it's a valid address it will be added to RA
+ * messages.
+ */
+static uint16_t lowpan_get_short_addr(struct Interface *iface)
+{
+ unsigned int short_addr;
+ char path[PATH_MAX];
+ FILE *f;
+ int ret;
+
+ ret = sprintf(path, DEBUGFS_6LOWPAN_SHORT_ADDR, iface->props.name);
+ if (ret < 0)
+ return SHORT_ADDR_UNSPEC;
+
+ f = fopen(path, "r");
+ if (!f)
+ return SHORT_ADDR_UNSPEC;
+
+ ret = fscanf(f, "0x%04x", &short_addr);
+ if (ferror(f)) {
+ fclose(f);
+ return SHORT_ADDR_UNSPEC;
+ }
+
+ fclose(f);
+ return short_addr;
+}
+
+/*
* this function gets the hardware type and address of an interface,
* determines the link layer token length and checks it against
* the defined prefixes
@@ -86,6 +117,8 @@ int update_device_info(int sock, struct Interface *iface)
case ARPHRD_6LOWPAN:
iface->sllao.if_hwaddr_len = 64;
iface->sllao.if_prefix_len = 64;
+ /* for 802.15.4 only, all others L2 should fail and assign invalid address */
+ iface->short_addr = lowpan_get_short_addr(iface);
if (iface->AdvLowpanCoList) {
for (int i = 0; i < MAX_CIDLen; i++)
@@ -47,6 +47,7 @@ void iface_init_defaults(struct Interface *iface)
iface->AdvLinkMTU = DFLT_AdvLinkMTU;
+ iface->short_addr = SHORT_ADDR_UNSPEC;
}
@@ -44,6 +44,7 @@
#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"
+#define DEBUGFS_6LOWPAN_SHORT_ADDR "/sys/kernel/debug/6lowpan/%s/ieee802154/short_addr"
#else /* BSD */
#define SYSCTL_IP6_FORWARDING CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_FORWARDING
#endif
@@ -102,6 +102,8 @@ struct Interface {
int if_maxmtu;
} sllao;
+ uint16_t short_addr;
+
struct mipv6 {
/* Mobile IPv6 extensions */
int AdvIntervalOpt;
@@ -32,7 +32,8 @@ static void add_rdnss(struct safe_buffer * sb, struct AdvRDNSS const *rdnss, int
static size_t serialize_domain_names(struct safe_buffer * safe_buffer, struct AdvDNSSL const *dnssl);
static void add_dnssl(struct safe_buffer * sb, struct AdvDNSSL const *dnssl, int cease_adv);
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_sllao(struct safe_buffer * sb, const uint8_t *if_hwaddr,
+ int if_hwaddr_len);
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 *lowpanco);
@@ -431,7 +432,8 @@ static void add_dnssl(struct safe_buffer * safe_buffer, struct AdvDNSSL const *d
/*
* add Source Link-layer Address option
*/
-static void add_sllao(struct safe_buffer * sb, struct sllao const *sllao)
+static void add_sllao(struct safe_buffer * sb, const uint8_t *if_hwaddr,
+ int if_hwaddr_len)
{
/* *INDENT-OFF* */
/*
@@ -467,14 +469,14 @@ static void add_sllao(struct safe_buffer * sb, struct sllao const *sllao)
/* *INDENT-ON* */
/* +2 for the ND_OPT_SOURCE_LINKADDR and the length (each occupy one byte) */
- size_t const sllao_bytes = (sllao->if_hwaddr_len / 8) + 2;
+ size_t const sllao_bytes = (if_hwaddr_len / 8) + 2;
size_t const sllao_len = (sllao_bytes + 7) / 8;
uint8_t buff[2] = {ND_OPT_SOURCE_LINKADDR, (uint8_t)sllao_len};
safe_buffer_append(sb, buff, sizeof(buff));
/* if_hwaddr_len is in bits, so divide by 8 to get the byte count. */
- safe_buffer_append(sb, sllao->if_hwaddr, sllao->if_hwaddr_len / 8);
+ safe_buffer_append(sb, if_hwaddr, if_hwaddr_len / 8);
safe_buffer_pad(sb, sllao_len * 8 - sllao_bytes);
}
@@ -608,8 +610,17 @@ static void build_ra(struct safe_buffer * sb, struct Interface const * iface)
add_mtu(sb, iface->AdvLinkMTU);
}
- if (iface->AdvSourceLLAddress && iface->sllao.if_hwaddr_len > 0) {
- add_sllao(sb, &iface->sllao);
+ if (iface->AdvSourceLLAddress) {
+ if (iface->sllao.if_hwaddr_len > 0) {
+ add_sllao(sb, iface->sllao.if_hwaddr, iface->sllao.if_hwaddr_len);
+ }
+
+ /* add second sllao for 802.15.4 short address if valid unicast */
+ if (!(iface->short_addr & 0x8000)) {
+ uint16_t short_addr_be = htons(iface->short_addr);
+
+ add_sllao(sb, (const uint8_t *)&short_addr_be, SHORT_ADDR_BITS_LEN);
+ }
}
if (iface->mipv6.AdvIntervalOpt) {
This patch adds handling for adding the 802.15.4 short address in RA as sllao if available. All others 6LoWPAN layers and if getting of short address failed, we don't add a short address sllao in there. Signed-off-by: Alexander Aring <aar@pengutronix.de> --- changes since v2: - fix error handling in fscanf - changes to new kernel UAPI - check on 6lowpan unicast short addr only (first bit) defaults.h | 2 ++ device-linux.c | 33 +++++++++++++++++++++++++++++++++ interface.c | 1 + pathnames.h | 1 + radvd.h | 2 ++ send.c | 23 +++++++++++++++++------ 6 files changed, 56 insertions(+), 6 deletions(-)