aboutsummaryrefslogtreecommitdiffstats
path: root/net/6lowpan/iphc.c
diff options
context:
space:
mode:
authorAlexander Aring <alex.aring@gmail.com>2015-01-09 10:42:58 -0500
committerMarcel Holtmann <marcel@holtmann.org>2015-02-14 17:08:44 -0500
commitcc6ed2684751b0a1074b37c080983b6ce737ed22 (patch)
treea000e4ac91ee5afa1fa65c55e5ce5c70cef8009f /net/6lowpan/iphc.c
parent92aa7c65d295f3cbb96904afe335f683e55584b8 (diff)
6lowpan: add udp compression via nhc layer
This patch move UDP header compression and uncompression into the generic 6LoWPAN nhc header compression layer. Moreover this patch activates the nhc layer compression in iphc compression and uncompression functions. Signed-off-by: Alexander Aring <alex.aring@gmail.com> Cc: Martin Townsend <mtownsend1973@gmail.com> Reviewed-by: Stefan Schmidt <s.schmidt@samsung.com> Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/6lowpan/iphc.c')
-rw-r--r--net/6lowpan/iphc.c194
1 files changed, 26 insertions, 168 deletions
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index 32ffec6ef164..390bdd9677df 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -54,6 +54,8 @@
54#include <net/ipv6.h> 54#include <net/ipv6.h>
55#include <net/af_ieee802154.h> 55#include <net/af_ieee802154.h>
56 56
57#include "nhc.h"
58
57/* Uncompress address function for source and 59/* Uncompress address function for source and
58 * destination address(non-multicast). 60 * destination address(non-multicast).
59 * 61 *
@@ -224,77 +226,6 @@ static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
224 return 0; 226 return 0;
225} 227}
226 228
227static int uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
228{
229 bool fail;
230 u8 tmp = 0, val = 0;
231
232 fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
233
234 if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
235 pr_debug("UDP header uncompression\n");
236 switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
237 case LOWPAN_NHC_UDP_CS_P_00:
238 fail |= lowpan_fetch_skb(skb, &uh->source,
239 sizeof(uh->source));
240 fail |= lowpan_fetch_skb(skb, &uh->dest,
241 sizeof(uh->dest));
242 break;
243 case LOWPAN_NHC_UDP_CS_P_01:
244 fail |= lowpan_fetch_skb(skb, &uh->source,
245 sizeof(uh->source));
246 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
247 uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
248 break;
249 case LOWPAN_NHC_UDP_CS_P_10:
250 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
251 uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
252 fail |= lowpan_fetch_skb(skb, &uh->dest,
253 sizeof(uh->dest));
254 break;
255 case LOWPAN_NHC_UDP_CS_P_11:
256 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
257 uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
258 (val >> 4));
259 uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
260 (val & 0x0f));
261 break;
262 default:
263 pr_debug("ERROR: unknown UDP format\n");
264 goto err;
265 }
266
267 pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
268 ntohs(uh->source), ntohs(uh->dest));
269
270 /* checksum */
271 if (tmp & LOWPAN_NHC_UDP_CS_C) {
272 pr_debug_ratelimited("checksum elided currently not supported\n");
273 goto err;
274 } else {
275 fail |= lowpan_fetch_skb(skb, &uh->check,
276 sizeof(uh->check));
277 }
278
279 /* UDP length needs to be infered from the lower layers
280 * here, we obtain the hint from the remaining size of the
281 * frame
282 */
283 uh->len = htons(skb->len + sizeof(struct udphdr));
284 pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
285 } else {
286 pr_debug("ERROR: unsupported NH format\n");
287 goto err;
288 }
289
290 if (fail)
291 goto err;
292
293 return 0;
294err:
295 return -EINVAL;
296}
297
298/* TTL uncompression values */ 229/* TTL uncompression values */
299static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 }; 230static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
300 231
@@ -425,29 +356,11 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
425 return -EINVAL; 356 return -EINVAL;
426 } 357 }
427 358
428 /* UDP data uncompression */ 359 /* Next header data uncompression */
429 if (iphc0 & LOWPAN_IPHC_NH_C) { 360 if (iphc0 & LOWPAN_IPHC_NH_C) {
430 struct udphdr uh; 361 err = lowpan_nhc_do_uncompression(skb, dev, &hdr);
431 const int needed = sizeof(struct udphdr) + sizeof(hdr); 362 if (err < 0)
432
433 if (uncompress_udp_header(skb, &uh))
434 return -EINVAL;
435
436 /* replace the compressed UDP head by the uncompressed UDP
437 * header
438 */
439 err = skb_cow(skb, needed);
440 if (unlikely(err))
441 return err; 363 return err;
442
443 skb_push(skb, sizeof(struct udphdr));
444 skb_reset_transport_header(skb);
445 skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
446
447 raw_dump_table(__func__, "raw UDP header dump",
448 (u8 *)&uh, sizeof(uh));
449
450 hdr.nexthdr = UIP_PROTO_UDP;
451 } else { 364 } else {
452 err = skb_cow(skb, sizeof(hdr)); 365 err = skb_cow(skb, sizeof(hdr));
453 if (unlikely(err)) 366 if (unlikely(err))
@@ -500,71 +413,6 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
500 return rol8(val, shift); 413 return rol8(val, shift);
501} 414}
502 415
503static void compress_udp_header(u8 **hc_ptr, struct sk_buff *skb)
504{
505 struct udphdr *uh;
506 u8 tmp;
507
508 /* In the case of RAW sockets the transport header is not set by
509 * the ip6 stack so we must set it ourselves
510 */
511 if (skb->transport_header == skb->network_header)
512 skb_set_transport_header(skb, sizeof(struct ipv6hdr));
513
514 uh = udp_hdr(skb);
515
516 if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
517 LOWPAN_NHC_UDP_4BIT_PORT) &&
518 ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
519 LOWPAN_NHC_UDP_4BIT_PORT)) {
520 pr_debug("UDP header: both ports compression to 4 bits\n");
521 /* compression value */
522 tmp = LOWPAN_NHC_UDP_CS_P_11;
523 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
524 /* source and destination port */
525 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
526 ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
527 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
528 } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
529 LOWPAN_NHC_UDP_8BIT_PORT) {
530 pr_debug("UDP header: remove 8 bits of dest\n");
531 /* compression value */
532 tmp = LOWPAN_NHC_UDP_CS_P_01;
533 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
534 /* source port */
535 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
536 /* destination port */
537 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
538 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
539 } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
540 LOWPAN_NHC_UDP_8BIT_PORT) {
541 pr_debug("UDP header: remove 8 bits of source\n");
542 /* compression value */
543 tmp = LOWPAN_NHC_UDP_CS_P_10;
544 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
545 /* source port */
546 tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
547 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
548 /* destination port */
549 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
550 } else {
551 pr_debug("UDP header: can't compress\n");
552 /* compression value */
553 tmp = LOWPAN_NHC_UDP_CS_P_00;
554 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
555 /* source port */
556 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
557 /* destination port */
558 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
559 }
560
561 /* checksum is always inline */
562 lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
563
564 /* skip the UDP header */
565 skb_pull(skb, sizeof(struct udphdr));
566}
567
568int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev, 416int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
569 unsigned short type, const void *_daddr, 417 unsigned short type, const void *_daddr,
570 const void *_saddr, unsigned int len) 418 const void *_saddr, unsigned int len)
@@ -572,7 +420,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
572 u8 tmp, iphc0, iphc1, *hc_ptr; 420 u8 tmp, iphc0, iphc1, *hc_ptr;
573 struct ipv6hdr *hdr; 421 struct ipv6hdr *hdr;
574 u8 head[100] = {}; 422 u8 head[100] = {};
575 int addr_type; 423 int ret, addr_type;
576 424
577 if (type != ETH_P_IPV6) 425 if (type != ETH_P_IPV6)
578 return -EINVAL; 426 return -EINVAL;
@@ -649,13 +497,12 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
649 497
650 /* NOTE: payload length is always compressed */ 498 /* NOTE: payload length is always compressed */
651 499
652 /* Next Header is compress if UDP */ 500 /* Check if we provide the nhc format for nexthdr and compression
653 if (hdr->nexthdr == UIP_PROTO_UDP) 501 * functionality. If not nexthdr is handled inline and not compressed.
654 iphc0 |= LOWPAN_IPHC_NH_C; 502 */
655 503 ret = lowpan_nhc_check_compression(skb, hdr, &hc_ptr, &iphc0);
656 if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) 504 if (ret < 0)
657 lowpan_push_hc_data(&hc_ptr, &hdr->nexthdr, 505 return ret;
658 sizeof(hdr->nexthdr));
659 506
660 /* Hop limit 507 /* Hop limit
661 * if 1: compress, encoding is 01 508 * if 1: compress, encoding is 01
@@ -741,9 +588,12 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
741 } 588 }
742 } 589 }
743 590
744 /* UDP header compression */ 591 /* next header compression */
745 if (hdr->nexthdr == UIP_PROTO_UDP) 592 if (iphc0 & LOWPAN_IPHC_NH_C) {
746 compress_udp_header(&hc_ptr, skb); 593 ret = lowpan_nhc_do_compression(skb, hdr, &hc_ptr);
594 if (ret < 0)
595 return ret;
596 }
747 597
748 head[0] = iphc0; 598 head[0] = iphc0;
749 head[1] = iphc1; 599 head[1] = iphc1;
@@ -761,4 +611,12 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
761} 611}
762EXPORT_SYMBOL_GPL(lowpan_header_compress); 612EXPORT_SYMBOL_GPL(lowpan_header_compress);
763 613
614static int __init lowpan_module_init(void)
615{
616 request_module_nowait("nhc_udp");
617
618 return 0;
619}
620module_init(lowpan_module_init);
621
764MODULE_LICENSE("GPL"); 622MODULE_LICENSE("GPL");