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 offset 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.ar...@gmail.com> --- net/ieee802154/6lowpan.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c index 426b5df..7182072 100644 --- a/net/ieee802154/6lowpan.c +++ b/net/ieee802154/6lowpan.c @@ -374,6 +374,7 @@ lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb) memcpy(*hc06_ptr, &uh->check, 2); *hc06_ptr += 2; + mac_cb(skb)->frag_info.d_offset += sizeof(struct udphdr); /* skip the UDP header */ skb_pull(skb, sizeof(struct udphdr)); } @@ -484,6 +485,7 @@ static int lowpan_header_create(struct sk_buff *skb, if (type != ETH_P_IPV6) return 0; + mac_cb(skb)->frag_info.d_offset = 0; hdr = ipv6_hdr(skb); hc06_ptr = head + 2; @@ -653,6 +655,11 @@ static int lowpan_header_create(struct sk_buff *skb, head[0] = iphc0; head[1] = iphc1; + /* Before replace ipv6hdr to 6lowpan header we save the dgram_size */ + mac_cb(skb)->frag_info.d_size = ntohs(hdr->payload_len) + + sizeof(struct ipv6hdr); + mac_cb(skb)->frag_info.d_offset += sizeof(struct ipv6hdr); + skb_pull(skb, sizeof(struct ipv6hdr)); skb_reset_transport_header(skb); memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head); @@ -1141,44 +1148,58 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head, static int lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev) { - int err, header_length, payload_length, tag, offset = 0; + int err, header_length, payload_length, tag, dgram_size, + dgram_offset, lowpan_size, frag_plen, offset = 0; u8 head[5]; header_length = skb->mac_len; payload_length = skb->len - header_length; tag = lowpan_dev_info(dev)->fragment_tag++; + lowpan_size = skb_network_header_len(skb); + dgram_size = mac_cb(skb)->frag_info.d_size; /* first fragment header */ - head[0] = LOWPAN_DISPATCH_FRAG1 | ((payload_length >> 8) & 0x7); - head[1] = payload_length & 0xff; + head[0] = LOWPAN_DISPATCH_FRAG1 | ((dgram_size >> 8) & 0x7); + head[1] = dgram_size & 0xff; head[2] = tag >> 8; head[3] = tag & 0xff; - err = lowpan_fragment_xmit(skb, head, header_length, LOWPAN_FRAG_SIZE, - 0, LOWPAN_DISPATCH_FRAG1); + /* calc the nearest payload length(divided to 8) for first fragment + * which fits into a IEEE802154_MTU + */ + frag_plen = round_down(IEEE802154_MTU - header_length - + LOWPAN_FRAG1_HEAD_SIZE - lowpan_size - + IEEE802154_MFR_SIZE, 8); + err = lowpan_fragment_xmit(skb, head, header_length, + frag_plen + lowpan_size, 0, + LOWPAN_DISPATCH_FRAG1); if (err) { pr_debug("%s unable to send FRAG1 packet (tag: %d)", __func__, tag); goto exit; } - offset = LOWPAN_FRAG_SIZE; + offset = lowpan_size + frag_plen; + dgram_offset = mac_cb(skb)->frag_info.d_offset + frag_plen; /* next fragment header */ head[0] &= ~LOWPAN_DISPATCH_FRAG1; head[0] |= LOWPAN_DISPATCH_FRAGN; + frag_plen = round_down(IEEE802154_MTU - header_length - + LOWPAN_FRAGN_HEAD_SIZE - IEEE802154_MFR_SIZE, 8); + while (payload_length - offset > 0) { - int len = LOWPAN_FRAG_SIZE; + int len = frag_plen; - head[4] = offset / 8; + head[4] = dgram_offset / 8; if (payload_length - offset < len) len = payload_length - offset; - err = lowpan_fragment_xmit(skb, head, header_length, - len, offset, LOWPAN_DISPATCH_FRAGN); + err = lowpan_fragment_xmit(skb, head, header_length, len, + offset, LOWPAN_DISPATCH_FRAGN); if (err) { pr_debug("%s unable to send a subsequent FRAGN packet " "(tag: %d, offset: %d", __func__, tag, offset); @@ -1186,6 +1207,7 @@ lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev) } offset += len; + dgram_offset += len; } exit: -- 1.8.4.2 ------------------------------------------------------------------------------ Sponsored by Intel(R) XDK Develop, test and display web and hybrid apps with a single code base. Download it for free now! http://pubads.g.doubleclick.net/gampad/clk?id=111408631&iu=/4140/ostg.clktrk _______________________________________________ Linux-zigbee-devel mailing list Linux-zigbee-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-zigbee-devel