diff options
author | Luiz Augusto von Dentz <luiz.von.dentz@intel.com> | 2017-03-12 04:19:37 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2017-04-12 16:02:36 -0400 |
commit | fa09ae661fb5ab6f9826545d5128f2b7393bcf4a (patch) | |
tree | 3e97a905cfc5182279062b77b3be654db917876a | |
parent | 8a7a4b476719df1e06f8eae837b13bdf79908843 (diff) |
6lowpan: Use netdev addr_len to determine lladdr len
This allow technologies such as Bluetooth to use its native lladdr which
is eui48 instead of eui64 which was expected by functions like
lowpan_header_decompress and lowpan_header_compress.
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Reviewed-by: Stefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/6lowpan.h | 19 | ||||
-rw-r--r-- | net/6lowpan/iphc.c | 49 | ||||
-rw-r--r-- | net/bluetooth/6lowpan.c | 42 |
3 files changed, 63 insertions, 47 deletions
diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h index 5ab4c9901ccc..c5792cb6c3eb 100644 --- a/include/net/6lowpan.h +++ b/include/net/6lowpan.h | |||
@@ -198,6 +198,25 @@ static inline void lowpan_iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr, | |||
198 | ipaddr->s6_addr[8] ^= 0x02; | 198 | ipaddr->s6_addr[8] ^= 0x02; |
199 | } | 199 | } |
200 | 200 | ||
201 | static inline void lowpan_iphc_uncompress_eui48_lladdr(struct in6_addr *ipaddr, | ||
202 | const void *lladdr) | ||
203 | { | ||
204 | /* fe:80::XXXX:XXff:feXX:XXXX | ||
205 | * \_________________/ | ||
206 | * hwaddr | ||
207 | */ | ||
208 | ipaddr->s6_addr[0] = 0xFE; | ||
209 | ipaddr->s6_addr[1] = 0x80; | ||
210 | memcpy(&ipaddr->s6_addr[8], lladdr, 3); | ||
211 | ipaddr->s6_addr[11] = 0xFF; | ||
212 | ipaddr->s6_addr[12] = 0xFE; | ||
213 | memcpy(&ipaddr->s6_addr[13], lladdr + 3, 3); | ||
214 | /* second bit-flip (Universe/Local) | ||
215 | * is done according RFC2464 | ||
216 | */ | ||
217 | ipaddr->s6_addr[8] ^= 0x02; | ||
218 | } | ||
219 | |||
201 | #ifdef DEBUG | 220 | #ifdef DEBUG |
202 | /* print data in line */ | 221 | /* print data in line */ |
203 | static inline void raw_dump_inline(const char *caller, char *msg, | 222 | static inline void raw_dump_inline(const char *caller, char *msg, |
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index fb5f6fa8f1df..6b1042e21656 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c | |||
@@ -278,6 +278,23 @@ lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev, | |||
278 | return ret; | 278 | return ret; |
279 | } | 279 | } |
280 | 280 | ||
281 | static void lowpan_iphc_uncompress_lladdr(const struct net_device *dev, | ||
282 | struct in6_addr *ipaddr, | ||
283 | const void *lladdr) | ||
284 | { | ||
285 | switch (dev->addr_len) { | ||
286 | case ETH_ALEN: | ||
287 | lowpan_iphc_uncompress_eui48_lladdr(ipaddr, lladdr); | ||
288 | break; | ||
289 | case EUI64_ADDR_LEN: | ||
290 | lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); | ||
291 | break; | ||
292 | default: | ||
293 | WARN_ON_ONCE(1); | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | |||
281 | /* Uncompress address function for source and | 298 | /* Uncompress address function for source and |
282 | * destination address(non-multicast). | 299 | * destination address(non-multicast). |
283 | * | 300 | * |
@@ -320,7 +337,7 @@ static int lowpan_iphc_uncompress_addr(struct sk_buff *skb, | |||
320 | lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); | 337 | lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); |
321 | break; | 338 | break; |
322 | default: | 339 | default: |
323 | lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); | 340 | lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr); |
324 | break; | 341 | break; |
325 | } | 342 | } |
326 | break; | 343 | break; |
@@ -381,7 +398,7 @@ static int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb, | |||
381 | lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); | 398 | lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); |
382 | break; | 399 | break; |
383 | default: | 400 | default: |
384 | lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); | 401 | lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr); |
385 | break; | 402 | break; |
386 | } | 403 | } |
387 | ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); | 404 | ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); |
@@ -810,6 +827,21 @@ lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr, | |||
810 | return lladdr_compress; | 827 | return lladdr_compress; |
811 | } | 828 | } |
812 | 829 | ||
830 | static bool lowpan_iphc_addr_equal(const struct net_device *dev, | ||
831 | const struct lowpan_iphc_ctx *ctx, | ||
832 | const struct in6_addr *ipaddr, | ||
833 | const void *lladdr) | ||
834 | { | ||
835 | struct in6_addr tmp = {}; | ||
836 | |||
837 | lowpan_iphc_uncompress_lladdr(dev, &tmp, lladdr); | ||
838 | |||
839 | if (ctx) | ||
840 | ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); | ||
841 | |||
842 | return ipv6_addr_equal(&tmp, ipaddr); | ||
843 | } | ||
844 | |||
813 | static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev, | 845 | static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev, |
814 | const struct in6_addr *ipaddr, | 846 | const struct in6_addr *ipaddr, |
815 | const struct lowpan_iphc_ctx *ctx, | 847 | const struct lowpan_iphc_ctx *ctx, |
@@ -827,13 +859,7 @@ static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev, | |||
827 | } | 859 | } |
828 | break; | 860 | break; |
829 | default: | 861 | default: |
830 | /* check for SAM/DAM = 11 */ | 862 | if (lowpan_iphc_addr_equal(dev, ctx, ipaddr, lladdr)) { |
831 | memcpy(&tmp.s6_addr[8], lladdr, EUI64_ADDR_LEN); | ||
832 | /* second bit-flip (Universe/Local) is done according RFC2464 */ | ||
833 | tmp.s6_addr[8] ^= 0x02; | ||
834 | /* context information are always used */ | ||
835 | ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); | ||
836 | if (ipv6_addr_equal(&tmp, ipaddr)) { | ||
837 | dam = LOWPAN_IPHC_DAM_11; | 863 | dam = LOWPAN_IPHC_DAM_11; |
838 | goto out; | 864 | goto out; |
839 | } | 865 | } |
@@ -929,11 +955,12 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev, | |||
929 | } | 955 | } |
930 | break; | 956 | break; |
931 | default: | 957 | default: |
932 | if (is_addr_mac_addr_based(ipaddr, lladdr)) { | 958 | if (lowpan_iphc_addr_equal(dev, NULL, ipaddr, lladdr)) { |
933 | dam = LOWPAN_IPHC_DAM_11; /* 0-bits */ | 959 | dam = LOWPAN_IPHC_DAM_11; |
934 | pr_debug("address compression 0 bits\n"); | 960 | pr_debug("address compression 0 bits\n"); |
935 | goto out; | 961 | goto out; |
936 | } | 962 | } |
963 | |||
937 | break; | 964 | break; |
938 | } | 965 | } |
939 | 966 | ||
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index bad0e9d1ea20..54bf4d765a7d 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c | |||
@@ -64,7 +64,7 @@ struct lowpan_peer { | |||
64 | struct l2cap_chan *chan; | 64 | struct l2cap_chan *chan; |
65 | 65 | ||
66 | /* peer addresses in various formats */ | 66 | /* peer addresses in various formats */ |
67 | unsigned char eui64_addr[EUI64_ADDR_LEN]; | 67 | unsigned char lladdr[ETH_ALEN]; |
68 | struct in6_addr peer_addr; | 68 | struct in6_addr peer_addr; |
69 | }; | 69 | }; |
70 | 70 | ||
@@ -80,8 +80,6 @@ struct lowpan_btle_dev { | |||
80 | struct delayed_work notify_peers; | 80 | struct delayed_work notify_peers; |
81 | }; | 81 | }; |
82 | 82 | ||
83 | static void set_addr(u8 *eui, u8 *addr, u8 addr_type); | ||
84 | |||
85 | static inline struct lowpan_btle_dev * | 83 | static inline struct lowpan_btle_dev * |
86 | lowpan_btle_dev(const struct net_device *netdev) | 84 | lowpan_btle_dev(const struct net_device *netdev) |
87 | { | 85 | { |
@@ -277,7 +275,6 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev, | |||
277 | const u8 *saddr; | 275 | const u8 *saddr; |
278 | struct lowpan_btle_dev *dev; | 276 | struct lowpan_btle_dev *dev; |
279 | struct lowpan_peer *peer; | 277 | struct lowpan_peer *peer; |
280 | unsigned char eui64_daddr[EUI64_ADDR_LEN]; | ||
281 | 278 | ||
282 | dev = lowpan_btle_dev(netdev); | 279 | dev = lowpan_btle_dev(netdev); |
283 | 280 | ||
@@ -287,10 +284,9 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev, | |||
287 | if (!peer) | 284 | if (!peer) |
288 | return -EINVAL; | 285 | return -EINVAL; |
289 | 286 | ||
290 | saddr = peer->eui64_addr; | 287 | saddr = peer->lladdr; |
291 | set_addr(&eui64_daddr[0], chan->src.b, chan->src_type); | ||
292 | 288 | ||
293 | return lowpan_header_decompress(skb, netdev, &eui64_daddr, saddr); | 289 | return lowpan_header_decompress(skb, netdev, netdev->dev_addr, saddr); |
294 | } | 290 | } |
295 | 291 | ||
296 | static int recv_pkt(struct sk_buff *skb, struct net_device *dev, | 292 | static int recv_pkt(struct sk_buff *skb, struct net_device *dev, |
@@ -477,7 +473,7 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev, | |||
477 | } | 473 | } |
478 | } | 474 | } |
479 | 475 | ||
480 | daddr = peer->eui64_addr; | 476 | daddr = peer->lladdr; |
481 | *peer_addr = addr; | 477 | *peer_addr = addr; |
482 | *peer_addr_type = addr_type; | 478 | *peer_addr_type = addr_type; |
483 | lowpan_cb(skb)->chan = peer->chan; | 479 | lowpan_cb(skb)->chan = peer->chan; |
@@ -663,27 +659,6 @@ static struct device_type bt_type = { | |||
663 | .name = "bluetooth", | 659 | .name = "bluetooth", |
664 | }; | 660 | }; |
665 | 661 | ||
666 | static void set_addr(u8 *eui, u8 *addr, u8 addr_type) | ||
667 | { | ||
668 | /* addr is the BT address in little-endian format */ | ||
669 | eui[0] = addr[5]; | ||
670 | eui[1] = addr[4]; | ||
671 | eui[2] = addr[3]; | ||
672 | eui[3] = 0xFF; | ||
673 | eui[4] = 0xFE; | ||
674 | eui[5] = addr[2]; | ||
675 | eui[6] = addr[1]; | ||
676 | eui[7] = addr[0]; | ||
677 | |||
678 | /* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */ | ||
679 | if (addr_type == BDADDR_LE_PUBLIC) | ||
680 | eui[0] &= ~0x02; | ||
681 | else | ||
682 | eui[0] |= 0x02; | ||
683 | |||
684 | BT_DBG("type %d addr %*phC", addr_type, 8, eui); | ||
685 | } | ||
686 | |||
687 | static void ifup(struct net_device *netdev) | 662 | static void ifup(struct net_device *netdev) |
688 | { | 663 | { |
689 | int err; | 664 | int err; |
@@ -762,14 +737,9 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, | |||
762 | peer->chan = chan; | 737 | peer->chan = chan; |
763 | memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); | 738 | memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); |
764 | 739 | ||
765 | /* RFC 2464 ch. 5 */ | 740 | baswap((void *)peer->lladdr, &chan->dst); |
766 | peer->peer_addr.s6_addr[0] = 0xFE; | ||
767 | peer->peer_addr.s6_addr[1] = 0x80; | ||
768 | set_addr((u8 *)&peer->peer_addr.s6_addr + 8, chan->dst.b, | ||
769 | chan->dst_type); | ||
770 | 741 | ||
771 | memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, | 742 | lowpan_iphc_uncompress_eui48_lladdr(&peer->peer_addr, peer->lladdr); |
772 | EUI64_ADDR_LEN); | ||
773 | 743 | ||
774 | /* IPv6 address needs to have the U/L bit set properly so toggle | 744 | /* IPv6 address needs to have the U/L bit set properly so toggle |
775 | * it back here. | 745 | * it back here. |