summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Aring <aar@pengutronix.de>2016-06-15 15:20:17 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-15 23:41:22 -0400
commit2ad3ed59198c5404c34515cfcfd9a2b3c54d964f (patch)
tree0dd9cbc8f4787819d70afd97ff91256f70d4ccc7
parent8626a0c83b0d471d859bcd908d016874df951fc3 (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.h6
-rw-r--r--include/net/addrconf.h3
-rw-r--r--net/6lowpan/core.c46
-rw-r--r--net/ipv6/addrconf.c5
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
257static 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
257static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data, 263static 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,
94void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); 94void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr);
95void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); 95void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr);
96 96
97void addrconf_add_linklocal(struct inet6_dev *idev,
98 const struct in6_addr *addr, u32 flags);
99
97static inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) 100static 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}
73EXPORT_SYMBOL(lowpan_unregister_netdev); 74EXPORT_SYMBOL(lowpan_unregister_netdev);
74 75
76static 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
75static int lowpan_event(struct notifier_block *unused, 105static 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
2950static void addrconf_add_linklocal(struct inet6_dev *idev, 2950void 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}
2970EXPORT_SYMBOL_GPL(addrconf_add_linklocal);
2970 2971
2971static bool ipv6_reserved_interfaceid(struct in6_addr address) 2972static bool ipv6_reserved_interfaceid(struct in6_addr address)
2972{ 2973{