diff options
author | Tony Cheneau <tony.cheneau@amnesiak.org> | 2013-03-25 17:59:32 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-26 12:37:58 -0400 |
commit | 24363b67328733ad11ceadffe72a9721a37a3e9e (patch) | |
tree | 2e85baf2b2ad779991166a7a664f7f3ee065887b | |
parent | 43de7aa6ac4e37eaf0a5e83adc0a79d61fe3a55a (diff) | |
download | linux-24363b67328733ad11ceadffe72a9721a37a3e9e.tar.bz2 |
6lowpan: modify udp compression/uncompression to match the standard
The previous code would just compress the UDP header and send the compressed
UDP header along with the uncompressed one.
Signed-off-by: Tony Cheneau <tony.cheneau@amnesiak.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ieee802154/6lowpan.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 276971ba3ade..c9c3f3d18c41 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -284,6 +284,9 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) /* checksum is always inline */ memcpy(*hc06_ptr, &uh->check, 2); *hc06_ptr += 2; + + /* skip the UDP header */ + skb_pull(skb, sizeof(struct udphdr)); } static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val) @@ -309,9 +312,8 @@ static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val) } static int -lowpan_uncompress_udp_header(struct sk_buff *skb) +lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) { - struct udphdr *uh = udp_hdr(skb); u8 tmp; if (!uh) @@ -358,6 +360,14 @@ lowpan_uncompress_udp_header(struct sk_buff *skb) /* copy checksum */ memcpy(&uh->check, &skb->data[0], 2); skb_pull(skb, 2); + + /* + * UDP lenght needs to be infered from the lower layers + * here, we obtain the hint from the remaining size of the + * frame + */ + uh->len = htons(skb->len + sizeof(struct udphdr)); + pr_debug("uncompressed UDP length: src = %d", uh->len); } else { pr_debug("ERROR: unsupported NH format\n"); goto err; @@ -944,8 +954,31 @@ lowpan_process_data(struct sk_buff *skb) /* UDP data uncompression */ if (iphc0 & LOWPAN_IPHC_NH_C) { - if (lowpan_uncompress_udp_header(skb)) + struct udphdr uh; + struct sk_buff *new; + if (lowpan_uncompress_udp_header(skb, &uh)) goto drop; + + /* + * replace the compressed UDP head by the uncompressed UDP + * header + */ + new = skb_copy_expand(skb, sizeof(struct udphdr), + skb_tailroom(skb), GFP_ATOMIC); + kfree_skb(skb); + + if (!new) + return -ENOMEM; + + skb = new; + + skb_push(skb, sizeof(struct udphdr)); + skb_reset_transport_header(skb); + skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); + + lowpan_raw_dump_table(__func__, "raw UDP header dump", + (u8 *)&uh, sizeof(uh)); + hdr.nexthdr = UIP_PROTO_UDP; } |