Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Luiz Augusto von Dentz and committed by
Marcel Holtmann
fa09ae66 8a7a4b47

+63 -47
+19
include/net/6lowpan.h
··· 198 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 220 #ifdef DEBUG 202 221 /* print data in line */ 203 222 static inline void raw_dump_inline(const char *caller, char *msg,
+38 -11
net/6lowpan/iphc.c
··· 278 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 298 /* Uncompress address function for source and 282 299 * destination address(non-multicast). 283 300 * ··· 337 320 lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); 338 321 break; 339 322 default: 340 - lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); 323 + lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr); 341 324 break; 342 325 } 343 326 break; ··· 398 381 lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); 399 382 break; 400 383 default: 401 - lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); 384 + lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr); 402 385 break; 403 386 } 404 387 ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); ··· 827 810 return lladdr_compress; 828 811 } 829 812 813 + static bool lowpan_iphc_addr_equal(const struct net_device *dev, 814 + const struct lowpan_iphc_ctx *ctx, 815 + const struct in6_addr *ipaddr, 816 + const void *lladdr) 817 + { 818 + struct in6_addr tmp = {}; 819 + 820 + lowpan_iphc_uncompress_lladdr(dev, &tmp, lladdr); 821 + 822 + if (ctx) 823 + ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); 824 + 825 + return ipv6_addr_equal(&tmp, ipaddr); 826 + } 827 + 830 828 static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev, 831 829 const struct in6_addr *ipaddr, 832 830 const struct lowpan_iphc_ctx *ctx, ··· 859 827 } 860 828 break; 861 829 default: 862 - /* check for SAM/DAM = 11 */ 863 - memcpy(&tmp.s6_addr[8], lladdr, EUI64_ADDR_LEN); 864 - /* second bit-flip (Universe/Local) is done according RFC2464 */ 865 - tmp.s6_addr[8] ^= 0x02; 866 - /* context information are always used */ 867 - ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); 868 - if (ipv6_addr_equal(&tmp, ipaddr)) { 830 + if (lowpan_iphc_addr_equal(dev, ctx, ipaddr, lladdr)) { 869 831 dam = LOWPAN_IPHC_DAM_11; 870 832 goto out; 871 833 } ··· 955 929 } 956 930 break; 957 931 default: 958 - if (is_addr_mac_addr_based(ipaddr, lladdr)) { 959 - dam = LOWPAN_IPHC_DAM_11; /* 0-bits */ 932 + if (lowpan_iphc_addr_equal(dev, NULL, ipaddr, lladdr)) { 933 + dam = LOWPAN_IPHC_DAM_11; 960 934 pr_debug("address compression 0 bits\n"); 961 935 goto out; 962 936 } 937 + 963 938 break; 964 939 } 965 940
+6 -36
net/bluetooth/6lowpan.c
··· 64 64 struct l2cap_chan *chan; 65 65 66 66 /* peer addresses in various formats */ 67 - unsigned char eui64_addr[EUI64_ADDR_LEN]; 67 + unsigned char lladdr[ETH_ALEN]; 68 68 struct in6_addr peer_addr; 69 69 }; 70 70 ··· 79 79 struct work_struct delete_netdev; 80 80 struct delayed_work notify_peers; 81 81 }; 82 - 83 - static void set_addr(u8 *eui, u8 *addr, u8 addr_type); 84 82 85 83 static inline struct lowpan_btle_dev * 86 84 lowpan_btle_dev(const struct net_device *netdev) ··· 275 277 const u8 *saddr; 276 278 struct lowpan_btle_dev *dev; 277 279 struct lowpan_peer *peer; 278 - unsigned char eui64_daddr[EUI64_ADDR_LEN]; 279 280 280 281 dev = lowpan_btle_dev(netdev); 281 282 ··· 284 287 if (!peer) 285 288 return -EINVAL; 286 289 287 - saddr = peer->eui64_addr; 288 - set_addr(&eui64_daddr[0], chan->src.b, chan->src_type); 290 + saddr = peer->lladdr; 289 291 290 - return lowpan_header_decompress(skb, netdev, &eui64_daddr, saddr); 292 + return lowpan_header_decompress(skb, netdev, netdev->dev_addr, saddr); 291 293 } 292 294 293 295 static int recv_pkt(struct sk_buff *skb, struct net_device *dev, ··· 473 477 } 474 478 } 475 479 476 - daddr = peer->eui64_addr; 480 + daddr = peer->lladdr; 477 481 *peer_addr = addr; 478 482 *peer_addr_type = addr_type; 479 483 lowpan_cb(skb)->chan = peer->chan; ··· 659 663 .name = "bluetooth", 660 664 }; 661 665 662 - static void set_addr(u8 *eui, u8 *addr, u8 addr_type) 663 - { 664 - /* addr is the BT address in little-endian format */ 665 - eui[0] = addr[5]; 666 - eui[1] = addr[4]; 667 - eui[2] = addr[3]; 668 - eui[3] = 0xFF; 669 - eui[4] = 0xFE; 670 - eui[5] = addr[2]; 671 - eui[6] = addr[1]; 672 - eui[7] = addr[0]; 673 - 674 - /* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */ 675 - if (addr_type == BDADDR_LE_PUBLIC) 676 - eui[0] &= ~0x02; 677 - else 678 - eui[0] |= 0x02; 679 - 680 - BT_DBG("type %d addr %*phC", addr_type, 8, eui); 681 - } 682 - 683 666 static void ifup(struct net_device *netdev) 684 667 { 685 668 int err; ··· 737 762 peer->chan = chan; 738 763 memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); 739 764 740 - /* RFC 2464 ch. 5 */ 741 - peer->peer_addr.s6_addr[0] = 0xFE; 742 - peer->peer_addr.s6_addr[1] = 0x80; 743 - set_addr((u8 *)&peer->peer_addr.s6_addr + 8, chan->dst.b, 744 - chan->dst_type); 765 + baswap((void *)peer->lladdr, &chan->dst); 745 766 746 - memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, 747 - EUI64_ADDR_LEN); 767 + lowpan_iphc_uncompress_eui48_lladdr(&peer->peer_addr, peer->lladdr); 748 768 749 769 /* IPv6 address needs to have the U/L bit set properly so toggle 750 770 * it back here.