aboutsummaryrefslogtreecommitdiffstats
path: root/net/ieee802154
diff options
context:
space:
mode:
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: