aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Aring <aar@pengutronix.de>2016-06-15 15:20:27 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-15 23:41:24 -0400
commiteab560e58208730ec47e1e0461b8db1049d5d176 (patch)
treefd09b3276c17b4e3dcc8b81197e6a58b3561cc7b
parentcfce94653dad2d0661e1926c028ce63052eb20cd (diff)
6lowpan: add support for 802.15.4 short addr handling
This patch adds necessary handling for use the short address for 802.15.4 6lowpan. It contains support for IPHC address compression and new matching algorithmn to decide which link layer address will be used for 802.15.4 frame. 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--net/6lowpan/iphc.c167
-rw-r--r--net/ieee802154/6lowpan/tx.c113
2 files changed, 195 insertions, 85 deletions
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index 8501dd532fe1..79f1fa22509a 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -761,22 +761,75 @@ static const u8 lowpan_iphc_dam_to_sam_value[] = {
761 [LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11, 761 [LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11,
762}; 762};
763 763
764static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct in6_addr *ipaddr, 764static inline bool
765lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr,
766 const struct lowpan_iphc_ctx *ctx,
767 const void *lladdr)
768{
769 const struct ieee802154_addr *addr = lladdr;
770 unsigned char extended_addr[EUI64_ADDR_LEN];
771 bool lladdr_compress = false;
772 struct in6_addr tmp = {};
773
774 switch (addr->mode) {
775 case IEEE802154_ADDR_LONG:
776 ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
777 /* check for SAM/DAM = 11 */
778 memcpy(&tmp.s6_addr[8], &extended_addr, EUI64_ADDR_LEN);
779 /* second bit-flip (Universe/Local) is done according RFC2464 */
780 tmp.s6_addr[8] ^= 0x02;
781 /* context information are always used */
782 ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
783 if (ipv6_addr_equal(&tmp, ipaddr))
784 lladdr_compress = true;
785 break;
786 case IEEE802154_ADDR_SHORT:
787 tmp.s6_addr[11] = 0xFF;
788 tmp.s6_addr[12] = 0xFE;
789 ieee802154_le16_to_be16(&tmp.s6_addr16[7],
790 &addr->short_addr);
791 /* context information are always used */
792 ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
793 if (ipv6_addr_equal(&tmp, ipaddr))
794 lladdr_compress = true;
795 break;
796 default:
797 /* should never handled and filtered by 802154 6lowpan */
798 WARN_ON_ONCE(1);
799 break;
800 }
801
802 return lladdr_compress;
803}
804
805static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
806 const struct in6_addr *ipaddr,
765 const struct lowpan_iphc_ctx *ctx, 807 const struct lowpan_iphc_ctx *ctx,
766 const unsigned char *lladdr, bool sam) 808 const unsigned char *lladdr, bool sam)
767{ 809{
768 struct in6_addr tmp = {}; 810 struct in6_addr tmp = {};
769 u8 dam; 811 u8 dam;
770 812
771 /* check for SAM/DAM = 11 */ 813 switch (lowpan_dev(dev)->lltype) {
772 memcpy(&tmp.s6_addr[8], lladdr, 8); 814 case LOWPAN_LLTYPE_IEEE802154:
773 /* second bit-flip (Universe/Local) is done according RFC2464 */ 815 if (lowpan_iphc_compress_ctx_802154_lladdr(ipaddr, ctx,
774 tmp.s6_addr[8] ^= 0x02; 816 lladdr)) {
775 /* context information are always used */ 817 dam = LOWPAN_IPHC_DAM_11;
776 ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); 818 goto out;
777 if (ipv6_addr_equal(&tmp, ipaddr)) { 819 }
778 dam = LOWPAN_IPHC_DAM_11; 820 break;
779 goto out; 821 default:
822 /* check for SAM/DAM = 11 */
823 memcpy(&tmp.s6_addr[8], lladdr, EUI64_ADDR_LEN);
824 /* second bit-flip (Universe/Local) is done according RFC2464 */
825 tmp.s6_addr[8] ^= 0x02;
826 /* context information are always used */
827 ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
828 if (ipv6_addr_equal(&tmp, ipaddr)) {
829 dam = LOWPAN_IPHC_DAM_11;
830 goto out;
831 }
832 break;
780 } 833 }
781 834
782 memset(&tmp, 0, sizeof(tmp)); 835 memset(&tmp, 0, sizeof(tmp));
@@ -813,28 +866,85 @@ out:
813 return dam; 866 return dam;
814} 867}
815 868
816static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct in6_addr *ipaddr, 869static inline bool
870lowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr,
871 const void *lladdr)
872{
873 const struct ieee802154_addr *addr = lladdr;
874 unsigned char extended_addr[EUI64_ADDR_LEN];
875 bool lladdr_compress = false;
876 struct in6_addr tmp = {};
877
878 switch (addr->mode) {
879 case IEEE802154_ADDR_LONG:
880 ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
881 if (is_addr_mac_addr_based(ipaddr, extended_addr))
882 lladdr_compress = true;
883 break;
884 case IEEE802154_ADDR_SHORT:
885 /* fe:80::ff:fe00:XXXX
886 * \__/
887 * short_addr
888 *
889 * Universe/Local bit is zero.
890 */
891 tmp.s6_addr[0] = 0xFE;
892 tmp.s6_addr[1] = 0x80;
893 tmp.s6_addr[11] = 0xFF;
894 tmp.s6_addr[12] = 0xFE;
895 ieee802154_le16_to_be16(&tmp.s6_addr16[7],
896 &addr->short_addr);
897 if (ipv6_addr_equal(&tmp, ipaddr))
898 lladdr_compress = true;
899 break;
900 default:
901 /* should never handled and filtered by 802154 6lowpan */
902 WARN_ON_ONCE(1);
903 break;
904 }
905
906 return lladdr_compress;
907}
908
909static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
910 const struct in6_addr *ipaddr,
817 const unsigned char *lladdr, bool sam) 911 const unsigned char *lladdr, bool sam)
818{ 912{
819 u8 dam = LOWPAN_IPHC_DAM_00; 913 u8 dam = LOWPAN_IPHC_DAM_01;
820 914
821 if (is_addr_mac_addr_based(ipaddr, lladdr)) { 915 switch (lowpan_dev(dev)->lltype) {
822 dam = LOWPAN_IPHC_DAM_11; /* 0-bits */ 916 case LOWPAN_LLTYPE_IEEE802154:
823 pr_debug("address compression 0 bits\n"); 917 if (lowpan_iphc_compress_802154_lladdr(ipaddr, lladdr)) {
824 } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) { 918 dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
919 pr_debug("address compression 0 bits\n");
920 goto out;
921 }
922 break;
923 default:
924 if (is_addr_mac_addr_based(ipaddr, lladdr)) {
925 dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
926 pr_debug("address compression 0 bits\n");
927 goto out;
928 }
929 break;
930 }
931
932 if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
825 /* compress IID to 16 bits xxxx::XXXX */ 933 /* compress IID to 16 bits xxxx::XXXX */
826 lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2); 934 lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
827 dam = LOWPAN_IPHC_DAM_10; /* 16-bits */ 935 dam = LOWPAN_IPHC_DAM_10; /* 16-bits */
828 raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", 936 raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
829 *hc_ptr - 2, 2); 937 *hc_ptr - 2, 2);
830 } else { 938 goto out;
831 /* do not compress IID => xxxx::IID */
832 lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
833 dam = LOWPAN_IPHC_DAM_01; /* 64-bits */
834 raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
835 *hc_ptr - 8, 8);
836 } 939 }
837 940
941 /* do not compress IID => xxxx::IID */
942 lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
943 raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
944 *hc_ptr - 8, 8);
945
946out:
947
838 if (sam) 948 if (sam)
839 return lowpan_iphc_dam_to_sam_value[dam]; 949 return lowpan_iphc_dam_to_sam_value[dam];
840 else 950 else
@@ -1013,9 +1123,6 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
1013 iphc0 = LOWPAN_DISPATCH_IPHC; 1123 iphc0 = LOWPAN_DISPATCH_IPHC;
1014 iphc1 = 0; 1124 iphc1 = 0;
1015 1125
1016 raw_dump_inline(__func__, "saddr", saddr, EUI64_ADDR_LEN);
1017 raw_dump_inline(__func__, "daddr", daddr, EUI64_ADDR_LEN);
1018
1019 raw_dump_table(__func__, "sending raw skb network uncompressed packet", 1126 raw_dump_table(__func__, "sending raw skb network uncompressed packet",
1020 skb->data, skb->len); 1127 skb->data, skb->len);
1021 1128
@@ -1088,14 +1195,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
1088 iphc1 |= LOWPAN_IPHC_SAC; 1195 iphc1 |= LOWPAN_IPHC_SAC;
1089 } else { 1196 } else {
1090 if (sci) { 1197 if (sci) {
1091 iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->saddr, 1198 iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
1199 &hdr->saddr,
1092 &sci_entry, saddr, 1200 &sci_entry, saddr,
1093 true); 1201 true);
1094 iphc1 |= LOWPAN_IPHC_SAC; 1202 iphc1 |= LOWPAN_IPHC_SAC;
1095 } else { 1203 } else {
1096 if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL && 1204 if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL &&
1097 lowpan_is_linklocal_zero_padded(hdr->saddr)) { 1205 lowpan_is_linklocal_zero_padded(hdr->saddr)) {
1098 iphc1 |= lowpan_compress_addr_64(&hc_ptr, 1206 iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
1099 &hdr->saddr, 1207 &hdr->saddr,
1100 saddr, true); 1208 saddr, true);
1101 pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n", 1209 pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
@@ -1123,14 +1231,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
1123 } 1231 }
1124 } else { 1232 } else {
1125 if (dci) { 1233 if (dci) {
1126 iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->daddr, 1234 iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
1235 &hdr->daddr,
1127 &dci_entry, daddr, 1236 &dci_entry, daddr,
1128 false); 1237 false);
1129 iphc1 |= LOWPAN_IPHC_DAC; 1238 iphc1 |= LOWPAN_IPHC_DAC;
1130 } else { 1239 } else {
1131 if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL && 1240 if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL &&
1132 lowpan_is_linklocal_zero_padded(hdr->daddr)) { 1241 lowpan_is_linklocal_zero_padded(hdr->daddr)) {
1133 iphc1 |= lowpan_compress_addr_64(&hc_ptr, 1242 iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
1134 &hdr->daddr, 1243 &hdr->daddr,
1135 daddr, false); 1244 daddr, false);
1136 pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x\n", 1245 pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x\n",
diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
index e459afd16bb3..dbb476d7d38f 100644
--- a/net/ieee802154/6lowpan/tx.c
+++ b/net/ieee802154/6lowpan/tx.c
@@ -9,6 +9,7 @@
9 */ 9 */
10 10
11#include <net/6lowpan.h> 11#include <net/6lowpan.h>
12#include <net/ndisc.h>
12#include <net/ieee802154_netdev.h> 13#include <net/ieee802154_netdev.h>
13#include <net/mac802154.h> 14#include <net/mac802154.h>
14 15
@@ -17,19 +18,9 @@
17#define LOWPAN_FRAG1_HEAD_SIZE 0x4 18#define LOWPAN_FRAG1_HEAD_SIZE 0x4
18#define LOWPAN_FRAGN_HEAD_SIZE 0x5 19#define LOWPAN_FRAGN_HEAD_SIZE 0x5
19 20
20/* don't save pan id, it's intra pan */
21struct lowpan_addr {
22 u8 mode;
23 union {
24 /* IPv6 needs big endian here */
25 __be64 extended_addr;
26 __be16 short_addr;
27 } u;
28};
29
30struct lowpan_addr_info { 21struct lowpan_addr_info {
31 struct lowpan_addr daddr; 22 struct ieee802154_addr daddr;
32 struct lowpan_addr saddr; 23 struct ieee802154_addr saddr;
33}; 24};
34 25
35static inline struct 26static inline struct
@@ -48,12 +39,14 @@ lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
48 * RAW/DGRAM sockets. 39 * RAW/DGRAM sockets.
49 */ 40 */
50int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev, 41int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
51 unsigned short type, const void *_daddr, 42 unsigned short type, const void *daddr,
52 const void *_saddr, unsigned int len) 43 const void *saddr, unsigned int len)
53{ 44{
54 const u8 *saddr = _saddr; 45 struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
55 const u8 *daddr = _daddr; 46 struct lowpan_addr_info *info = lowpan_skb_priv(skb);
56 struct lowpan_addr_info *info; 47 struct lowpan_802154_neigh *llneigh = NULL;
48 const struct ipv6hdr *hdr = ipv6_hdr(skb);
49 struct neighbour *n;
57 50
58 /* TODO: 51 /* TODO:
59 * if this package isn't ipv6 one, where should it be routed? 52 * if this package isn't ipv6 one, where should it be routed?
@@ -61,21 +54,50 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
61 if (type != ETH_P_IPV6) 54 if (type != ETH_P_IPV6)
62 return 0; 55 return 0;
63 56
64 if (!saddr) 57 /* intra-pan communication */
65 saddr = ldev->dev_addr; 58 info->saddr.pan_id = wpan_dev->pan_id;
59 info->daddr.pan_id = info->saddr.pan_id;
66 60
67 raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8); 61 if (!memcmp(daddr, ldev->broadcast, EUI64_ADDR_LEN)) {
68 raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8); 62 info->daddr.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
63 info->daddr.mode = IEEE802154_ADDR_SHORT;
64 } else {
65 __le16 short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
66
67 n = neigh_lookup(&nd_tbl, &hdr->daddr, ldev);
68 if (n) {
69 llneigh = lowpan_802154_neigh(neighbour_priv(n));
70 read_lock_bh(&n->lock);
71 short_addr = llneigh->short_addr;
72 read_unlock_bh(&n->lock);
73 }
69 74
70 info = lowpan_skb_priv(skb); 75 if (llneigh &&
76 lowpan_802154_is_valid_src_short_addr(short_addr)) {
77 info->daddr.short_addr = short_addr;
78 info->daddr.mode = IEEE802154_ADDR_SHORT;
79 } else {
80 info->daddr.mode = IEEE802154_ADDR_LONG;
81 ieee802154_be64_to_le64(&info->daddr.extended_addr,
82 daddr);
83 }
71 84
72 /* TODO: Currently we only support extended_addr */ 85 if (n)
73 info->daddr.mode = IEEE802154_ADDR_LONG; 86 neigh_release(n);
74 memcpy(&info->daddr.u.extended_addr, daddr, 87 }
75 sizeof(info->daddr.u.extended_addr)); 88
76 info->saddr.mode = IEEE802154_ADDR_LONG; 89 if (!saddr) {
77 memcpy(&info->saddr.u.extended_addr, saddr, 90 if (lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr)) {
78 sizeof(info->daddr.u.extended_addr)); 91 info->saddr.mode = IEEE802154_ADDR_SHORT;
92 info->saddr.short_addr = wpan_dev->short_addr;
93 } else {
94 info->saddr.mode = IEEE802154_ADDR_LONG;
95 info->saddr.extended_addr = wpan_dev->extended_addr;
96 }
97 } else {
98 info->saddr.mode = IEEE802154_ADDR_LONG;
99 ieee802154_be64_to_le64(&info->saddr.extended_addr, saddr);
100 }
79 101
80 return 0; 102 return 0;
81} 103}
@@ -209,47 +231,26 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
209 u16 *dgram_size, u16 *dgram_offset) 231 u16 *dgram_size, u16 *dgram_offset)
210{ 232{
211 struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr; 233 struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
212 struct ieee802154_addr sa, da;
213 struct ieee802154_mac_cb *cb = mac_cb_init(skb); 234 struct ieee802154_mac_cb *cb = mac_cb_init(skb);
214 struct lowpan_addr_info info; 235 struct lowpan_addr_info info;
215 void *daddr, *saddr;
216 236
217 memcpy(&info, lowpan_skb_priv(skb), sizeof(info)); 237 memcpy(&info, lowpan_skb_priv(skb), sizeof(info));
218 238
219 /* TODO: Currently we only support extended_addr */
220 daddr = &info.daddr.u.extended_addr;
221 saddr = &info.saddr.u.extended_addr;
222
223 *dgram_size = skb->len; 239 *dgram_size = skb->len;
224 lowpan_header_compress(skb, ldev, daddr, saddr); 240 lowpan_header_compress(skb, ldev, &info.daddr, &info.saddr);
225 /* dgram_offset = (saved bytes after compression) + lowpan header len */ 241 /* dgram_offset = (saved bytes after compression) + lowpan header len */
226 *dgram_offset = (*dgram_size - skb->len) + skb_network_header_len(skb); 242 *dgram_offset = (*dgram_size - skb->len) + skb_network_header_len(skb);
227 243
228 cb->type = IEEE802154_FC_TYPE_DATA; 244 cb->type = IEEE802154_FC_TYPE_DATA;
229 245
230 /* prepare wpan address data */ 246 if (info.daddr.mode == IEEE802154_ADDR_SHORT &&
231 sa.mode = IEEE802154_ADDR_LONG; 247 ieee802154_is_broadcast_short_addr(info.daddr.short_addr))
232 sa.pan_id = wpan_dev->pan_id;
233 sa.extended_addr = ieee802154_devaddr_from_raw(saddr);
234
235 /* intra-PAN communications */
236 da.pan_id = sa.pan_id;
237
238 /* if the destination address is the broadcast address, use the
239 * corresponding short address
240 */
241 if (!memcmp(daddr, ldev->broadcast, EUI64_ADDR_LEN)) {
242 da.mode = IEEE802154_ADDR_SHORT;
243 da.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
244 cb->ackreq = false; 248 cb->ackreq = false;
245 } else { 249 else
246 da.mode = IEEE802154_ADDR_LONG;
247 da.extended_addr = ieee802154_devaddr_from_raw(daddr);
248 cb->ackreq = wpan_dev->ackreq; 250 cb->ackreq = wpan_dev->ackreq;
249 }
250 251
251 return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev, &da, 252 return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev,
252 &sa, 0); 253 &info.daddr, &info.saddr, 0);
253} 254}
254 255
255netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev) 256netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)