diff options
Diffstat (limited to 'net/ieee802154')
-rw-r--r-- | net/ieee802154/6lowpan.c | 145 | ||||
-rw-r--r-- | net/ieee802154/6lowpan.h | 8 |
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 | ||
68 | static LIST_HEAD(lowpan_devices); | 68 | static 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 | */ | ||
80 | static 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 | */ | ||
89 | static const u8 lowpan_unc_ctxconf[] = {0x00, 0x88, 0x82, 0x80}; | ||
90 | |||
91 | /* Link local prefix */ | ||
92 | static const u8 lowpan_llprefix[] = {0xfe, 0x80}; | ||
93 | |||
94 | /* private device info */ | 70 | /* private device info */ |
95 | struct lowpan_dev_info { | 71 | struct 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 | ||
185 | static void | ||
186 | lowpan_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 | */ |
200 | static int | 167 | static int |
201 | lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr, | 168 | lowpan_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 |