diff mbox

[PATCHv2,linux-wpan/radvd,6lowpan] radvd: add handling for 802.15.4 short addr sllao

Message ID 20160618085628.5287-1-aar@pengutronix.de (mailing list archive)
State Not Applicable
Headers show

Commit Message

Alexander Aring June 18, 2016, 8:56 a.m. UTC
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(-)
diff mbox

Patch

diff --git a/defaults.h b/defaults.h
index a328793..a4d100d 100644
--- a/defaults.h
+++ b/defaults.h
@@ -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 */
diff --git a/device-linux.c b/device-linux.c
index 0a62634..55f8522 100644
--- a/device-linux.c
+++ b/device-linux.c
@@ -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++)
diff --git a/interface.c b/interface.c
index d09a1e7..0fd180e 100644
--- a/interface.c
+++ b/interface.c
@@ -47,6 +47,7 @@  void iface_init_defaults(struct Interface *iface)
 
 	iface->AdvLinkMTU = DFLT_AdvLinkMTU;
 
+	iface->short_addr = SHORT_ADDR_UNSPEC;
 }
 
 
diff --git a/pathnames.h b/pathnames.h
index c219c7e..0d3017b 100644
--- a/pathnames.h
+++ b/pathnames.h
@@ -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
diff --git a/radvd.h b/radvd.h
index 2540a82..1ba875c 100644
--- a/radvd.h
+++ b/radvd.h
@@ -102,6 +102,8 @@  struct Interface {
 		int if_maxmtu;
 	} sllao;
 
+	uint16_t short_addr;
+
 	struct mipv6 {
 		/* Mobile IPv6 extensions */
 		int AdvIntervalOpt;
diff --git a/send.c b/send.c
index 06281c6..01cfaaa 100644
--- a/send.c
+++ b/send.c
@@ -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) {