aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
authorAlexander Aring <alex.aring@gmail.com>2013-08-16 15:59:58 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-20 16:23:12 -0400
commitce2463b283a0cb63e0e4de5e7d971b4c92be542a (patch)
tree53ffb342699069a3a9da9b12d0e8974b26782565 /net/ieee802154
parent84c2e7bcf531a3881d602035243eda80e62d700a (diff)
6lowpan: lowpan_uncompress_addr with address_mode
This patch drops the pre and postcount calculation from the lowpan_uncompress_addr function.We use instead a switch/case over address_mode value. The original implementation has several bugs in this function and it was hard to decrypt how it works. To make it maintainable and fix these bugs this patch basically reimplements lowpan_uncompress_addr from scratch. A list of bugs we found in the current implementation: 1) Properly support uncompression of short-address based IPv6 addresses (instead of basically copying garbage) 2) Fix use and uncompression of long-addresses based IPv6 addresses 3) Add missing ff:fe00 in the case of SAM/DAM = 2 and M = 0 Signed-off-by: Alexander Aring <alex.aring@gmail.com> Reviewed-by: Werner Almesberger <werner@almesberger.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ieee802154')
-rw-r--r--net/ieee802154/6lowpan.c145
-rw-r--r--net/ieee802154/6lowpan.h8
2 files changed, 82 insertions, 71 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 9aea7ce8b83d..5ef9157c5f1b 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -67,30 +67,6 @@ static const u8 lowpan_ttl_values[] = {0, 1, 64, 255};
67 67
68static LIST_HEAD(lowpan_devices); 68static LIST_HEAD(lowpan_devices);
69 69
70/*
71 * Uncompression of linklocal:
72 * 0 -> 16 bytes from packet
73 * 1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet
74 * 2 -> 2 bytes from prefix - zeroes + 2 from packet
75 * 3 -> 2 bytes from prefix - infer 8 bytes from lladdr
76 *
77 * NOTE: => the uncompress function does change 0xf to 0x10
78 * NOTE: 0x00 => no-autoconfig => unspecified
79 */
80static const u8 lowpan_unc_llconf[] = {0x0f, 0x28, 0x22, 0x20};
81
82/*
83 * Uncompression of ctx-based:
84 * 0 -> 0 bits from packet [unspecified / reserved]
85 * 1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet
86 * 2 -> 8 bytes from prefix - zeroes + 2 from packet
87 * 3 -> 8 bytes from prefix - infer 8 bytes from lladdr
88 */
89static const u8 lowpan_unc_ctxconf[] = {0x00, 0x88, 0x82, 0x80};
90
91/* Link local prefix */
92static const u8 lowpan_llprefix[] = {0xfe, 0x80};
93
94/* private device info */ 70/* private device info */
95struct lowpan_dev_info { 71struct lowpan_dev_info {
96 struct net_device *real_dev; /* real WPAN device ptr */ 72 struct net_device *real_dev; /* real WPAN device ptr */
@@ -182,51 +158,86 @@ lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr,
182 return rol8(val, shift); 158 return rol8(val, shift);
183} 159}
184 160
185static void
186lowpan_uip_ds6_set_addr_iid(struct in6_addr *ipaddr, unsigned char *lladdr)
187{
188 memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ADDR_LEN);
189 /* second bit-flip (Universe/Local) is done according RFC2464 */
190 ipaddr->s6_addr[8] ^= 0x02;
191}
192
193/* 161/*
194 * Uncompress addresses based on a prefix and a postfix with zeroes in 162 * Uncompress address function for source and
195 * between. If the postfix is zero in length it will use the link address 163 * destination address(non-multicast).
196 * to configure the IP address (autoconf style). 164 *
197 * pref_post_count takes a byte where the first nibble specify prefix count 165 * address_mode is sam value or dam value.
198 * and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
199 */ 166 */
200static int 167static int
201lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr, 168lowpan_uncompress_addr(struct sk_buff *skb,
202 u8 const *prefix, u8 pref_post_count, unsigned char *lladdr) 169 struct in6_addr *ipaddr,
170 const u8 address_mode,
171 const struct ieee802154_addr *lladdr)
203{ 172{
204 u8 prefcount = pref_post_count >> 4; 173 bool fail;
205 u8 postcount = pref_post_count & 0x0f; 174
206 175 switch (address_mode) {
207 /* full nibble 15 => 16 */ 176 case LOWPAN_IPHC_ADDR_00:
208 prefcount = (prefcount == 15 ? 16 : prefcount); 177 /* for global link addresses */
209 postcount = (postcount == 15 ? 16 : postcount); 178 fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
210 179 break;
211 if (lladdr) 180 case LOWPAN_IPHC_ADDR_01:
212 lowpan_raw_dump_inline(__func__, "linklocal address", 181 /* fe:80::XXXX:XXXX:XXXX:XXXX */
213 lladdr, IEEE802154_ADDR_LEN); 182 ipaddr->s6_addr[0] = 0xFE;
214 if (prefcount > 0) 183 ipaddr->s6_addr[1] = 0x80;
215 memcpy(ipaddr, prefix, prefcount); 184 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
216 185 break;
217 if (postcount > 0) { 186 case LOWPAN_IPHC_ADDR_02:
218 memcpy(&ipaddr->s6_addr[16 - postcount], skb->data, postcount); 187 /* fe:80::ff:fe00:XXXX */
219 skb_pull(skb, postcount); 188 ipaddr->s6_addr[0] = 0xFE;
220 } else if (prefcount > 0) { 189 ipaddr->s6_addr[1] = 0x80;
221 if (lladdr == NULL) 190 ipaddr->s6_addr[11] = 0xFF;
191 ipaddr->s6_addr[12] = 0xFE;
192 fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
193 break;
194 case LOWPAN_IPHC_ADDR_03:
195 fail = false;
196 switch (lladdr->addr_type) {
197 case IEEE802154_ADDR_LONG:
198 /* fe:80::XXXX:XXXX:XXXX:XXXX
199 * \_________________/
200 * hwaddr
201 */
202 ipaddr->s6_addr[0] = 0xFE;
203 ipaddr->s6_addr[1] = 0x80;
204 memcpy(&ipaddr->s6_addr[8], lladdr->hwaddr,
205 IEEE802154_ADDR_LEN);
206 /* second bit-flip (Universe/Local)
207 * is done according RFC2464
208 */
209 ipaddr->s6_addr[8] ^= 0x02;
210 break;
211 case IEEE802154_ADDR_SHORT:
212 /* fe:80::ff:fe00:XXXX
213 * \__/
214 * short_addr
215 *
216 * Universe/Local bit is zero.
217 */
218 ipaddr->s6_addr[0] = 0xFE;
219 ipaddr->s6_addr[1] = 0x80;
220 ipaddr->s6_addr[11] = 0xFF;
221 ipaddr->s6_addr[12] = 0xFE;
222 ipaddr->s6_addr16[7] = htons(lladdr->short_addr);
223 break;
224 default:
225 pr_debug("Invalid addr_type set\n");
222 return -EINVAL; 226 return -EINVAL;
227 }
228 break;
229 default:
230 pr_debug("Invalid address mode value: 0x%x\n", address_mode);
231 return -EINVAL;
232 }
223 233
224 /* no IID based configuration if no prefix and no data */ 234 if (fail) {
225 lowpan_uip_ds6_set_addr_iid(ipaddr, lladdr); 235 pr_debug("Failed to fetch skb data\n");
236 return -EIO;
226 } 237 }
227 238
228 pr_debug("uncompressing %d + %d => ", prefcount, postcount); 239 lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 addr is:\n",
229 lowpan_raw_dump_inline(NULL, NULL, ipaddr->s6_addr, 16); 240 ipaddr->s6_addr, 16);
230 241
231 return 0; 242 return 0;
232} 243}
@@ -775,7 +786,7 @@ lowpan_process_data(struct sk_buff *skb)
775{ 786{
776 struct ipv6hdr hdr = {}; 787 struct ipv6hdr hdr = {};
777 u8 tmp, iphc0, iphc1, num_context = 0; 788 u8 tmp, iphc0, iphc1, num_context = 0;
778 u8 *_saddr, *_daddr; 789 const struct ieee802154_addr *_saddr, *_daddr;
779 int err; 790 int err;
780 791
781 lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data, 792 lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
@@ -878,8 +889,8 @@ lowpan_process_data(struct sk_buff *skb)
878 if (lowpan_fetch_skb_u8(skb, &iphc1)) 889 if (lowpan_fetch_skb_u8(skb, &iphc1))
879 goto drop; 890 goto drop;
880 891
881 _saddr = mac_cb(skb)->sa.hwaddr; 892 _saddr = &mac_cb(skb)->sa;
882 _daddr = mac_cb(skb)->da.hwaddr; 893 _daddr = &mac_cb(skb)->da;
883 894
884 pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1); 895 pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1);
885 896
@@ -961,8 +972,7 @@ lowpan_process_data(struct sk_buff *skb)
961 972
962 /* Source address uncompression */ 973 /* Source address uncompression */
963 pr_debug("source address stateless compression\n"); 974 pr_debug("source address stateless compression\n");
964 err = lowpan_uncompress_addr(skb, &hdr.saddr, lowpan_llprefix, 975 err = lowpan_uncompress_addr(skb, &hdr.saddr, tmp, _saddr);
965 lowpan_unc_llconf[tmp], skb->data);
966 if (err) 976 if (err)
967 goto drop; 977 goto drop;
968 978
@@ -982,8 +992,7 @@ lowpan_process_data(struct sk_buff *skb)
982 } 992 }
983 } else { 993 } else {
984 pr_debug("dest: stateless compression\n"); 994 pr_debug("dest: stateless compression\n");
985 err = lowpan_uncompress_addr(skb, &hdr.daddr, lowpan_llprefix, 995 err = lowpan_uncompress_addr(skb, &hdr.daddr, tmp, _daddr);
986 lowpan_unc_llconf[tmp], skb->data);
987 if (err) 996 if (err)
988 goto drop; 997 goto drop;
989 } 998 }
diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
index a636545d8dcf..2869c0526dad 100644
--- a/net/ieee802154/6lowpan.h
+++ b/net/ieee802154/6lowpan.h
@@ -193,10 +193,12 @@
193/* Values of fields within the IPHC encoding second byte */ 193/* Values of fields within the IPHC encoding second byte */
194#define LOWPAN_IPHC_CID 0x80 194#define LOWPAN_IPHC_CID 0x80
195 195
196#define LOWPAN_IPHC_ADDR_00 0x00
197#define LOWPAN_IPHC_ADDR_01 0x01
198#define LOWPAN_IPHC_ADDR_02 0x02
199#define LOWPAN_IPHC_ADDR_03 0x03
200
196#define LOWPAN_IPHC_SAC 0x40 201#define LOWPAN_IPHC_SAC 0x40
197#define LOWPAN_IPHC_SAM_00 0x00
198#define LOWPAN_IPHC_SAM_01 0x10
199#define LOWPAN_IPHC_SAM_10 0x20
200#define LOWPAN_IPHC_SAM 0x30 202#define LOWPAN_IPHC_SAM 0x30
201 203
202#define LOWPAN_IPHC_SAM_BIT 4 204#define LOWPAN_IPHC_SAM_BIT 4