aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-rw-r--r--net/6lowpan/Kconfig19
-rw-r--r--net/6lowpan/Makefile5
-rw-r--r--net/6lowpan/iphc.c194
-rw-r--r--net/6lowpan/nhc_udp.c157
4 files changed, 205 insertions, 170 deletions
diff --git a/net/6lowpan/Kconfig b/net/6lowpan/Kconfig
index e4a02ef55102..e45c96321845 100644
--- a/net/6lowpan/Kconfig
+++ b/net/6lowpan/Kconfig
@@ -1,6 +1,23 @@
1config 6LOWPAN 1menuconfig 6LOWPAN
2 tristate "6LoWPAN Support" 2 tristate "6LoWPAN Support"
3 depends on IPV6 3 depends on IPV6
4 ---help--- 4 ---help---
5 This enables IPv6 over Low power Wireless Personal Area Network - 5 This enables IPv6 over Low power Wireless Personal Area Network -
6 "6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks. 6 "6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks.
7
8menuconfig 6LOWPAN_NHC
9 tristate "Next Header Compression Support"
10 depends on 6LOWPAN
11 default y
12 ---help---
13 Support for next header compression.
14
15if 6LOWPAN_NHC
16
17config 6LOWPAN_NHC_UDP
18 tristate "UDP Header Support"
19 default y
20 ---help---
21 6LoWPAN IPv6 UDP Header compression according to RFC6282.
22
23endif
diff --git a/net/6lowpan/Makefile b/net/6lowpan/Makefile
index 4215602a25bd..abf551d31881 100644
--- a/net/6lowpan/Makefile
+++ b/net/6lowpan/Makefile
@@ -1,3 +1,6 @@
1obj-$(CONFIG_6LOWPAN) := 6lowpan.o 1obj-$(CONFIG_6LOWPAN) += 6lowpan.o
2 2
36lowpan-y := iphc.o nhc.o 36lowpan-y := iphc.o nhc.o
4
5#rfc6282 nhcs
6obj-$(CONFIG_6LOWPAN_NHC_UDP) += nhc_udp.o
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");
diff --git a/net/6lowpan/nhc_udp.c b/net/6lowpan/nhc_udp.c
new file mode 100644
index 000000000000..c6bcaeb428ae
--- /dev/null
+++ b/net/6lowpan/nhc_udp.c
@@ -0,0 +1,157 @@
1/*
2 * 6LoWPAN IPv6 UDP compression according to RFC6282
3 *
4 *
5 * Authors:
6 * Alexander Aring <aar@pengutronix.de>
7 *
8 * Orignal written by:
9 * Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
10 * Jon Smirl <jonsmirl@gmail.com>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18#include "nhc.h"
19
20#define LOWPAN_NHC_UDP_IDLEN 1
21
22static int udp_uncompress(struct sk_buff *skb, size_t needed)
23{
24 u8 tmp = 0, val = 0;
25 struct udphdr uh;
26 bool fail;
27 int err;
28
29 fail = lowpan_fetch_skb(skb, &tmp, sizeof(tmp));
30
31 pr_debug("UDP header uncompression\n");
32 switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
33 case LOWPAN_NHC_UDP_CS_P_00:
34 fail |= lowpan_fetch_skb(skb, &uh.source, sizeof(uh.source));
35 fail |= lowpan_fetch_skb(skb, &uh.dest, sizeof(uh.dest));
36 break;
37 case LOWPAN_NHC_UDP_CS_P_01:
38 fail |= lowpan_fetch_skb(skb, &uh.source, sizeof(uh.source));
39 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
40 uh.dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
41 break;
42 case LOWPAN_NHC_UDP_CS_P_10:
43 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
44 uh.source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
45 fail |= lowpan_fetch_skb(skb, &uh.dest, sizeof(uh.dest));
46 break;
47 case LOWPAN_NHC_UDP_CS_P_11:
48 fail |= lowpan_fetch_skb(skb, &val, sizeof(val));
49 uh.source = htons(LOWPAN_NHC_UDP_4BIT_PORT + (val >> 4));
50 uh.dest = htons(LOWPAN_NHC_UDP_4BIT_PORT + (val & 0x0f));
51 break;
52 default:
53 BUG();
54 }
55
56 pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
57 ntohs(uh.source), ntohs(uh.dest));
58
59 /* checksum */
60 if (tmp & LOWPAN_NHC_UDP_CS_C) {
61 pr_debug_ratelimited("checksum elided currently not supported\n");
62 fail = true;
63 } else {
64 fail |= lowpan_fetch_skb(skb, &uh.check, sizeof(uh.check));
65 }
66
67 if (fail)
68 return -EINVAL;
69
70 /* UDP length needs to be infered from the lower layers
71 * here, we obtain the hint from the remaining size of the
72 * frame
73 */
74 uh.len = htons(skb->len + sizeof(struct udphdr));
75 pr_debug("uncompressed UDP length: src = %d", ntohs(uh.len));
76
77 /* replace the compressed UDP head by the uncompressed UDP
78 * header
79 */
80 err = skb_cow(skb, needed);
81 if (unlikely(err))
82 return err;
83
84 skb_push(skb, sizeof(struct udphdr));
85 skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
86
87 return 0;
88}
89
90static int udp_compress(struct sk_buff *skb, u8 **hc_ptr)
91{
92 const struct udphdr *uh = udp_hdr(skb);
93 u8 tmp;
94
95 if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
96 LOWPAN_NHC_UDP_4BIT_PORT) &&
97 ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
98 LOWPAN_NHC_UDP_4BIT_PORT)) {
99 pr_debug("UDP header: both ports compression to 4 bits\n");
100 /* compression value */
101 tmp = LOWPAN_NHC_UDP_CS_P_11;
102 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
103 /* source and destination port */
104 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
105 ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
106 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
107 } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
108 LOWPAN_NHC_UDP_8BIT_PORT) {
109 pr_debug("UDP header: remove 8 bits of dest\n");
110 /* compression value */
111 tmp = LOWPAN_NHC_UDP_CS_P_01;
112 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
113 /* source port */
114 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
115 /* destination port */
116 tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
117 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
118 } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
119 LOWPAN_NHC_UDP_8BIT_PORT) {
120 pr_debug("UDP header: remove 8 bits of source\n");
121 /* compression value */
122 tmp = LOWPAN_NHC_UDP_CS_P_10;
123 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
124 /* source port */
125 tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
126 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
127 /* destination port */
128 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
129 } else {
130 pr_debug("UDP header: can't compress\n");
131 /* compression value */
132 tmp = LOWPAN_NHC_UDP_CS_P_00;
133 lowpan_push_hc_data(hc_ptr, &tmp, sizeof(tmp));
134 /* source port */
135 lowpan_push_hc_data(hc_ptr, &uh->source, sizeof(uh->source));
136 /* destination port */
137 lowpan_push_hc_data(hc_ptr, &uh->dest, sizeof(uh->dest));
138 }
139
140 /* checksum is always inline */
141 lowpan_push_hc_data(hc_ptr, &uh->check, sizeof(uh->check));
142
143 return 0;
144}
145
146static void udp_nhid_setup(struct lowpan_nhc *nhc)
147{
148 nhc->id[0] = LOWPAN_NHC_UDP_ID;
149 nhc->idmask[0] = LOWPAN_NHC_UDP_MASK;
150}
151
152LOWPAN_NHC(nhc_udp, "RFC6282 UDP", NEXTHDR_UDP, sizeof(struct udphdr),
153 udp_nhid_setup, LOWPAN_NHC_UDP_IDLEN, udp_uncompress, udp_compress);
154
155module_lowpan_nhc(nhc_udp);
156MODULE_DESCRIPTION("6LoWPAN next header RFC6282 UDP compression");
157MODULE_LICENSE("GPL");