aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
authorTony Cheneau <tony.cheneau@amnesiak.org>2013-03-25 13:59:32 -0400
committerDavid S. Miller <davem@davemloft.net>2013-03-26 12:37:58 -0400
commit24363b67328733ad11ceadffe72a9721a37a3e9e (patch)
tree2e85baf2b2ad779991166a7a664f7f3ee065887b /net/ieee802154
parent43de7aa6ac4e37eaf0a5e83adc0a79d61fe3a55a (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.c39
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
289static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val) 292static 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
311static int 314static int
312lowpan_uncompress_udp_header(struct sk_buff *skb) 315lowpan_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