aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
authoralex.bluesman.smirnov@gmail.com <alex.bluesman.smirnov@gmail.com>2011-11-10 02:40:53 -0500
committerDavid S. Miller <davem@davemloft.net>2011-11-14 00:19:43 -0500
commitf8b1b5d231c6db03f87e9db195530156fde47c4b (patch)
treee8292bc28ee50bcdb11f436f920a4ac3289757a1 /net/ieee802154
parent3bd5b958c2a2dd1a9b4c8d21e75fb47b062fc941 (diff)
6LoWPAN: UDP header decompression
This patch provides possibility to decompress UDP headers. Derived from Contiki OS. Signed-off-by: Alexander Smirnov <alex.bluesman.smirnov@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ieee802154')
-rw-r--r--net/ieee802154/6lowpan.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 9bf82d72bb9e..602f318a8d62 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -311,6 +311,62 @@ static u16 lowpan_fetch_skb_u16(struct sk_buff *skb)
311 return ret; 311 return ret;
312} 312}
313 313
314static int
315lowpan_uncompress_udp_header(struct sk_buff *skb)
316{
317 struct udphdr *uh = udp_hdr(skb);
318 u8 tmp;
319
320 tmp = lowpan_fetch_skb_u8(skb);
321
322 if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
323 pr_debug("(%s): UDP header uncompression\n", __func__);
324 switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
325 case LOWPAN_NHC_UDP_CS_P_00:
326 memcpy(&uh->source, &skb->data[0], 2);
327 memcpy(&uh->dest, &skb->data[2], 2);
328 skb_pull(skb, 4);
329 break;
330 case LOWPAN_NHC_UDP_CS_P_01:
331 memcpy(&uh->source, &skb->data[0], 2);
332 uh->dest =
333 skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT;
334 skb_pull(skb, 3);
335 break;
336 case LOWPAN_NHC_UDP_CS_P_10:
337 uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT;
338 memcpy(&uh->dest, &skb->data[1], 2);
339 skb_pull(skb, 3);
340 break;
341 case LOWPAN_NHC_UDP_CS_P_11:
342 uh->source =
343 LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4);
344 uh->dest =
345 LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f);
346 skb_pull(skb, 1);
347 break;
348 default:
349 pr_debug("(%s) ERROR: unknown UDP format\n", __func__);
350 goto err;
351 break;
352 }
353
354 pr_debug("(%s): uncompressed UDP ports: src = %d, dst = %d\n",
355 __func__, uh->source, uh->dest);
356
357 /* copy checksum */
358 memcpy(&uh->check, &skb->data[0], 2);
359 skb_pull(skb, 2);
360 } else {
361 pr_debug("(%s): ERROR: unsupported NH format\n", __func__);
362 goto err;
363 }
364
365 return 0;
366err:
367 return -EINVAL;
368}
369
314static int lowpan_header_create(struct sk_buff *skb, 370static int lowpan_header_create(struct sk_buff *skb,
315 struct net_device *dev, 371 struct net_device *dev,
316 unsigned short type, const void *_daddr, 372 unsigned short type, const void *_daddr,
@@ -842,7 +898,10 @@ lowpan_process_data(struct sk_buff *skb)
842 goto drop; 898 goto drop;
843 } 899 }
844 900
845 /* TODO: UDP header parse */ 901 /* UDP data uncompression */
902 if (iphc0 & LOWPAN_IPHC_NH_C)
903 if (lowpan_uncompress_udp_header(skb))
904 goto drop;
846 905
847 /* Not fragmented package */ 906 /* Not fragmented package */
848 hdr.payload_len = htons(skb->len); 907 hdr.payload_len = htons(skb->len);