aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
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