aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
authorAlexander Aring <alex.aring@gmail.com>2014-02-28 01:32:45 -0500
committerDavid S. Miller <davem@davemloft.net>2014-02-28 17:05:21 -0500
commit96cb3eb7a1a5f0c3598500a2348f7d2cc76afbd2 (patch)
tree9961f2a93ce6b067afe76a9253fa552f9c1d173f /net/ieee802154
parent349aa7bc29ee2469f94bba97bb1c9c270fffa215 (diff)
6lowpan: fix fragmentation on sending side
This patch fix the fragmentation on sending side according to rfc4944. Also add improvement to use the full payload of a PDU which calculate the nearest divided to 8 payload length for the fragmentation datagram size attribute. The main issue is that the datagram size of fragmentation header use the ipv6 payload length, but rfc4944 says it's the ipv6 payload length inclusive network header size (and transport header size if compressed). Signed-off-by: Alexander Aring <alex.aring@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ieee802154')
-rw-r--r--net/ieee802154/6lowpan.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 8edfea5da572..872c8f97a30c 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -422,44 +422,60 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
422static int 422static int
423lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev) 423lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
424{ 424{
425 int err, header_length, payload_length, tag, offset = 0; 425 int err;
426 u16 dgram_offset, dgram_size, payload_length, header_length,
427 lowpan_size, frag_plen, offset, tag;
426 u8 head[5]; 428 u8 head[5];
427 429
428 header_length = skb->mac_len; 430 header_length = skb->mac_len;
429 payload_length = skb->len - header_length; 431 payload_length = skb->len - header_length;
430 tag = lowpan_dev_info(dev)->fragment_tag++; 432 tag = lowpan_dev_info(dev)->fragment_tag++;
433 lowpan_size = skb_network_header_len(skb);
434 dgram_size = lowpan_uncompress_size(skb, &dgram_offset) -
435 header_length;
431 436
432 /* first fragment header */ 437 /* first fragment header */
433 head[0] = LOWPAN_DISPATCH_FRAG1 | ((payload_length >> 8) & 0x7); 438 head[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x7);
434 head[1] = payload_length & 0xff; 439 head[1] = dgram_size & 0xff;
435 head[2] = tag >> 8; 440 head[2] = tag >> 8;
436 head[3] = tag & 0xff; 441 head[3] = tag & 0xff;
437 442
438 err = lowpan_fragment_xmit(skb, head, header_length, LOWPAN_FRAG_SIZE, 443 /* calc the nearest payload length(divided to 8) for first fragment
439 0, LOWPAN_DISPATCH_FRAG1); 444 * which fits into a IEEE802154_MTU
445 */
446 frag_plen = round_down(IEEE802154_MTU - header_length -
447 LOWPAN_FRAG1_HEAD_SIZE - lowpan_size -
448 IEEE802154_MFR_SIZE, 8);
440 449
450 err = lowpan_fragment_xmit(skb, head, header_length,
451 frag_plen + lowpan_size, 0,
452 LOWPAN_DISPATCH_FRAG1);
441 if (err) { 453 if (err) {
442 pr_debug("%s unable to send FRAG1 packet (tag: %d)", 454 pr_debug("%s unable to send FRAG1 packet (tag: %d)",
443 __func__, tag); 455 __func__, tag);
444 goto exit; 456 goto exit;
445 } 457 }
446 458
447 offset = LOWPAN_FRAG_SIZE; 459 offset = lowpan_size + frag_plen;
460 dgram_offset += frag_plen;
448 461
449 /* next fragment header */ 462 /* next fragment header */
450 head[0] &= ~LOWPAN_DISPATCH_FRAG1; 463 head[0] &= ~LOWPAN_DISPATCH_FRAG1;
451 head[0] |= LOWPAN_DISPATCH_FRAGN; 464 head[0] |= LOWPAN_DISPATCH_FRAGN;
452 465
466 frag_plen = round_down(IEEE802154_MTU - header_length -
467 LOWPAN_FRAGN_HEAD_SIZE - IEEE802154_MFR_SIZE, 8);
468
453 while (payload_length - offset > 0) { 469 while (payload_length - offset > 0) {
454 int len = LOWPAN_FRAG_SIZE; 470 int len = frag_plen;
455 471
456 head[4] = offset / 8; 472 head[4] = dgram_offset >> 3;
457 473
458 if (payload_length - offset < len) 474 if (payload_length - offset < len)
459 len = payload_length - offset; 475 len = payload_length - offset;
460 476
461 err = lowpan_fragment_xmit(skb, head, header_length, 477 err = lowpan_fragment_xmit(skb, head, header_length, len,
462 len, offset, LOWPAN_DISPATCH_FRAGN); 478 offset, LOWPAN_DISPATCH_FRAGN);
463 if (err) { 479 if (err) {
464 pr_debug("%s unable to send a subsequent FRAGN packet " 480 pr_debug("%s unable to send a subsequent FRAGN packet "
465 "(tag: %d, offset: %d", __func__, tag, offset); 481 "(tag: %d, offset: %d", __func__, tag, offset);
@@ -467,6 +483,7 @@ lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
467 } 483 }
468 484
469 offset += len; 485 offset += len;
486 dgram_offset += len;
470 } 487 }
471 488
472exit: 489exit: