Blame view
net/6lowpan/iphc.c
36.7 KB
8df8c56a5 6lowpan: Moving g... |
1 2 3 4 |
/* * Copyright 2011, Siemens AG * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com> */ |
4710d806f 6lowpan: mac80215... |
5 |
/* Based on patches from Jon Smirl <jonsmirl@gmail.com> |
8df8c56a5 6lowpan: Moving g... |
6 7 8 9 10 11 12 13 14 15 16 |
* Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * |
8df8c56a5 6lowpan: Moving g... |
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
*/ /* Jon's code is based on 6lowpan implementation for Contiki which is: * Copyright (c) 2008, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include <linux/bitops.h> #include <linux/if_arp.h> #include <linux/netdevice.h> |
8911d7748 6lowpan: cleanup ... |
51 |
|
cefc8c8a7 6lowpan: move 6lo... |
52 |
#include <net/6lowpan.h> |
8df8c56a5 6lowpan: Moving g... |
53 |
#include <net/ipv6.h> |
8911d7748 6lowpan: cleanup ... |
54 |
|
5609c185f 6lowpan: iphc: ad... |
55 |
#include "6lowpan_i.h" |
cc6ed2684 6lowpan: add udp ... |
56 |
#include "nhc.h" |
c8a3e7eb9 6lowpan: iphc: ch... |
57 58 59 60 61 62 63 64 |
/* Values of fields within the IPHC encoding first byte */ #define LOWPAN_IPHC_TF_MASK 0x18 #define LOWPAN_IPHC_TF_00 0x00 #define LOWPAN_IPHC_TF_01 0x08 #define LOWPAN_IPHC_TF_10 0x10 #define LOWPAN_IPHC_TF_11 0x18 #define LOWPAN_IPHC_NH 0x04 |
6350047eb 6lowpan: move IPH... |
65 |
|
c8a3e7eb9 6lowpan: iphc: ch... |
66 67 68 69 70 |
#define LOWPAN_IPHC_HLIM_MASK 0x03 #define LOWPAN_IPHC_HLIM_00 0x00 #define LOWPAN_IPHC_HLIM_01 0x01 #define LOWPAN_IPHC_HLIM_10 0x02 #define LOWPAN_IPHC_HLIM_11 0x03 |
6350047eb 6lowpan: move IPH... |
71 72 73 |
/* Values of fields within the IPHC encoding second byte */ #define LOWPAN_IPHC_CID 0x80 |
6350047eb 6lowpan: move IPH... |
74 |
#define LOWPAN_IPHC_SAC 0x40 |
6350047eb 6lowpan: move IPH... |
75 |
|
c8a3e7eb9 6lowpan: iphc: ch... |
76 77 78 79 80 |
#define LOWPAN_IPHC_SAM_MASK 0x30 #define LOWPAN_IPHC_SAM_00 0x00 #define LOWPAN_IPHC_SAM_01 0x10 #define LOWPAN_IPHC_SAM_10 0x20 #define LOWPAN_IPHC_SAM_11 0x30 |
6350047eb 6lowpan: move IPH... |
81 82 |
#define LOWPAN_IPHC_M 0x08 |
c8a3e7eb9 6lowpan: iphc: ch... |
83 |
|
6350047eb 6lowpan: move IPH... |
84 |
#define LOWPAN_IPHC_DAC 0x04 |
c8a3e7eb9 6lowpan: iphc: ch... |
85 86 |
#define LOWPAN_IPHC_DAM_MASK 0x03 |
6350047eb 6lowpan: move IPH... |
87 88 89 90 |
#define LOWPAN_IPHC_DAM_00 0x00 #define LOWPAN_IPHC_DAM_01 0x01 #define LOWPAN_IPHC_DAM_10 0x02 #define LOWPAN_IPHC_DAM_11 0x03 |
6350047eb 6lowpan: move IPH... |
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
/* ipv6 address based on mac * second bit-flip (Universe/Local) is done according RFC2464 */ #define is_addr_mac_addr_based(a, m) \ ((((a)->s6_addr[8]) == (((m)[0]) ^ 0x02)) && \ (((a)->s6_addr[9]) == (m)[1]) && \ (((a)->s6_addr[10]) == (m)[2]) && \ (((a)->s6_addr[11]) == (m)[3]) && \ (((a)->s6_addr[12]) == (m)[4]) && \ (((a)->s6_addr[13]) == (m)[5]) && \ (((a)->s6_addr[14]) == (m)[6]) && \ (((a)->s6_addr[15]) == (m)[7])) /* check whether we can compress the IID to 16 bits, * it's possible for unicast addresses with first 49 bits are zero only. */ #define lowpan_is_iid_16_bit_compressable(a) \ ((((a)->s6_addr16[4]) == 0) && \ (((a)->s6_addr[10]) == 0) && \ (((a)->s6_addr[11]) == 0xff) && \ (((a)->s6_addr[12]) == 0xfe) && \ (((a)->s6_addr[13]) == 0)) /* check whether the 112-bit gid of the multicast address is mappable to: */ /* 48 bits, FFXX::00XX:XXXX:XXXX */ #define lowpan_is_mcast_addr_compressable48(a) \ ((((a)->s6_addr16[1]) == 0) && \ (((a)->s6_addr16[2]) == 0) && \ (((a)->s6_addr16[3]) == 0) && \ (((a)->s6_addr16[4]) == 0) && \ (((a)->s6_addr[10]) == 0)) /* 32 bits, FFXX::00XX:XXXX */ #define lowpan_is_mcast_addr_compressable32(a) \ ((((a)->s6_addr16[1]) == 0) && \ (((a)->s6_addr16[2]) == 0) && \ (((a)->s6_addr16[3]) == 0) && \ (((a)->s6_addr16[4]) == 0) && \ (((a)->s6_addr16[5]) == 0) && \ (((a)->s6_addr[12]) == 0)) /* 8 bits, FF02::00XX */ #define lowpan_is_mcast_addr_compressable8(a) \ ((((a)->s6_addr[1]) == 2) && \ (((a)->s6_addr16[1]) == 0) && \ (((a)->s6_addr16[2]) == 0) && \ (((a)->s6_addr16[3]) == 0) && \ (((a)->s6_addr16[4]) == 0) && \ (((a)->s6_addr16[5]) == 0) && \ (((a)->s6_addr16[6]) == 0) && \ (((a)->s6_addr[14]) == 0)) |
feb2add32 6lowpan: iphc: fi... |
143 144 145 146 |
#define lowpan_is_linklocal_zero_padded(a) \ (!(hdr->saddr.s6_addr[1] & 0x3f) && \ !hdr->saddr.s6_addr16[1] && \ !hdr->saddr.s6_addr32[1]) |
5609c185f 6lowpan: iphc: ad... |
147 148 |
#define LOWPAN_IPHC_CID_DCI(cid) (cid & 0x0f) #define LOWPAN_IPHC_CID_SCI(cid) ((cid & 0xf0) >> 4) |
7115a968b 6lowpan: iphc: re... |
149 150 151 |
static inline void lowpan_iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr, const void *lladdr) |
8911d7748 6lowpan: cleanup ... |
152 153 |
{ const struct ieee802154_addr *addr = lladdr; |
2bc068c3d 6lowpan: iphc: re... |
154 |
u8 eui64[EUI64_ADDR_LEN]; |
8911d7748 6lowpan: cleanup ... |
155 156 157 158 |
switch (addr->mode) { case IEEE802154_ADDR_LONG: ieee802154_le64_to_be64(eui64, &addr->extended_addr); |
7115a968b 6lowpan: iphc: re... |
159 |
lowpan_iphc_uncompress_eui64_lladdr(ipaddr, eui64); |
8911d7748 6lowpan: cleanup ... |
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
break; case IEEE802154_ADDR_SHORT: /* fe:80::ff:fe00:XXXX * \__/ * short_addr * * Universe/Local bit is zero. */ ipaddr->s6_addr[0] = 0xFE; ipaddr->s6_addr[1] = 0x80; ipaddr->s6_addr[11] = 0xFF; ipaddr->s6_addr[12] = 0xFE; ieee802154_le16_to_be16(&ipaddr->s6_addr16[7], &addr->short_addr); break; default: /* should never handled and filtered by 802154 6lowpan */ WARN_ON_ONCE(1); break; } } |
5609c185f 6lowpan: iphc: ad... |
181 182 183 |
static struct lowpan_iphc_ctx * lowpan_iphc_ctx_get_by_id(const struct net_device *dev, u8 id) { |
2e4d60cbc 6lowpan: change n... |
184 |
struct lowpan_iphc_ctx *ret = &lowpan_dev(dev)->ctx.table[id]; |
5609c185f 6lowpan: iphc: ad... |
185 186 187 188 189 190 191 192 193 194 195 |
if (!lowpan_iphc_ctx_is_active(ret)) return NULL; return ret; } static struct lowpan_iphc_ctx * lowpan_iphc_ctx_get_by_addr(const struct net_device *dev, const struct in6_addr *addr) { |
2e4d60cbc 6lowpan: change n... |
196 |
struct lowpan_iphc_ctx *table = lowpan_dev(dev)->ctx.table; |
5609c185f 6lowpan: iphc: ad... |
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
struct lowpan_iphc_ctx *ret = NULL; struct in6_addr addr_pfx; u8 addr_plen; int i; for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { /* Check if context is valid. A context that is not valid * MUST NOT be used for compression. */ if (!lowpan_iphc_ctx_is_active(&table[i]) || !lowpan_iphc_ctx_is_compression(&table[i])) continue; ipv6_addr_prefix(&addr_pfx, addr, table[i].plen); /* if prefix len < 64, the remaining bits until 64th bit is * zero. Otherwise we use table[i]->plen. */ if (table[i].plen < 64) addr_plen = 64; else addr_plen = table[i].plen; if (ipv6_prefix_equal(&addr_pfx, &table[i].pfx, addr_plen)) { /* remember first match */ if (!ret) { ret = &table[i]; continue; } /* get the context with longest prefix len */ if (table[i].plen > ret->plen) ret = &table[i]; } } return ret; } static struct lowpan_iphc_ctx * lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev, const struct in6_addr *addr) { |
2e4d60cbc 6lowpan: change n... |
240 |
struct lowpan_iphc_ctx *table = lowpan_dev(dev)->ctx.table; |
5609c185f 6lowpan: iphc: ad... |
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
struct lowpan_iphc_ctx *ret = NULL; struct in6_addr addr_mcast, network_pfx = {}; int i; /* init mcast address with */ memcpy(&addr_mcast, addr, sizeof(*addr)); for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++) { /* Check if context is valid. A context that is not valid * MUST NOT be used for compression. */ if (!lowpan_iphc_ctx_is_active(&table[i]) || !lowpan_iphc_ctx_is_compression(&table[i])) continue; /* setting plen */ addr_mcast.s6_addr[3] = table[i].plen; /* get network prefix to copy into multicast address */ ipv6_addr_prefix(&network_pfx, &table[i].pfx, table[i].plen); /* setting network prefix */ memcpy(&addr_mcast.s6_addr[4], &network_pfx, 8); if (ipv6_addr_equal(addr, &addr_mcast)) { ret = &table[i]; break; } } return ret; } |
fa09ae661 6lowpan: Use netd... |
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
static void lowpan_iphc_uncompress_lladdr(const struct net_device *dev, struct in6_addr *ipaddr, const void *lladdr) { switch (dev->addr_len) { case ETH_ALEN: lowpan_iphc_uncompress_eui48_lladdr(ipaddr, lladdr); break; case EUI64_ADDR_LEN: lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); break; default: WARN_ON_ONCE(1); break; } } |
4710d806f 6lowpan: mac80215... |
288 |
/* Uncompress address function for source and |
8df8c56a5 6lowpan: Moving g... |
289 290 |
* destination address(non-multicast). * |
c8a3e7eb9 6lowpan: iphc: ch... |
291 |
* address_mode is the masked value for sam or dam value |
8df8c56a5 6lowpan: Moving g... |
292 |
*/ |
7115a968b 6lowpan: iphc: re... |
293 294 295 296 |
static int lowpan_iphc_uncompress_addr(struct sk_buff *skb, const struct net_device *dev, struct in6_addr *ipaddr, u8 address_mode, const void *lladdr) |
8df8c56a5 6lowpan: Moving g... |
297 298 299 300 |
{ bool fail; switch (address_mode) { |
c8a3e7eb9 6lowpan: iphc: ch... |
301 302 |
/* SAM and DAM are the same here */ case LOWPAN_IPHC_DAM_00: |
8df8c56a5 6lowpan: Moving g... |
303 304 305 |
/* for global link addresses */ fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); break; |
c8a3e7eb9 6lowpan: iphc: ch... |
306 307 |
case LOWPAN_IPHC_SAM_01: case LOWPAN_IPHC_DAM_01: |
8df8c56a5 6lowpan: Moving g... |
308 309 310 311 312 |
/* fe:80::XXXX:XXXX:XXXX:XXXX */ ipaddr->s6_addr[0] = 0xFE; ipaddr->s6_addr[1] = 0x80; fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); break; |
c8a3e7eb9 6lowpan: iphc: ch... |
313 314 |
case LOWPAN_IPHC_SAM_10: case LOWPAN_IPHC_DAM_10: |
8df8c56a5 6lowpan: Moving g... |
315 316 317 318 319 320 321 |
/* fe:80::ff:fe00:XXXX */ ipaddr->s6_addr[0] = 0xFE; ipaddr->s6_addr[1] = 0x80; ipaddr->s6_addr[11] = 0xFF; ipaddr->s6_addr[12] = 0xFE; fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); break; |
c8a3e7eb9 6lowpan: iphc: ch... |
322 323 |
case LOWPAN_IPHC_SAM_11: case LOWPAN_IPHC_DAM_11: |
8df8c56a5 6lowpan: Moving g... |
324 |
fail = false; |
2e4d60cbc 6lowpan: change n... |
325 |
switch (lowpan_dev(dev)->lltype) { |
8911d7748 6lowpan: cleanup ... |
326 |
case LOWPAN_LLTYPE_IEEE802154: |
7115a968b 6lowpan: iphc: re... |
327 |
lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); |
8df8c56a5 6lowpan: Moving g... |
328 329 |
break; default: |
fa09ae661 6lowpan: Use netd... |
330 |
lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr); |
8911d7748 6lowpan: cleanup ... |
331 |
break; |
8df8c56a5 6lowpan: Moving g... |
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
} break; default: pr_debug("Invalid address mode value: 0x%x ", address_mode); return -EINVAL; } if (fail) { pr_debug("Failed to fetch skb data "); return -EIO; } raw_dump_inline(NULL, "Reconstructed ipv6 addr is", ipaddr->s6_addr, 16); return 0; } |
4710d806f 6lowpan: mac80215... |
351 |
/* Uncompress address function for source context |
8df8c56a5 6lowpan: Moving g... |
352 353 |
* based address(non-multicast). */ |
7115a968b 6lowpan: iphc: re... |
354 355 356 357 358 |
static int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb, const struct net_device *dev, const struct lowpan_iphc_ctx *ctx, struct in6_addr *ipaddr, u8 address_mode, const void *lladdr) |
8df8c56a5 6lowpan: Moving g... |
359 |
{ |
5609c185f 6lowpan: iphc: ad... |
360 |
bool fail; |
c8a3e7eb9 6lowpan: iphc: ch... |
361 |
switch (address_mode) { |
5609c185f 6lowpan: iphc: ad... |
362 363 364 365 |
/* SAM and DAM are the same here */ case LOWPAN_IPHC_DAM_00: fail = false; /* SAM_00 -> unspec address :: |
8df8c56a5 6lowpan: Moving g... |
366 |
* Do nothing, address is already :: |
5609c185f 6lowpan: iphc: ad... |
367 368 |
* * DAM 00 -> reserved should never occur. |
8df8c56a5 6lowpan: Moving g... |
369 370 |
*/ break; |
c8a3e7eb9 6lowpan: iphc: ch... |
371 |
case LOWPAN_IPHC_SAM_01: |
5609c185f 6lowpan: iphc: ad... |
372 373 374 375 |
case LOWPAN_IPHC_DAM_01: fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8); ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); break; |
c8a3e7eb9 6lowpan: iphc: ch... |
376 |
case LOWPAN_IPHC_SAM_10: |
5609c185f 6lowpan: iphc: ad... |
377 378 379 380 381 382 |
case LOWPAN_IPHC_DAM_10: ipaddr->s6_addr[11] = 0xFF; ipaddr->s6_addr[12] = 0xFE; fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2); ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); break; |
c8a3e7eb9 6lowpan: iphc: ch... |
383 |
case LOWPAN_IPHC_SAM_11: |
5609c185f 6lowpan: iphc: ad... |
384 385 |
case LOWPAN_IPHC_DAM_11: fail = false; |
2e4d60cbc 6lowpan: change n... |
386 |
switch (lowpan_dev(dev)->lltype) { |
5609c185f 6lowpan: iphc: ad... |
387 |
case LOWPAN_LLTYPE_IEEE802154: |
7115a968b 6lowpan: iphc: re... |
388 |
lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); |
5609c185f 6lowpan: iphc: ad... |
389 390 |
break; default: |
fa09ae661 6lowpan: Use netd... |
391 |
lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr); |
5609c185f 6lowpan: iphc: ad... |
392 393 394 395 |
break; } ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); break; |
8df8c56a5 6lowpan: Moving g... |
396 |
default: |
c8a3e7eb9 6lowpan: iphc: ch... |
397 398 |
pr_debug("Invalid sam value: 0x%x ", address_mode); |
8df8c56a5 6lowpan: Moving g... |
399 400 |
return -EINVAL; } |
5609c185f 6lowpan: iphc: ad... |
401 402 403 404 405 |
if (fail) { pr_debug("Failed to fetch skb data "); return -EIO; } |
8df8c56a5 6lowpan: Moving g... |
406 407 408 409 410 411 |
raw_dump_inline(NULL, "Reconstructed context based ipv6 src addr is", ipaddr->s6_addr, 16); return 0; } |
8df8c56a5 6lowpan: Moving g... |
412 413 414 |
/* Uncompress function for multicast destination address, * when M bit is set. */ |
7fc4cfda7 6lowpan: iphc: Fi... |
415 416 |
static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb, struct in6_addr *ipaddr, |
c8a3e7eb9 6lowpan: iphc: ch... |
417 |
u8 address_mode) |
8df8c56a5 6lowpan: Moving g... |
418 419 |
{ bool fail; |
c8a3e7eb9 6lowpan: iphc: ch... |
420 |
switch (address_mode) { |
8df8c56a5 6lowpan: Moving g... |
421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
case LOWPAN_IPHC_DAM_00: /* 00: 128 bits. The full address * is carried in-line. */ fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16); break; case LOWPAN_IPHC_DAM_01: /* 01: 48 bits. The address takes * the form ffXX::00XX:XXXX:XXXX. */ ipaddr->s6_addr[0] = 0xFF; fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5); break; case LOWPAN_IPHC_DAM_10: /* 10: 32 bits. The address takes * the form ffXX::00XX:XXXX. */ ipaddr->s6_addr[0] = 0xFF; fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1); fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3); break; case LOWPAN_IPHC_DAM_11: /* 11: 8 bits. The address takes * the form ff02::00XX. */ ipaddr->s6_addr[0] = 0xFF; ipaddr->s6_addr[1] = 0x02; fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1); break; default: |
c8a3e7eb9 6lowpan: iphc: ch... |
452 453 |
pr_debug("DAM value has a wrong value: 0x%x ", address_mode); |
8df8c56a5 6lowpan: Moving g... |
454 455 456 457 458 459 460 461 462 463 |
return -EINVAL; } if (fail) { pr_debug("Failed to fetch skb data "); return -EIO; } raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is", |
7fc4cfda7 6lowpan: iphc: Fi... |
464 |
ipaddr->s6_addr, 16); |
8df8c56a5 6lowpan: Moving g... |
465 466 467 |
return 0; } |
5609c185f 6lowpan: iphc: ad... |
468 469 470 471 472 473 474 475 476 477 478 |
static int lowpan_uncompress_multicast_ctx_daddr(struct sk_buff *skb, struct lowpan_iphc_ctx *ctx, struct in6_addr *ipaddr, u8 address_mode) { struct in6_addr network_pfx = {}; bool fail; ipaddr->s6_addr[0] = 0xFF; fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 2); fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[12], 4); |
4c23d8745 6lowpan: fix erro... |
479 |
if (fail) |
5609c185f 6lowpan: iphc: ad... |
480 481 482 483 484 485 486 487 488 489 490 |
return -EIO; /* take prefix_len and network prefix from the context */ ipaddr->s6_addr[3] = ctx->plen; /* get network prefix to copy into multicast address */ ipv6_addr_prefix(&network_pfx, &ctx->pfx, ctx->plen); /* setting network prefix */ memcpy(&ipaddr->s6_addr[4], &network_pfx, 8); return 0; } |
b5af9bdbf 6lowpan: rework t... |
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
/* get the ecn values from iphc tf format and set it to ipv6hdr */ static inline void lowpan_iphc_tf_set_ecn(struct ipv6hdr *hdr, const u8 *tf) { /* get the two higher bits which is ecn */ u8 ecn = tf[0] & 0xc0; /* ECN takes 0x30 in hdr->flow_lbl[0] */ hdr->flow_lbl[0] |= (ecn >> 2); } /* get the dscp values from iphc tf format and set it to ipv6hdr */ static inline void lowpan_iphc_tf_set_dscp(struct ipv6hdr *hdr, const u8 *tf) { /* DSCP is at place after ECN */ u8 dscp = tf[0] & 0x3f; /* The four highest bits need to be set at hdr->priority */ hdr->priority |= ((dscp & 0x3c) >> 2); /* The two lower bits is part of hdr->flow_lbl[0] */ hdr->flow_lbl[0] |= ((dscp & 0x03) << 6); } /* get the flow label values from iphc tf format and set it to ipv6hdr */ static inline void lowpan_iphc_tf_set_lbl(struct ipv6hdr *hdr, const u8 *lbl) { /* flow label is always some array started with lower nibble of * flow_lbl[0] and followed with two bytes afterwards. Inside inline * data the flow_lbl position can be different, which will be handled * by lbl pointer. E.g. case "01" vs "00" the traffic class is 8 bit * shifted, the different lbl pointer will handle that. * * The flow label will started at lower nibble of flow_lbl[0], the * higher nibbles are part of DSCP + ECN. */ hdr->flow_lbl[0] |= lbl[0] & 0x0f; memcpy(&hdr->flow_lbl[1], &lbl[1], 2); } /* lowpan_iphc_tf_decompress - decompress the traffic class. * This function will return zero on success, a value lower than zero if * failed. */ static int lowpan_iphc_tf_decompress(struct sk_buff *skb, struct ipv6hdr *hdr, u8 val) { u8 tf[4]; /* Traffic Class and Flow Label */ switch (val) { case LOWPAN_IPHC_TF_00: /* ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) */ if (lowpan_fetch_skb(skb, tf, 4)) return -EINVAL; /* 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |ECN| DSCP | rsv | Flow Label | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ lowpan_iphc_tf_set_ecn(hdr, tf); lowpan_iphc_tf_set_dscp(hdr, tf); lowpan_iphc_tf_set_lbl(hdr, &tf[1]); break; case LOWPAN_IPHC_TF_01: /* ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided. */ if (lowpan_fetch_skb(skb, tf, 3)) return -EINVAL; /* 1 2 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |ECN|rsv| Flow Label | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ lowpan_iphc_tf_set_ecn(hdr, tf); lowpan_iphc_tf_set_lbl(hdr, &tf[0]); break; case LOWPAN_IPHC_TF_10: /* ECN + DSCP (1 byte), Flow Label is elided. */ if (lowpan_fetch_skb(skb, tf, 1)) return -EINVAL; /* 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * |ECN| DSCP | * +-+-+-+-+-+-+-+-+ */ lowpan_iphc_tf_set_ecn(hdr, tf); lowpan_iphc_tf_set_dscp(hdr, tf); break; case LOWPAN_IPHC_TF_11: /* Traffic Class and Flow Label are elided */ break; default: WARN_ON_ONCE(1); return -EINVAL; } return 0; } |
8df8c56a5 6lowpan: Moving g... |
592 |
/* TTL uncompression values */ |
c8a3e7eb9 6lowpan: iphc: ch... |
593 594 595 596 597 |
static const u8 lowpan_ttl_values[] = { [LOWPAN_IPHC_HLIM_01] = 1, [LOWPAN_IPHC_HLIM_10] = 64, [LOWPAN_IPHC_HLIM_11] = 255, }; |
8df8c56a5 6lowpan: Moving g... |
598 |
|
8911d7748 6lowpan: cleanup ... |
599 600 |
int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev, const void *daddr, const void *saddr) |
8df8c56a5 6lowpan: Moving g... |
601 602 |
{ struct ipv6hdr hdr = {}; |
5609c185f 6lowpan: iphc: ad... |
603 604 |
struct lowpan_iphc_ctx *ci; u8 iphc0, iphc1, cid = 0; |
8df8c56a5 6lowpan: Moving g... |
605 606 607 |
int err; raw_dump_table(__func__, "raw skb data dump uncompressed", |
4710d806f 6lowpan: mac80215... |
608 |
skb->data, skb->len); |
8df8c56a5 6lowpan: Moving g... |
609 |
|
478208e3b 6lowpan: remove l... |
610 611 |
if (lowpan_fetch_skb(skb, &iphc0, sizeof(iphc0)) || lowpan_fetch_skb(skb, &iphc1, sizeof(iphc1))) |
8911d7748 6lowpan: cleanup ... |
612 |
return -EINVAL; |
8df8c56a5 6lowpan: Moving g... |
613 |
hdr.version = 6; |
5609c185f 6lowpan: iphc: ad... |
614 615 616 617 618 |
/* default CID = 0, another if the CID flag is set */ if (iphc1 & LOWPAN_IPHC_CID) { if (lowpan_fetch_skb(skb, &cid, sizeof(cid))) return -EINVAL; } |
b5af9bdbf 6lowpan: rework t... |
619 620 621 622 |
err = lowpan_iphc_tf_decompress(skb, &hdr, iphc0 & LOWPAN_IPHC_TF_MASK); if (err < 0) return err; |
8df8c56a5 6lowpan: Moving g... |
623 624 |
/* Next Header */ |
c8a3e7eb9 6lowpan: iphc: ch... |
625 |
if (!(iphc0 & LOWPAN_IPHC_NH)) { |
8df8c56a5 6lowpan: Moving g... |
626 |
/* Next header is carried inline */ |
4ebc960f9 6lowpan: iphc: cl... |
627 |
if (lowpan_fetch_skb(skb, &hdr.nexthdr, sizeof(hdr.nexthdr))) |
56b2c3eea 6lowpan: move skb... |
628 |
return -EINVAL; |
8df8c56a5 6lowpan: Moving g... |
629 630 631 632 633 634 635 |
pr_debug("NH flag is set, next header carried inline: %02x ", hdr.nexthdr); } /* Hop Limit */ |
c8a3e7eb9 6lowpan: iphc: ch... |
636 637 |
if ((iphc0 & LOWPAN_IPHC_HLIM_MASK) != LOWPAN_IPHC_HLIM_00) { hdr.hop_limit = lowpan_ttl_values[iphc0 & LOWPAN_IPHC_HLIM_MASK]; |
4710d806f 6lowpan: mac80215... |
638 |
} else { |
4ebc960f9 6lowpan: iphc: cl... |
639 640 |
if (lowpan_fetch_skb(skb, &hdr.hop_limit, sizeof(hdr.hop_limit))) |
56b2c3eea 6lowpan: move skb... |
641 |
return -EINVAL; |
8df8c56a5 6lowpan: Moving g... |
642 |
} |
8df8c56a5 6lowpan: Moving g... |
643 |
if (iphc1 & LOWPAN_IPHC_SAC) { |
2e4d60cbc 6lowpan: change n... |
644 |
spin_lock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
645 646 |
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_SCI(cid)); if (!ci) { |
2e4d60cbc 6lowpan: change n... |
647 |
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
648 649 |
return -EINVAL; } |
8df8c56a5 6lowpan: Moving g... |
650 651 |
pr_debug("SAC bit is set. Handle context based source address. "); |
7115a968b 6lowpan: iphc: re... |
652 653 654 |
err = lowpan_iphc_uncompress_ctx_addr(skb, dev, ci, &hdr.saddr, iphc1 & LOWPAN_IPHC_SAM_MASK, saddr); |
2e4d60cbc 6lowpan: change n... |
655 |
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); |
8df8c56a5 6lowpan: Moving g... |
656 657 658 659 |
} else { /* Source address uncompression */ pr_debug("source address stateless compression "); |
7115a968b 6lowpan: iphc: re... |
660 661 662 |
err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.saddr, iphc1 & LOWPAN_IPHC_SAM_MASK, saddr); |
8df8c56a5 6lowpan: Moving g... |
663 664 665 666 |
} /* Check on error of previous branch */ if (err) |
56b2c3eea 6lowpan: move skb... |
667 |
return -EINVAL; |
8df8c56a5 6lowpan: Moving g... |
668 |
|
5609c185f 6lowpan: iphc: ad... |
669 670 |
switch (iphc1 & (LOWPAN_IPHC_M | LOWPAN_IPHC_DAC)) { case LOWPAN_IPHC_M | LOWPAN_IPHC_DAC: |
94e4a6803 6lowpan: iphc: ov... |
671 |
skb->pkt_type = PACKET_BROADCAST; |
2e4d60cbc 6lowpan: change n... |
672 |
spin_lock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
673 674 |
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid)); if (!ci) { |
2e4d60cbc 6lowpan: change n... |
675 |
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
676 677 |
return -EINVAL; } |
7fc4cfda7 6lowpan: iphc: Fi... |
678 |
|
5609c185f 6lowpan: iphc: ad... |
679 680 681 682 683 684 |
/* multicast with context */ pr_debug("dest: context-based mcast compression "); err = lowpan_uncompress_multicast_ctx_daddr(skb, ci, &hdr.daddr, iphc1 & LOWPAN_IPHC_DAM_MASK); |
2e4d60cbc 6lowpan: change n... |
685 |
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
686 687 |
break; case LOWPAN_IPHC_M: |
94e4a6803 6lowpan: iphc: ov... |
688 |
skb->pkt_type = PACKET_BROADCAST; |
5609c185f 6lowpan: iphc: ad... |
689 690 691 692 693 |
/* multicast */ err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr, iphc1 & LOWPAN_IPHC_DAM_MASK); break; case LOWPAN_IPHC_DAC: |
94e4a6803 6lowpan: iphc: ov... |
694 |
skb->pkt_type = PACKET_HOST; |
2e4d60cbc 6lowpan: change n... |
695 |
spin_lock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
696 697 |
ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid)); if (!ci) { |
2e4d60cbc 6lowpan: change n... |
698 |
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
699 |
return -EINVAL; |
8df8c56a5 6lowpan: Moving g... |
700 |
} |
5609c185f 6lowpan: iphc: ad... |
701 702 703 704 |
/* Destination address context based uncompression */ pr_debug("DAC bit is set. Handle context based destination address. "); |
7115a968b 6lowpan: iphc: re... |
705 706 707 |
err = lowpan_iphc_uncompress_ctx_addr(skb, dev, ci, &hdr.daddr, iphc1 & LOWPAN_IPHC_DAM_MASK, daddr); |
2e4d60cbc 6lowpan: change n... |
708 |
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
709 710 |
break; default: |
94e4a6803 6lowpan: iphc: ov... |
711 |
skb->pkt_type = PACKET_HOST; |
7115a968b 6lowpan: iphc: re... |
712 713 714 |
err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.daddr, iphc1 & LOWPAN_IPHC_DAM_MASK, daddr); |
8df8c56a5 6lowpan: Moving g... |
715 716 |
pr_debug("dest: stateless compression mode %d dest %pI6c ", |
c8a3e7eb9 6lowpan: iphc: ch... |
717 |
iphc1 & LOWPAN_IPHC_DAM_MASK, &hdr.daddr); |
5609c185f 6lowpan: iphc: ad... |
718 |
break; |
8df8c56a5 6lowpan: Moving g... |
719 |
} |
5609c185f 6lowpan: iphc: ad... |
720 721 |
if (err) return -EINVAL; |
cc6ed2684 6lowpan: add udp ... |
722 |
/* Next header data uncompression */ |
c8a3e7eb9 6lowpan: iphc: ch... |
723 |
if (iphc0 & LOWPAN_IPHC_NH) { |
cc6ed2684 6lowpan: add udp ... |
724 725 |
err = lowpan_nhc_do_uncompression(skb, dev, &hdr); if (err < 0) |
11e3ff707 6lowpan: Use skb_... |
726 |
return err; |
11e3ff707 6lowpan: Use skb_... |
727 728 |
} else { err = skb_cow(skb, sizeof(hdr)); |
56b2c3eea 6lowpan: move skb... |
729 |
if (unlikely(err)) |
11e3ff707 6lowpan: Use skb_... |
730 |
return err; |
8df8c56a5 6lowpan: Moving g... |
731 |
} |
2e4d60cbc 6lowpan: change n... |
732 |
switch (lowpan_dev(dev)->lltype) { |
72a5e6bb5 ieee820154: 6lowp... |
733 734 735 736 737 738 739 740 741 742 743 |
case LOWPAN_LLTYPE_IEEE802154: if (lowpan_802154_cb(skb)->d_size) hdr.payload_len = htons(lowpan_802154_cb(skb)->d_size - sizeof(struct ipv6hdr)); else hdr.payload_len = htons(skb->len); break; default: hdr.payload_len = htons(skb->len); break; } |
8df8c56a5 6lowpan: Moving g... |
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 |
pr_debug("skb headroom size = %d, data length = %d ", skb_headroom(skb), skb->len); pr_debug("IPv6 header dump: \tversion = %d \tlength = %d \t" "nexthdr = 0x%02x \thop_lim = %d \tdest = %pI6c ", hdr.version, ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit, &hdr.daddr); |
f8b361768 6lowpan: remove s... |
759 |
skb_push(skb, sizeof(hdr)); |
03bc05e1a 6lowpan: iphc: re... |
760 |
skb_reset_mac_header(skb); |
f8b361768 6lowpan: remove s... |
761 762 |
skb_reset_network_header(skb); skb_copy_to_linear_data(skb, &hdr, sizeof(hdr)); |
8df8c56a5 6lowpan: Moving g... |
763 |
|
f8b361768 6lowpan: remove s... |
764 |
raw_dump_table(__func__, "raw header dump", (u8 *)&hdr, sizeof(hdr)); |
8df8c56a5 6lowpan: Moving g... |
765 |
|
f8b361768 6lowpan: remove s... |
766 |
return 0; |
8df8c56a5 6lowpan: Moving g... |
767 |
} |
01141234f ieee802154: 6lowp... |
768 |
EXPORT_SYMBOL_GPL(lowpan_header_decompress); |
8df8c56a5 6lowpan: Moving g... |
769 |
|
c8a3e7eb9 6lowpan: iphc: ch... |
770 771 772 773 774 775 |
static const u8 lowpan_iphc_dam_to_sam_value[] = { [LOWPAN_IPHC_DAM_00] = LOWPAN_IPHC_SAM_00, [LOWPAN_IPHC_DAM_01] = LOWPAN_IPHC_SAM_01, [LOWPAN_IPHC_DAM_10] = LOWPAN_IPHC_SAM_10, [LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11, }; |
eab560e58 6lowpan: add supp... |
776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 |
static inline bool lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr, const struct lowpan_iphc_ctx *ctx, const void *lladdr) { const struct ieee802154_addr *addr = lladdr; unsigned char extended_addr[EUI64_ADDR_LEN]; bool lladdr_compress = false; struct in6_addr tmp = {}; switch (addr->mode) { case IEEE802154_ADDR_LONG: ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr); /* check for SAM/DAM = 11 */ memcpy(&tmp.s6_addr[8], &extended_addr, EUI64_ADDR_LEN); /* second bit-flip (Universe/Local) is done according RFC2464 */ tmp.s6_addr[8] ^= 0x02; /* context information are always used */ ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); if (ipv6_addr_equal(&tmp, ipaddr)) lladdr_compress = true; break; case IEEE802154_ADDR_SHORT: tmp.s6_addr[11] = 0xFF; tmp.s6_addr[12] = 0xFE; ieee802154_le16_to_be16(&tmp.s6_addr16[7], &addr->short_addr); /* context information are always used */ ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); if (ipv6_addr_equal(&tmp, ipaddr)) lladdr_compress = true; break; default: /* should never handled and filtered by 802154 6lowpan */ WARN_ON_ONCE(1); break; } return lladdr_compress; } |
fa09ae661 6lowpan: Use netd... |
816 817 818 819 820 821 822 823 824 825 826 827 828 829 |
static bool lowpan_iphc_addr_equal(const struct net_device *dev, const struct lowpan_iphc_ctx *ctx, const struct in6_addr *ipaddr, const void *lladdr) { struct in6_addr tmp = {}; lowpan_iphc_uncompress_lladdr(dev, &tmp, lladdr); if (ctx) ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); return ipv6_addr_equal(&tmp, ipaddr); } |
eab560e58 6lowpan: add supp... |
830 831 |
static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev, const struct in6_addr *ipaddr, |
5609c185f 6lowpan: iphc: ad... |
832 833 834 835 836 |
const struct lowpan_iphc_ctx *ctx, const unsigned char *lladdr, bool sam) { struct in6_addr tmp = {}; u8 dam; |
eab560e58 6lowpan: add supp... |
837 838 839 840 841 842 843 844 845 |
switch (lowpan_dev(dev)->lltype) { case LOWPAN_LLTYPE_IEEE802154: if (lowpan_iphc_compress_ctx_802154_lladdr(ipaddr, ctx, lladdr)) { dam = LOWPAN_IPHC_DAM_11; goto out; } break; default: |
fa09ae661 6lowpan: Use netd... |
846 |
if (lowpan_iphc_addr_equal(dev, ctx, ipaddr, lladdr)) { |
eab560e58 6lowpan: add supp... |
847 848 849 850 |
dam = LOWPAN_IPHC_DAM_11; goto out; } break; |
5609c185f 6lowpan: iphc: ad... |
851 852 853 |
} memset(&tmp, 0, sizeof(tmp)); |
24c4a81d7 6lowpan: iphc: fi... |
854 |
/* check for SAM/DAM = 10 */ |
5609c185f 6lowpan: iphc: ad... |
855 856 857 858 859 860 861 862 863 864 865 866 |
tmp.s6_addr[11] = 0xFF; tmp.s6_addr[12] = 0xFE; memcpy(&tmp.s6_addr[14], &ipaddr->s6_addr[14], 2); /* context information are always used */ ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); if (ipv6_addr_equal(&tmp, ipaddr)) { lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[14], 2); dam = LOWPAN_IPHC_DAM_10; goto out; } memset(&tmp, 0, sizeof(tmp)); |
24c4a81d7 6lowpan: iphc: fi... |
867 |
/* check for SAM/DAM = 01, should always match */ |
5609c185f 6lowpan: iphc: ad... |
868 869 870 871 872 873 874 875 |
memcpy(&tmp.s6_addr[8], &ipaddr->s6_addr[8], 8); /* context information are always used */ ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen); if (ipv6_addr_equal(&tmp, ipaddr)) { lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[8], 8); dam = LOWPAN_IPHC_DAM_01; goto out; } |
2306f6563 6lowpan: iphc: fi... |
876 877 878 |
WARN_ONCE(1, "context found but no address mode matched "); return LOWPAN_IPHC_DAM_00; |
5609c185f 6lowpan: iphc: ad... |
879 880 881 882 883 884 885 |
out: if (sam) return lowpan_iphc_dam_to_sam_value[dam]; else return dam; } |
eab560e58 6lowpan: add supp... |
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
static inline bool lowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr, const void *lladdr) { const struct ieee802154_addr *addr = lladdr; unsigned char extended_addr[EUI64_ADDR_LEN]; bool lladdr_compress = false; struct in6_addr tmp = {}; switch (addr->mode) { case IEEE802154_ADDR_LONG: ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr); if (is_addr_mac_addr_based(ipaddr, extended_addr)) lladdr_compress = true; break; case IEEE802154_ADDR_SHORT: /* fe:80::ff:fe00:XXXX * \__/ * short_addr * * Universe/Local bit is zero. */ tmp.s6_addr[0] = 0xFE; tmp.s6_addr[1] = 0x80; tmp.s6_addr[11] = 0xFF; tmp.s6_addr[12] = 0xFE; ieee802154_le16_to_be16(&tmp.s6_addr16[7], &addr->short_addr); if (ipv6_addr_equal(&tmp, ipaddr)) lladdr_compress = true; break; default: /* should never handled and filtered by 802154 6lowpan */ WARN_ON_ONCE(1); break; } return lladdr_compress; } static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev, const struct in6_addr *ipaddr, |
c8a3e7eb9 6lowpan: iphc: ch... |
928 |
const unsigned char *lladdr, bool sam) |
8df8c56a5 6lowpan: Moving g... |
929 |
{ |
eab560e58 6lowpan: add supp... |
930 |
u8 dam = LOWPAN_IPHC_DAM_01; |
8df8c56a5 6lowpan: Moving g... |
931 |
|
eab560e58 6lowpan: add supp... |
932 933 934 935 936 937 938 939 940 941 |
switch (lowpan_dev(dev)->lltype) { case LOWPAN_LLTYPE_IEEE802154: if (lowpan_iphc_compress_802154_lladdr(ipaddr, lladdr)) { dam = LOWPAN_IPHC_DAM_11; /* 0-bits */ pr_debug("address compression 0 bits "); goto out; } break; default: |
fa09ae661 6lowpan: Use netd... |
942 943 |
if (lowpan_iphc_addr_equal(dev, NULL, ipaddr, lladdr)) { dam = LOWPAN_IPHC_DAM_11; |
eab560e58 6lowpan: add supp... |
944 945 946 947 |
pr_debug("address compression 0 bits "); goto out; } |
fa09ae661 6lowpan: Use netd... |
948 |
|
eab560e58 6lowpan: add supp... |
949 950 951 952 |
break; } if (lowpan_is_iid_16_bit_compressable(ipaddr)) { |
8df8c56a5 6lowpan: Moving g... |
953 |
/* compress IID to 16 bits xxxx::XXXX */ |
85c71240a 6lowpan: iphc: cl... |
954 |
lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2); |
c8a3e7eb9 6lowpan: iphc: ch... |
955 |
dam = LOWPAN_IPHC_DAM_10; /* 16-bits */ |
8df8c56a5 6lowpan: Moving g... |
956 |
raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)", |
84ca5e036 6lowpan: iphc: re... |
957 |
*hc_ptr - 2, 2); |
eab560e58 6lowpan: add supp... |
958 |
goto out; |
8df8c56a5 6lowpan: Moving g... |
959 |
} |
eab560e58 6lowpan: add supp... |
960 961 962 963 964 965 |
/* do not compress IID => xxxx::IID */ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8); raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)", *hc_ptr - 8, 8); out: |
c8a3e7eb9 6lowpan: iphc: ch... |
966 967 968 969 |
if (sam) return lowpan_iphc_dam_to_sam_value[dam]; else return dam; |
8df8c56a5 6lowpan: Moving g... |
970 |
} |
b5af9bdbf 6lowpan: rework t... |
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 |
/* lowpan_iphc_get_tc - get the ECN + DCSP fields in hc format */ static inline u8 lowpan_iphc_get_tc(const struct ipv6hdr *hdr) { u8 dscp, ecn; /* hdr->priority contains the higher bits of dscp, lower are part of * flow_lbl[0]. Note ECN, DCSP is swapped in ipv6 hdr. */ dscp = (hdr->priority << 2) | ((hdr->flow_lbl[0] & 0xc0) >> 6); /* ECN is at the two lower bits from first nibble of flow_lbl[0] */ ecn = (hdr->flow_lbl[0] & 0x30); /* for pretty debug output, also shift ecn to get the ecn value */ pr_debug("ecn 0x%02x dscp 0x%02x ", ecn >> 4, dscp); /* ECN is at 0x30 now, shift it to have ECN + DCSP */ return (ecn << 2) | dscp; } /* lowpan_iphc_is_flow_lbl_zero - check if flow label is zero */ static inline bool lowpan_iphc_is_flow_lbl_zero(const struct ipv6hdr *hdr) { return ((!(hdr->flow_lbl[0] & 0x0f)) && !hdr->flow_lbl[1] && !hdr->flow_lbl[2]); } /* lowpan_iphc_tf_compress - compress the traffic class which is set by * ipv6hdr. Return the corresponding format identifier which is used. */ static u8 lowpan_iphc_tf_compress(u8 **hc_ptr, const struct ipv6hdr *hdr) { /* get ecn dscp data in a byteformat as: ECN(hi) + DSCP(lo) */ u8 tc = lowpan_iphc_get_tc(hdr), tf[4], val; /* printout the traffic class in hc format */ pr_debug("tc 0x%02x ", tc); if (lowpan_iphc_is_flow_lbl_zero(hdr)) { if (!tc) { /* 11: Traffic Class and Flow Label are elided. */ val = LOWPAN_IPHC_TF_11; } else { /* 10: ECN + DSCP (1 byte), Flow Label is elided. * * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ * |ECN| DSCP | * +-+-+-+-+-+-+-+-+ */ lowpan_push_hc_data(hc_ptr, &tc, sizeof(tc)); val = LOWPAN_IPHC_TF_10; } } else { /* check if dscp is zero, it's after the first two bit */ if (!(tc & 0x3f)) { /* 01: ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided * * 1 2 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |ECN|rsv| Flow Label | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ memcpy(&tf[0], &hdr->flow_lbl[0], 3); /* zero the highest 4-bits, contains DCSP + ECN */ tf[0] &= ~0xf0; /* set ECN */ tf[0] |= (tc & 0xc0); lowpan_push_hc_data(hc_ptr, tf, 3); val = LOWPAN_IPHC_TF_01; } else { /* 00: ECN + DSCP + 4-bit Pad + Flow Label (4 bytes) * * 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |ECN| DSCP | rsv | Flow Label | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ memcpy(&tf[0], &tc, sizeof(tc)); /* highest nibble of flow_lbl[0] is part of DSCP + ECN * which will be the 4-bit pad and will be filled with * zeros afterwards. */ memcpy(&tf[1], &hdr->flow_lbl[0], 3); /* zero the 4-bit pad, which is reserved */ tf[1] &= ~0xf0; lowpan_push_hc_data(hc_ptr, tf, 4); val = LOWPAN_IPHC_TF_00; } } return val; } |
5609c185f 6lowpan: iphc: ad... |
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 |
static u8 lowpan_iphc_mcast_ctx_addr_compress(u8 **hc_ptr, const struct lowpan_iphc_ctx *ctx, const struct in6_addr *ipaddr) { u8 data[6]; /* flags/scope, reserved (RIID) */ memcpy(data, &ipaddr->s6_addr[1], 2); /* group ID */ memcpy(&data[1], &ipaddr->s6_addr[11], 4); lowpan_push_hc_data(hc_ptr, data, 6); return LOWPAN_IPHC_DAM_00; } |
09bf420f1 6lowpan: put mcas... |
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 |
static u8 lowpan_iphc_mcast_addr_compress(u8 **hc_ptr, const struct in6_addr *ipaddr) { u8 val; if (lowpan_is_mcast_addr_compressable8(ipaddr)) { pr_debug("compressed to 1 octet "); /* use last byte */ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[15], 1); val = LOWPAN_IPHC_DAM_11; } else if (lowpan_is_mcast_addr_compressable32(ipaddr)) { pr_debug("compressed to 4 octets "); /* second byte + the last three */ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[1], 1); lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[13], 3); val = LOWPAN_IPHC_DAM_10; } else if (lowpan_is_mcast_addr_compressable48(ipaddr)) { pr_debug("compressed to 6 octets "); /* second byte + the last five */ lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[1], 1); lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr[11], 5); val = LOWPAN_IPHC_DAM_01; } else { pr_debug("using full address "); lowpan_push_hc_data(hc_ptr, ipaddr->s6_addr, 16); val = LOWPAN_IPHC_DAM_00; } return val; } |
a6f773891 6lowpan: cleanup ... |
1115 1116 |
int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev, const void *daddr, const void *saddr) |
8df8c56a5 6lowpan: Moving g... |
1117 |
{ |
5609c185f 6lowpan: iphc: ad... |
1118 |
u8 iphc0, iphc1, *hc_ptr, cid = 0; |
8df8c56a5 6lowpan: Moving g... |
1119 |
struct ipv6hdr *hdr; |
bf513fd6f 6lowpan: introduc... |
1120 |
u8 head[LOWPAN_IPHC_MAX_HC_BUF_LEN] = {}; |
5609c185f 6lowpan: iphc: ad... |
1121 1122 |
struct lowpan_iphc_ctx *dci, *sci, dci_entry, sci_entry; int ret, ipv6_daddr_type, ipv6_saddr_type; |
8df8c56a5 6lowpan: Moving g... |
1123 |
|
a6f773891 6lowpan: cleanup ... |
1124 |
if (skb->protocol != htons(ETH_P_IPV6)) |
8df8c56a5 6lowpan: Moving g... |
1125 1126 1127 |
return -EINVAL; hdr = ipv6_hdr(skb); |
84ca5e036 6lowpan: iphc: re... |
1128 |
hc_ptr = head + 2; |
8df8c56a5 6lowpan: Moving g... |
1129 1130 1131 1132 1133 1134 1135 1136 1137 |
pr_debug("IPv6 header dump: \tversion = %d \tlength = %d " "\tnexthdr = 0x%02x \thop_lim = %d \tdest = %pI6c ", |
4710d806f 6lowpan: mac80215... |
1138 1139 |
hdr->version, ntohs(hdr->payload_len), hdr->nexthdr, hdr->hop_limit, &hdr->daddr); |
8df8c56a5 6lowpan: Moving g... |
1140 1141 |
raw_dump_table(__func__, "raw skb network header dump", |
4710d806f 6lowpan: mac80215... |
1142 |
skb_network_header(skb), sizeof(struct ipv6hdr)); |
8df8c56a5 6lowpan: Moving g... |
1143 |
|
4710d806f 6lowpan: mac80215... |
1144 |
/* As we copy some bit-length fields, in the IPHC encoding bytes, |
8df8c56a5 6lowpan: Moving g... |
1145 1146 1147 1148 1149 1150 |
* we sometimes use |= * If the field is 0, and the current bit value in memory is 1, * this does not work. We therefore reset the IPHC encoding here */ iphc0 = LOWPAN_DISPATCH_IPHC; iphc1 = 0; |
7fc4cfda7 6lowpan: iphc: Fi... |
1151 |
raw_dump_table(__func__, "sending raw skb network uncompressed packet", |
4710d806f 6lowpan: mac80215... |
1152 |
skb->data, skb->len); |
8df8c56a5 6lowpan: Moving g... |
1153 |
|
5609c185f 6lowpan: iphc: ad... |
1154 |
ipv6_daddr_type = ipv6_addr_type(&hdr->daddr); |
2e4d60cbc 6lowpan: change n... |
1155 |
spin_lock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
1156 1157 1158 1159 1160 1161 1162 1163 |
if (ipv6_daddr_type & IPV6_ADDR_MULTICAST) dci = lowpan_iphc_ctx_get_by_mcast_addr(dev, &hdr->daddr); else dci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->daddr); if (dci) { memcpy(&dci_entry, dci, sizeof(*dci)); cid |= dci->id; } |
2e4d60cbc 6lowpan: change n... |
1164 |
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
1165 |
|
2e4d60cbc 6lowpan: change n... |
1166 |
spin_lock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
1167 1168 1169 1170 1171 |
sci = lowpan_iphc_ctx_get_by_addr(dev, &hdr->saddr); if (sci) { memcpy(&sci_entry, sci, sizeof(*sci)); cid |= (sci->id << 4); } |
2e4d60cbc 6lowpan: change n... |
1172 |
spin_unlock_bh(&lowpan_dev(dev)->ctx.lock); |
5609c185f 6lowpan: iphc: ad... |
1173 1174 1175 1176 1177 1178 |
/* if cid is zero it will be compressed */ if (cid) { iphc1 |= LOWPAN_IPHC_CID; lowpan_push_hc_data(&hc_ptr, &cid, sizeof(cid)); } |
b5af9bdbf 6lowpan: rework t... |
1179 1180 |
/* Traffic Class, Flow Label compression */ iphc0 |= lowpan_iphc_tf_compress(&hc_ptr, hdr); |
8df8c56a5 6lowpan: Moving g... |
1181 1182 |
/* NOTE: payload length is always compressed */ |
cc6ed2684 6lowpan: add udp ... |
1183 1184 1185 |
/* Check if we provide the nhc format for nexthdr and compression * functionality. If not nexthdr is handled inline and not compressed. */ |
607b0bd3f 6lowpan: nhc: mov... |
1186 1187 1188 1189 1190 |
ret = lowpan_nhc_check_compression(skb, hdr, &hc_ptr); if (ret == -ENOENT) lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr, sizeof(hdr->nexthdr)); else |
c8a3e7eb9 6lowpan: iphc: ch... |
1191 |
iphc0 |= LOWPAN_IPHC_NH; |
8df8c56a5 6lowpan: Moving g... |
1192 |
|
4710d806f 6lowpan: mac80215... |
1193 |
/* Hop limit |
8df8c56a5 6lowpan: Moving g... |
1194 1195 1196 1197 1198 1199 1200 |
* if 1: compress, encoding is 01 * if 64: compress, encoding is 10 * if 255: compress, encoding is 11 * else do not compress */ switch (hdr->hop_limit) { case 1: |
c8a3e7eb9 6lowpan: iphc: ch... |
1201 |
iphc0 |= LOWPAN_IPHC_HLIM_01; |
8df8c56a5 6lowpan: Moving g... |
1202 1203 |
break; case 64: |
c8a3e7eb9 6lowpan: iphc: ch... |
1204 |
iphc0 |= LOWPAN_IPHC_HLIM_10; |
8df8c56a5 6lowpan: Moving g... |
1205 1206 |
break; case 255: |
c8a3e7eb9 6lowpan: iphc: ch... |
1207 |
iphc0 |= LOWPAN_IPHC_HLIM_11; |
8df8c56a5 6lowpan: Moving g... |
1208 1209 |
break; default: |
85c71240a 6lowpan: iphc: cl... |
1210 1211 |
lowpan_push_hc_data(&hc_ptr, &hdr->hop_limit, sizeof(hdr->hop_limit)); |
8df8c56a5 6lowpan: Moving g... |
1212 |
} |
5609c185f 6lowpan: iphc: ad... |
1213 |
ipv6_saddr_type = ipv6_addr_type(&hdr->saddr); |
8df8c56a5 6lowpan: Moving g... |
1214 |
/* source address compression */ |
5609c185f 6lowpan: iphc: ad... |
1215 |
if (ipv6_saddr_type == IPV6_ADDR_ANY) { |
8df8c56a5 6lowpan: Moving g... |
1216 1217 1218 |
pr_debug("source address is unspecified, setting SAC "); iphc1 |= LOWPAN_IPHC_SAC; |
8df8c56a5 6lowpan: Moving g... |
1219 |
} else { |
5609c185f 6lowpan: iphc: ad... |
1220 |
if (sci) { |
eab560e58 6lowpan: add supp... |
1221 1222 |
iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev, &hdr->saddr, |
5609c185f 6lowpan: iphc: ad... |
1223 1224 1225 |
&sci_entry, saddr, true); iphc1 |= LOWPAN_IPHC_SAC; |
556a5bfc0 6lowpan: iphc: us... |
1226 |
} else { |
feb2add32 6lowpan: iphc: fi... |
1227 1228 |
if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL && lowpan_is_linklocal_zero_padded(hdr->saddr)) { |
eab560e58 6lowpan: add supp... |
1229 |
iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev, |
5609c185f 6lowpan: iphc: ad... |
1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 |
&hdr->saddr, saddr, true); pr_debug("source address unicast link-local %pI6c iphc1 0x%02x ", &hdr->saddr, iphc1); } else { pr_debug("send the full source address "); lowpan_push_hc_data(&hc_ptr, hdr->saddr.s6_addr, 16); } |
556a5bfc0 6lowpan: iphc: us... |
1241 |
} |
8df8c56a5 6lowpan: Moving g... |
1242 1243 1244 |
} /* destination address compression */ |
5609c185f 6lowpan: iphc: ad... |
1245 |
if (ipv6_daddr_type & IPV6_ADDR_MULTICAST) { |
8df8c56a5 6lowpan: Moving g... |
1246 |
pr_debug("destination address is multicast: "); |
8790404de 6lowpan: iphc: fi... |
1247 |
iphc1 |= LOWPAN_IPHC_M; |
5609c185f 6lowpan: iphc: ad... |
1248 1249 1250 1251 |
if (dci) { iphc1 |= lowpan_iphc_mcast_ctx_addr_compress(&hc_ptr, &dci_entry, &hdr->daddr); |
8790404de 6lowpan: iphc: fi... |
1252 |
iphc1 |= LOWPAN_IPHC_DAC; |
5609c185f 6lowpan: iphc: ad... |
1253 |
} else { |
5609c185f 6lowpan: iphc: ad... |
1254 1255 1256 |
iphc1 |= lowpan_iphc_mcast_addr_compress(&hc_ptr, &hdr->daddr); } |
8df8c56a5 6lowpan: Moving g... |
1257 |
} else { |
5609c185f 6lowpan: iphc: ad... |
1258 |
if (dci) { |
eab560e58 6lowpan: add supp... |
1259 1260 |
iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev, &hdr->daddr, |
5609c185f 6lowpan: iphc: ad... |
1261 1262 1263 |
&dci_entry, daddr, false); iphc1 |= LOWPAN_IPHC_DAC; |
8df8c56a5 6lowpan: Moving g... |
1264 |
} else { |
feb2add32 6lowpan: iphc: fi... |
1265 1266 |
if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL && lowpan_is_linklocal_zero_padded(hdr->daddr)) { |
eab560e58 6lowpan: add supp... |
1267 |
iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev, |
5609c185f 6lowpan: iphc: ad... |
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 |
&hdr->daddr, daddr, false); pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x ", &hdr->daddr, iphc1); } else { pr_debug("dest address unicast %pI6c ", &hdr->daddr); lowpan_push_hc_data(&hc_ptr, hdr->daddr.s6_addr, 16); } |
8df8c56a5 6lowpan: Moving g... |
1280 1281 |
} } |
cc6ed2684 6lowpan: add udp ... |
1282 |
/* next header compression */ |
c8a3e7eb9 6lowpan: iphc: ch... |
1283 |
if (iphc0 & LOWPAN_IPHC_NH) { |
cc6ed2684 6lowpan: add udp ... |
1284 1285 1286 1287 |
ret = lowpan_nhc_do_compression(skb, hdr, &hc_ptr); if (ret < 0) return ret; } |
8df8c56a5 6lowpan: Moving g... |
1288 1289 1290 1291 1292 1293 |
head[0] = iphc0; head[1] = iphc1; skb_pull(skb, sizeof(struct ipv6hdr)); skb_reset_transport_header(skb); |
84ca5e036 6lowpan: iphc: re... |
1294 |
memcpy(skb_push(skb, hc_ptr - head), head, hc_ptr - head); |
8df8c56a5 6lowpan: Moving g... |
1295 |
skb_reset_network_header(skb); |
84ca5e036 6lowpan: iphc: re... |
1296 1297 |
pr_debug("header len %d skb %u ", (int)(hc_ptr - head), skb->len); |
8df8c56a5 6lowpan: Moving g... |
1298 1299 |
raw_dump_table(__func__, "raw skb data dump compressed", |
4710d806f 6lowpan: mac80215... |
1300 |
skb->data, skb->len); |
8df8c56a5 6lowpan: Moving g... |
1301 1302 1303 |
return 0; } EXPORT_SYMBOL_GPL(lowpan_header_compress); |