diff options
author | alex.bluesman.smirnov@gmail.com <alex.bluesman.smirnov@gmail.com> | 2011-11-10 02:40:53 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-14 00:19:43 -0500 |
commit | f8b1b5d231c6db03f87e9db195530156fde47c4b (patch) | |
tree | e8292bc28ee50bcdb11f436f920a4ac3289757a1 /net/ieee802154/6lowpan.c | |
parent | 3bd5b958c2a2dd1a9b4c8d21e75fb47b062fc941 (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/6lowpan.c')
-rw-r--r-- | net/ieee802154/6lowpan.c | 61 |
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 | ||
314 | static int | ||
315 | lowpan_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; | ||
366 | err: | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
314 | static int lowpan_header_create(struct sk_buff *skb, | 370 | static 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); |