diff options
author | Tony Cheneau <tony.cheneau@amnesiak.org> | 2013-03-25 13:59:32 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-26 12:37:58 -0400 |
commit | 24363b67328733ad11ceadffe72a9721a37a3e9e (patch) | |
tree | 2e85baf2b2ad779991166a7a664f7f3ee065887b /net/ieee802154 | |
parent | 43de7aa6ac4e37eaf0a5e83adc0a79d61fe3a55a (diff) |
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>
Diffstat (limited to 'net/ieee802154')
-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) | |||
284 | /* checksum is always inline */ | 284 | /* checksum is always inline */ |
285 | memcpy(*hc06_ptr, &uh->check, 2); | 285 | memcpy(*hc06_ptr, &uh->check, 2); |
286 | *hc06_ptr += 2; | 286 | *hc06_ptr += 2; |
287 | |||
288 | /* skip the UDP header */ | ||
289 | skb_pull(skb, sizeof(struct udphdr)); | ||
287 | } | 290 | } |
288 | 291 | ||
289 | static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val) | 292 | 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) | |||
309 | } | 312 | } |
310 | 313 | ||
311 | static int | 314 | static int |
312 | lowpan_uncompress_udp_header(struct sk_buff *skb) | 315 | lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh) |
313 | { | 316 | { |
314 | struct udphdr *uh = udp_hdr(skb); | ||
315 | u8 tmp; | 317 | u8 tmp; |
316 | 318 | ||
317 | if (!uh) | 319 | if (!uh) |
@@ -358,6 +360,14 @@ lowpan_uncompress_udp_header(struct sk_buff *skb) | |||
358 | /* copy checksum */ | 360 | /* copy checksum */ |
359 | memcpy(&uh->check, &skb->data[0], 2); | 361 | memcpy(&uh->check, &skb->data[0], 2); |
360 | skb_pull(skb, 2); | 362 | skb_pull(skb, 2); |
363 | |||
364 | /* | ||
365 | * UDP lenght needs to be infered from the lower layers | ||
366 | * here, we obtain the hint from the remaining size of the | ||
367 | * frame | ||
368 | */ | ||
369 | uh->len = htons(skb->len + sizeof(struct udphdr)); | ||
370 | pr_debug("uncompressed UDP length: src = %d", uh->len); | ||
361 | } else { | 371 | } else { |
362 | pr_debug("ERROR: unsupported NH format\n"); | 372 | pr_debug("ERROR: unsupported NH format\n"); |
363 | goto err; | 373 | goto err; |
@@ -944,8 +954,31 @@ lowpan_process_data(struct sk_buff *skb) | |||
944 | 954 | ||
945 | /* UDP data uncompression */ | 955 | /* UDP data uncompression */ |
946 | if (iphc0 & LOWPAN_IPHC_NH_C) { | 956 | if (iphc0 & LOWPAN_IPHC_NH_C) { |
947 | if (lowpan_uncompress_udp_header(skb)) | 957 | struct udphdr uh; |
958 | struct sk_buff *new; | ||
959 | if (lowpan_uncompress_udp_header(skb, &uh)) | ||
948 | goto drop; | 960 | goto drop; |
961 | |||
962 | /* | ||
963 | * replace the compressed UDP head by the uncompressed UDP | ||
964 | * header | ||
965 | */ | ||
966 | new = skb_copy_expand(skb, sizeof(struct udphdr), | ||
967 | skb_tailroom(skb), GFP_ATOMIC); | ||
968 | kfree_skb(skb); | ||
969 | |||
970 | if (!new) | ||
971 | return -ENOMEM; | ||
972 | |||
973 | skb = new; | ||
974 | |||
975 | skb_push(skb, sizeof(struct udphdr)); | ||
976 | skb_reset_transport_header(skb); | ||
977 | skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr)); | ||
978 | |||
979 | lowpan_raw_dump_table(__func__, "raw UDP header dump", | ||
980 | (u8 *)&uh, sizeof(uh)); | ||
981 | |||
949 | hdr.nexthdr = UIP_PROTO_UDP; | 982 | hdr.nexthdr = UIP_PROTO_UDP; |
950 | } | 983 | } |
951 | 984 | ||