diff options
author | Alexander Aring <aar@pengutronix.de> | 2016-06-15 15:20:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-06-15 23:41:22 -0400 |
commit | 2ad3ed59198c5404c34515cfcfd9a2b3c54d964f (patch) | |
tree | 0dd9cbc8f4787819d70afd97ff91256f70d4ccc7 | |
parent | 8626a0c83b0d471d859bcd908d016874df951fc3 (diff) |
6lowpan: add 802.15.4 short addr slaac
This patch adds the autoconfiguration if a valid 802.15.4 short address
is available for 802.15.4 6LoWPAN interfaces.
Cc: David S. Miller <davem@davemloft.net>
Cc: Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
Cc: James Morris <jmorris@namei.org>
Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
Cc: Patrick McHardy <kaber@trash.net>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Reviewed-by: Stefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: Alexander Aring <aar@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/6lowpan.h | 6 | ||||
-rw-r--r-- | include/net/addrconf.h | 3 | ||||
-rw-r--r-- | net/6lowpan/core.c | 46 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 5 |
4 files changed, 58 insertions, 2 deletions
diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h index 2d9b9d39221e..5ab4c9901ccc 100644 --- a/include/net/6lowpan.h +++ b/include/net/6lowpan.h | |||
@@ -254,6 +254,12 @@ static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data, | |||
254 | return false; | 254 | return false; |
255 | } | 255 | } |
256 | 256 | ||
257 | static inline bool lowpan_802154_is_valid_src_short_addr(__le16 addr) | ||
258 | { | ||
259 | /* First bit of addr is multicast, reserved or 802.15.4 specific */ | ||
260 | return !(addr & cpu_to_le16(0x8000)); | ||
261 | } | ||
262 | |||
257 | static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data, | 263 | static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data, |
258 | const size_t len) | 264 | const size_t len) |
259 | { | 265 | { |
diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 730d856683e5..b1774eb03f37 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h | |||
@@ -94,6 +94,9 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2, | |||
94 | void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); | 94 | void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); |
95 | void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); | 95 | void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); |
96 | 96 | ||
97 | void addrconf_add_linklocal(struct inet6_dev *idev, | ||
98 | const struct in6_addr *addr, u32 flags); | ||
99 | |||
97 | static inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) | 100 | static inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) |
98 | { | 101 | { |
99 | if (dev->addr_len != ETH_ALEN) | 102 | if (dev->addr_len != ETH_ALEN) |
diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c index 7a240b3eaed1..801404ceea23 100644 --- a/net/6lowpan/core.c +++ b/net/6lowpan/core.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | 15 | ||
16 | #include <net/6lowpan.h> | 16 | #include <net/6lowpan.h> |
17 | #include <net/addrconf.h> | ||
17 | 18 | ||
18 | #include "6lowpan_i.h" | 19 | #include "6lowpan_i.h" |
19 | 20 | ||
@@ -72,16 +73,61 @@ void lowpan_unregister_netdev(struct net_device *dev) | |||
72 | } | 73 | } |
73 | EXPORT_SYMBOL(lowpan_unregister_netdev); | 74 | EXPORT_SYMBOL(lowpan_unregister_netdev); |
74 | 75 | ||
76 | static int addrconf_ifid_802154_6lowpan(u8 *eui, struct net_device *dev) | ||
77 | { | ||
78 | struct wpan_dev *wpan_dev = lowpan_802154_dev(dev)->wdev->ieee802154_ptr; | ||
79 | |||
80 | /* Set short_addr autoconfiguration if short_addr is present only */ | ||
81 | if (!lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr)) | ||
82 | return -1; | ||
83 | |||
84 | /* For either address format, all zero addresses MUST NOT be used */ | ||
85 | if (wpan_dev->pan_id == cpu_to_le16(0x0000) && | ||
86 | wpan_dev->short_addr == cpu_to_le16(0x0000)) | ||
87 | return -1; | ||
88 | |||
89 | /* Alternatively, if no PAN ID is known, 16 zero bits may be used */ | ||
90 | if (wpan_dev->pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST)) | ||
91 | memset(eui, 0, 2); | ||
92 | else | ||
93 | ieee802154_le16_to_be16(eui, &wpan_dev->pan_id); | ||
94 | |||
95 | /* The "Universal/Local" (U/L) bit shall be set to zero */ | ||
96 | eui[0] &= ~2; | ||
97 | eui[2] = 0; | ||
98 | eui[3] = 0xFF; | ||
99 | eui[4] = 0xFE; | ||
100 | eui[5] = 0; | ||
101 | ieee802154_le16_to_be16(&eui[6], &wpan_dev->short_addr); | ||
102 | return 0; | ||
103 | } | ||
104 | |||
75 | static int lowpan_event(struct notifier_block *unused, | 105 | static int lowpan_event(struct notifier_block *unused, |
76 | unsigned long event, void *ptr) | 106 | unsigned long event, void *ptr) |
77 | { | 107 | { |
78 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 108 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
109 | struct inet6_dev *idev; | ||
110 | struct in6_addr addr; | ||
79 | int i; | 111 | int i; |
80 | 112 | ||
81 | if (dev->type != ARPHRD_6LOWPAN) | 113 | if (dev->type != ARPHRD_6LOWPAN) |
82 | return NOTIFY_DONE; | 114 | return NOTIFY_DONE; |
83 | 115 | ||
116 | idev = __in6_dev_get(dev); | ||
117 | if (!idev) | ||
118 | return NOTIFY_DONE; | ||
119 | |||
84 | switch (event) { | 120 | switch (event) { |
121 | case NETDEV_UP: | ||
122 | case NETDEV_CHANGE: | ||
123 | /* (802.15.4 6LoWPAN short address slaac handling */ | ||
124 | if (lowpan_is_ll(dev, LOWPAN_LLTYPE_IEEE802154) && | ||
125 | addrconf_ifid_802154_6lowpan(addr.s6_addr + 8, dev) == 0) { | ||
126 | __ipv6_addr_set_half(&addr.s6_addr32[0], | ||
127 | htonl(0xFE800000), 0); | ||
128 | addrconf_add_linklocal(idev, &addr, 0); | ||
129 | } | ||
130 | break; | ||
85 | case NETDEV_DOWN: | 131 | case NETDEV_DOWN: |
86 | for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) | 132 | for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) |
87 | clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, | 133 | clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b12553905e42..1ce4048d1b5e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -2947,8 +2947,8 @@ static void init_loopback(struct net_device *dev) | |||
2947 | } | 2947 | } |
2948 | } | 2948 | } |
2949 | 2949 | ||
2950 | static void addrconf_add_linklocal(struct inet6_dev *idev, | 2950 | void addrconf_add_linklocal(struct inet6_dev *idev, |
2951 | const struct in6_addr *addr, u32 flags) | 2951 | const struct in6_addr *addr, u32 flags) |
2952 | { | 2952 | { |
2953 | struct inet6_ifaddr *ifp; | 2953 | struct inet6_ifaddr *ifp; |
2954 | u32 addr_flags = flags | IFA_F_PERMANENT; | 2954 | u32 addr_flags = flags | IFA_F_PERMANENT; |
@@ -2967,6 +2967,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, | |||
2967 | in6_ifa_put(ifp); | 2967 | in6_ifa_put(ifp); |
2968 | } | 2968 | } |
2969 | } | 2969 | } |
2970 | EXPORT_SYMBOL_GPL(addrconf_add_linklocal); | ||
2970 | 2971 | ||
2971 | static bool ipv6_reserved_interfaceid(struct in6_addr address) | 2972 | static bool ipv6_reserved_interfaceid(struct in6_addr address) |
2972 | { | 2973 | { |