All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH net-next v4 0/8] 6lowpan: reimplementation of fragmentation handling
@ 2014-02-26 16:05 Alexander Aring
  2014-02-26 16:05 ` [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function Alexander Aring
                   ` (5 more replies)
  0 siblings, 6 replies; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend,
	Alexander Aring

Hi,

this patch series reimplementation the fragmentation handling of 6lowpan
accroding to rfc4944 [1].

The first big note is, that the current fragmentation behaviour isn't rfc
complaint. The main issue is a wrong datagram_size value which needs to be:
datagram_size = ipv6_payload + ipv6 header + (maybe compressed transport header,
                currently only udp is supported)

but the current datagram_size value is calculated as:
datagram_size = ipv6_payload

Fragmentation work in a linux<->linux communication only.


Why reimplementation?

I reimplemted the reassembly side only. The current behaviour is to allocate a
skb with the reassembled size and hold all fragments in a list, protected by a
spinlock. After we received all fragments (detected by the sum of all fragments,
it begins to place all fragments into the allocated skb).

This reassembly implementation has some race condition. Additional I make it more
rfc complaint. The current implementation match on the tag value inside the frag
header only, but rfc4944 says we need to match on dst addr(mac), src addr(mac),
tag value, datagram_size value. [2]

The new reassembly handling use the inet_frag api (I mean the callback interface
of ipv6 and ipv4 reassembly). I looked into ipv6 and wanted to see how ipv6 is
dealing with reassembly, so I based my code on this implementation.



On the sending side to generate the fragments I improved the current code to use
the nearest 8 divided payload. (We can do that, because the mac layer has a
dynamic size, so it depends on mac_header how big we can do the payload).

Of course I fix also the reassembly/sending side to be rfc complaint now.

Regards
Alexander Aring

[1] http://tools.ietf.org/html/rfc4944
[2] http://tools.ietf.org/html/rfc4944#section-5.3

changes since v2:
 - rework checkpatch code style issue patch.
   Merge two pr_debugs into one pr_debug.

changes since v3:
 - rename 6lowpan.ko to 6lowpan_rtnl.c in commit msg of patch 5/8.

changes since v4:
 - Add a new patch 2/8 to introduce lowpan_uncompress_size function. Also
   improving this function a little bit.
 - Add a new patch 4/8 to change tag value to __be16.
 - use skb_header_reset function on FRAG1 only, which should have the
   lowpan header. See lowpan_get_frag_info function. (slightly improving
   of fragmentation header parsing).
 - changes types of variables to u16 in lowpan_skb_fragmentation.
 - use lowpan_uncompress_size instead of storing necessary information
   in skb control block, this can be destroyed after dev_queue_xmit call.
   Thanks David for this hint.
 - remove Tested-by: Martin Townsend <martin.townsend@xsilon.com>, because
   too many funcionality change.

Alexander Aring (8):
  6lowpan: add frag information struct
  6lowpan: add uncompress header size function
  6lowpan: fix fragmentation on sending side
  6lowpan: change tag type to __be16
  6lowpan: move 6lowpan.c to 6lowpan_rtnl.c
  6lowpan: fix some checkpatch issues
  net: ns: add ieee802154_6lowpan namespace
  6lowpan: handling 6lowpan fragmentation via inet_frag api

 include/net/ieee802154_netdev.h              |   7 +
 include/net/net_namespace.h                  |   4 +
 include/net/netns/ieee802154_6lowpan.h       |  22 ++
 net/ieee802154/6lowpan.h                     | 116 ++++++
 net/ieee802154/{6lowpan.c => 6lowpan_rtnl.c} | 323 +++++----------
 net/ieee802154/Makefile                      |   1 +
 net/ieee802154/reassembly.c                  | 565 +++++++++++++++++++++++++++
 net/ieee802154/reassembly.h                  |  66 ++++
 8 files changed, 868 insertions(+), 236 deletions(-)
 create mode 100644 include/net/netns/ieee802154_6lowpan.h
 rename net/ieee802154/{6lowpan.c => 6lowpan_rtnl.c} (70%)
 create mode 100644 net/ieee802154/reassembly.c
 create mode 100644 net/ieee802154/reassembly.h

-- 
1.9.0

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH net-next v4 1/8] 6lowpan: add frag information struct
       [not found] ` <1393430712-11298-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2014-02-26 16:05   ` Alexander Aring
  2014-02-26 16:05   ` [PATCH net-next v4 4/8] 6lowpan: change tag type to __be16 Alexander Aring
  2014-02-26 16:05   ` [PATCH net-next v4 6/8] 6lowpan: fix some checkpatch issues Alexander Aring
  2 siblings, 0 replies; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q

This patch adds a 6lowpan fragmentation struct into cb of skb which
is necessary to hold fragmentation information.

Signed-off-by: Alexander Aring <alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 include/net/ieee802154_netdev.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/include/net/ieee802154_netdev.h b/include/net/ieee802154_netdev.h
index 8196d5d..97b2e34 100644
--- a/include/net/ieee802154_netdev.h
+++ b/include/net/ieee802154_netdev.h
@@ -29,6 +29,12 @@
 
 #include <net/af_ieee802154.h>
 
+struct ieee802154_frag_info {
+	__be16 d_tag;
+	u16 d_size;
+	u8 d_offset;
+};
+
 /*
  * A control block of skb passed between the ARPHRD_IEEE802154 device
  * and other stack parts.
@@ -39,6 +45,7 @@ struct ieee802154_mac_cb {
 	struct ieee802154_addr da;
 	u8 flags;
 	u8 seq;
+	struct ieee802154_frag_info frag_info;
 };
 
 static inline struct ieee802154_mac_cb *mac_cb(struct sk_buff *skb)
-- 
1.9.0


------------------------------------------------------------------------------
Flow-based real-time traffic analytics software. Cisco certified tool.
Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer
Customize your own dashboards, set traffic alerts and generate reports.
Network behavioral analysis & security monitoring. All-in-one tool.
http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function
  2014-02-26 16:05 [PATCH net-next v4 0/8] 6lowpan: reimplementation of fragmentation handling Alexander Aring
@ 2014-02-26 16:05 ` Alexander Aring
  2014-02-26 16:10   ` David Laight
  2014-02-26 16:05 ` [PATCH net-next v4 3/8] 6lowpan: fix fragmentation on sending side Alexander Aring
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend,
	Alexander Aring

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
---
 net/ieee802154/6lowpan.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
index 2b835db..b6ae0bc 100644
--- a/net/ieee802154/6lowpan.h
+++ b/net/ieee802154/6lowpan.h
@@ -306,6 +306,122 @@ static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
 	*hc_ptr += len;
 }
 
+static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
+{
+	switch (addr_mode) {
+	case LOWPAN_IPHC_ADDR_00:
+		return 16;
+	case LOWPAN_IPHC_ADDR_01:
+		return 8;
+	case LOWPAN_IPHC_ADDR_02:
+		return 2;
+	default:
+		return 0;
+	}
+}
+
+static inline u8 lowpan_next_hdr_size(const u8 h_enc, u16 *uncomp_header)
+{
+	u8 ret = 1;
+
+	if ((h_enc & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+		*uncomp_header += sizeof(struct udphdr);
+
+		switch (h_enc & LOWPAN_NHC_UDP_CS_P_11) {
+		case LOWPAN_NHC_UDP_CS_P_00:
+			ret += 4;
+			break;
+		case LOWPAN_NHC_UDP_CS_P_01:
+		case LOWPAN_NHC_UDP_CS_P_10:
+			ret += 3;
+			break;
+		case LOWPAN_NHC_UDP_CS_P_11:
+			ret++;
+			break;
+		default:
+			break;
+		}
+
+		if (!(h_enc & LOWPAN_NHC_UDP_CS_C))
+			ret += 2;
+	}
+
+	return ret;
+}
+
+/**
+ *	lowpan_uncompress_size - returns skb->len size with uncompressed header
+ *	@skb: sk_buff with 6lowpan header inside
+ *	@datagram_offset: optional to get the datagram_offset value
+ *
+ *	Returns the skb->len with uncompressed header
+ */
+static inline u16
+lowpan_uncompress_size(const struct sk_buff *skb, u16 *dgram_offset)
+{
+	u16 ret = 2, uncomp_header = sizeof(struct ipv6hdr);
+	u8 iphc0, iphc1, h_enc;
+
+	iphc0 = skb_network_header(skb)[0];
+	iphc1 = skb_network_header(skb)[1];
+
+	switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
+	case 0:
+		ret += 4;
+		break;
+	case 1:
+		ret += 3;
+		break;
+	case 2:
+		ret++;
+		break;
+	default:
+		break;
+	}
+
+	if (!(iphc0 & LOWPAN_IPHC_NH_C))
+		ret++;
+
+	if (!(iphc0 & 0x03))
+		ret++;
+
+	ret += lowpan_addr_mode_size((iphc1 & LOWPAN_IPHC_SAM) >>
+				     LOWPAN_IPHC_SAM_BIT);
+
+	if (iphc1 & LOWPAN_IPHC_M) {
+		switch ((iphc1 & LOWPAN_IPHC_DAM_11) >>
+			LOWPAN_IPHC_DAM_BIT) {
+		case LOWPAN_IPHC_DAM_00:
+			ret += 16;
+			break;
+		case LOWPAN_IPHC_DAM_01:
+			ret += 6;
+			break;
+		case LOWPAN_IPHC_DAM_10:
+			ret += 4;
+			break;
+		case LOWPAN_IPHC_DAM_11:
+			ret++;
+			break;
+		default:
+			break;
+		}
+	} else {
+		ret += lowpan_addr_mode_size((iphc1 & LOWPAN_IPHC_DAM_11) >>
+					     LOWPAN_IPHC_DAM_BIT);
+	}
+
+	if (iphc0 & LOWPAN_IPHC_NH_C) {
+		h_enc = skb_network_header(skb)[ret];
+		ret += lowpan_next_hdr_size(h_enc, &uncomp_header);
+	}
+
+	if (dgram_offset)
+		*dgram_offset = uncomp_header;
+
+	return skb->len + uncomp_header - ret;
+}
+
 typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
 
 int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH net-next v4 3/8] 6lowpan: fix fragmentation on sending side
  2014-02-26 16:05 [PATCH net-next v4 0/8] 6lowpan: reimplementation of fragmentation handling Alexander Aring
  2014-02-26 16:05 ` [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function Alexander Aring
@ 2014-02-26 16:05 ` Alexander Aring
       [not found] ` <1393430712-11298-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend,
	Alexander Aring

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>
---
 net/ieee802154/6lowpan.c | 37 +++++++++++++++++++++++++++----------
 1 file changed, 27 insertions(+), 10 deletions(-)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 8edfea5..872c8f9 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -422,44 +422,60 @@ 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;
+	u16 dgram_offset, dgram_size, payload_length, header_length,
+	    lowpan_size, frag_plen, offset, tag;
 	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 = lowpan_uncompress_size(skb, &dgram_offset) -
+		     header_length;
 
 	/* 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 += 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 >> 3;
 
 		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);
@@ -467,6 +483,7 @@ lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
 		}
 
 		offset += len;
+		dgram_offset += len;
 	}
 
 exit:
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH net-next v4 4/8] 6lowpan: change tag type to __be16
       [not found] ` <1393430712-11298-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2014-02-26 16:05   ` [PATCH net-next v4 1/8] 6lowpan: add frag information struct Alexander Aring
@ 2014-02-26 16:05   ` Alexander Aring
  2014-02-26 16:05   ` [PATCH net-next v4 6/8] 6lowpan: fix some checkpatch issues Alexander Aring
  2 siblings, 0 replies; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q

Signed-off-by: Alexander Aring <alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 net/ieee802154/6lowpan.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 872c8f9..6b7d17f 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -68,7 +68,7 @@ static LIST_HEAD(lowpan_devices);
 struct lowpan_dev_info {
 	struct net_device	*real_dev; /* real WPAN device ptr */
 	struct mutex		dev_list_mtx; /* mutex for list ops */
-	unsigned short		fragment_tag;
+	__be16			fragment_tag;
 };
 
 struct lowpan_dev_record {
@@ -424,7 +424,8 @@ lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
 {
 	int err;
 	u16 dgram_offset, dgram_size, payload_length, header_length,
-	    lowpan_size, frag_plen, offset, tag;
+	    lowpan_size, frag_plen, offset;
+	__be16 tag;
 	u8 head[5];
 
 	header_length = skb->mac_len;
-- 
1.9.0


------------------------------------------------------------------------------
Flow-based real-time traffic analytics software. Cisco certified tool.
Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer
Customize your own dashboards, set traffic alerts and generate reports.
Network behavioral analysis & security monitoring. All-in-one tool.
http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH net-next v4 5/8] 6lowpan: move 6lowpan.c to 6lowpan_rtnl.c
  2014-02-26 16:05 [PATCH net-next v4 0/8] 6lowpan: reimplementation of fragmentation handling Alexander Aring
                   ` (2 preceding siblings ...)
       [not found] ` <1393430712-11298-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2014-02-26 16:05 ` Alexander Aring
  2014-02-26 16:05 ` [PATCH net-next v4 7/8] net: ns: add ieee802154_6lowpan namespace Alexander Aring
  2014-02-26 16:05 ` [PATCH net-next v4 8/8] 6lowpan: handling 6lowpan fragmentation via inet_frag api Alexander Aring
  5 siblings, 0 replies; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend,
	Alexander Aring

We have a 6lowpan.c file and 6lowpan.ko file. To avoid confusing we
should move 6lowpan.c to 6lowpan_rtnl.c. Then we can support multiple
source files for 6lowpan module.

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
---
 net/ieee802154/{6lowpan.c => 6lowpan_rtnl.c} | 0
 net/ieee802154/Makefile                      | 1 +
 2 files changed, 1 insertion(+)
 rename net/ieee802154/{6lowpan.c => 6lowpan_rtnl.c} (100%)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan_rtnl.c
similarity index 100%
rename from net/ieee802154/6lowpan.c
rename to net/ieee802154/6lowpan_rtnl.c
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index e8f0588..3d08adf 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -2,5 +2,6 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
 obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
 obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o
 
+6lowpan-y := 6lowpan_rtnl.o
 ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
 af_802154-y := af_ieee802154.o raw.o dgram.o
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH net-next v4 6/8] 6lowpan: fix some checkpatch issues
       [not found] ` <1393430712-11298-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2014-02-26 16:05   ` [PATCH net-next v4 1/8] 6lowpan: add frag information struct Alexander Aring
  2014-02-26 16:05   ` [PATCH net-next v4 4/8] 6lowpan: change tag type to __be16 Alexander Aring
@ 2014-02-26 16:05   ` Alexander Aring
       [not found]     ` <1393430712-11298-7-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  2 siblings, 1 reply; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q

Detected with:

./scripts/checkpatch.pl --strict -f net/ieee802154/6lowpan_rtnl.c

Signed-off-by: Alexander Aring <alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 net/ieee802154/6lowpan_rtnl.c | 27 +++++++++------------------
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
index 6b7d17f..f9c9548 100644
--- a/net/ieee802154/6lowpan_rtnl.c
+++ b/net/ieee802154/6lowpan_rtnl.c
@@ -1,10 +1,8 @@
-/*
- * Copyright 2011, Siemens AG
+/* Copyright 2011, Siemens AG
  * written by Alexander Smirnov <alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  */
 
-/*
- * Based on patches from Jon Smirl <jonsmirl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+/* Based on patches from Jon Smirl <jonsmirl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  * Copyright (c) 2011 Jon Smirl <jonsmirl-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -15,10 +13,6 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
 /* Jon's code is based on 6lowpan implementation for Contiki which is:
@@ -124,13 +118,11 @@ static int lowpan_header_create(struct sk_buff *skb,
 
 	lowpan_header_compress(skb, dev, type, daddr, saddr, len);
 
-	/*
-	 * NOTE1: I'm still unsure about the fact that compression and WPAN
+	/* NOTE1: I'm still unsure about the fact that compression and WPAN
 	 * header are created here and not later in the xmit. So wait for
 	 * an opinion of net maintainers.
 	 */
-	/*
-	 * NOTE2: to be absolutely correct, we must derive PANid information
+	/* NOTE2: to be absolutely correct, we must derive PANid information
 	 * from MAC subif of the 'dev' and 'real_dev' network devices, but
 	 * this isn't implemented in mainline yet, so currently we assign 0xff
 	 */
@@ -145,8 +137,7 @@ static int lowpan_header_create(struct sk_buff *skb,
 	/* intra-PAN communications */
 	da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
-	/*
-	 * if the destination address is the broadcast address, use the
+	/* if the destination address is the broadcast address, use the
 	 * corresponding short address
 	 */
 	if (lowpan_is_addr_broadcast(daddr)) {
@@ -386,7 +377,7 @@ static int lowpan_set_address(struct net_device *dev, void *p)
 
 static int
 lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
-			int mlen, int plen, int offset, int type)
+		     int mlen, int plen, int offset, int type)
 {
 	struct sk_buff *frag;
 	int hlen;
@@ -478,8 +469,8 @@ lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
 		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);
+			pr_debug("%s unable to send a FRAGN packet. (tag: %d, offset: %d)\n",
+				 __func__, tag, offset);
 			goto exit;
 		}
 
@@ -686,7 +677,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *dev,
 	lowpan_dev_info(dev)->fragment_tag = 0;
 	mutex_init(&lowpan_dev_info(dev)->dev_list_mtx);
 
-	entry = kzalloc(sizeof(struct lowpan_dev_record), GFP_KERNEL);
+	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 	if (!entry) {
 		dev_put(real_dev);
 		lowpan_dev_info(dev)->real_dev = NULL;
-- 
1.9.0


------------------------------------------------------------------------------
Flow-based real-time traffic analytics software. Cisco certified tool.
Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer
Customize your own dashboards, set traffic alerts and generate reports.
Network behavioral analysis & security monitoring. All-in-one tool.
http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH net-next v4 7/8] net: ns: add ieee802154_6lowpan namespace
  2014-02-26 16:05 [PATCH net-next v4 0/8] 6lowpan: reimplementation of fragmentation handling Alexander Aring
                   ` (3 preceding siblings ...)
  2014-02-26 16:05 ` [PATCH net-next v4 5/8] 6lowpan: move 6lowpan.c to 6lowpan_rtnl.c Alexander Aring
@ 2014-02-26 16:05 ` Alexander Aring
  2014-02-26 16:05 ` [PATCH net-next v4 8/8] 6lowpan: handling 6lowpan fragmentation via inet_frag api Alexander Aring
  5 siblings, 0 replies; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend,
	Alexander Aring

This patch adds necessary ieee802154 6lowpan namespace to provide the
inet_frag information. This is a initial support for handling 6lowpan
fragmentation with the inet_frag api.

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
---
 include/net/net_namespace.h            |  4 ++++
 include/net/netns/ieee802154_6lowpan.h | 13 +++++++++++++
 2 files changed, 17 insertions(+)
 create mode 100644 include/net/netns/ieee802154_6lowpan.h

diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 991dcd9..79387f7 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -15,6 +15,7 @@
 #include <net/netns/packet.h>
 #include <net/netns/ipv4.h>
 #include <net/netns/ipv6.h>
+#include <net/netns/ieee802154_6lowpan.h>
 #include <net/netns/sctp.h>
 #include <net/netns/dccp.h>
 #include <net/netns/netfilter.h>
@@ -90,6 +91,9 @@ struct net {
 #if IS_ENABLED(CONFIG_IPV6)
 	struct netns_ipv6	ipv6;
 #endif
+#if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN)
+	struct netns_ieee802154_lowpan	ieee802154_lowpan;
+#endif
 #if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
 	struct netns_sctp	sctp;
 #endif
diff --git a/include/net/netns/ieee802154_6lowpan.h b/include/net/netns/ieee802154_6lowpan.h
new file mode 100644
index 0000000..88110b7
--- /dev/null
+++ b/include/net/netns/ieee802154_6lowpan.h
@@ -0,0 +1,13 @@
+/*
+ * ieee802154 6lowpan in net namespaces
+ */
+
+#include <net/inet_frag.h>
+
+#ifndef __NETNS_IEEE802154_6LOWPAN_H__
+#define __NETNS_IEEE802154_6LOWPAN_H__
+
+struct netns_ieee802154_lowpan {
+};
+
+#endif
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH net-next v4 8/8] 6lowpan: handling 6lowpan fragmentation via inet_frag api
  2014-02-26 16:05 [PATCH net-next v4 0/8] 6lowpan: reimplementation of fragmentation handling Alexander Aring
                   ` (4 preceding siblings ...)
  2014-02-26 16:05 ` [PATCH net-next v4 7/8] net: ns: add ieee802154_6lowpan namespace Alexander Aring
@ 2014-02-26 16:05 ` Alexander Aring
  5 siblings, 0 replies; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:05 UTC (permalink / raw)
  To: alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend,
	Alexander Aring

This patch drops the current way of 6lowpan fragmentation on receiving
side and replace it with a implementation which use the inet_frag api.
The old fragmentation handling has some race conditions and isn't
rfc4944 compatible. Also adding support to match fragments on
destination and source address which is missing in the current
implementation.

This patch add also a lookup function for uncompressed 6LoWPAN header
size. This is needed to estimate the real size of fragmented packet.

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
---
 include/net/netns/ieee802154_6lowpan.h |   9 +
 net/ieee802154/6lowpan_rtnl.c          | 256 +++------------
 net/ieee802154/Makefile                |   2 +-
 net/ieee802154/reassembly.c            | 565 +++++++++++++++++++++++++++++++++
 net/ieee802154/reassembly.h            |  66 ++++
 5 files changed, 690 insertions(+), 208 deletions(-)
 create mode 100644 net/ieee802154/reassembly.c
 create mode 100644 net/ieee802154/reassembly.h

diff --git a/include/net/netns/ieee802154_6lowpan.h b/include/net/netns/ieee802154_6lowpan.h
index 88110b7..079030c 100644
--- a/include/net/netns/ieee802154_6lowpan.h
+++ b/include/net/netns/ieee802154_6lowpan.h
@@ -7,7 +7,16 @@
 #ifndef __NETNS_IEEE802154_6LOWPAN_H__
 #define __NETNS_IEEE802154_6LOWPAN_H__
 
+struct netns_sysctl_lowpan {
+#ifdef CONFIG_SYSCTL
+	struct ctl_table_header *frags_hdr;
+#endif
+};
+
 struct netns_ieee802154_lowpan {
+	struct netns_sysctl_lowpan sysctl;
+	struct netns_frags	frags;
+	u16			max_dsize;
 };
 
 #endif
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
index f9c9548..c7bd8b5 100644
--- a/net/ieee802154/6lowpan_rtnl.c
+++ b/net/ieee802154/6lowpan_rtnl.c
@@ -54,6 +54,7 @@
 #include <net/ieee802154_netdev.h>
 #include <net/ipv6.h>
 
+#include "reassembly.h"
 #include "6lowpan.h"
 
 static LIST_HEAD(lowpan_devices);
@@ -70,18 +71,6 @@ struct lowpan_dev_record {
 	struct list_head list;
 };
 
-struct lowpan_fragment {
-	struct sk_buff		*skb;		/* skb to be assembled */
-	u16			length;		/* length to be assemled */
-	u32			bytes_rcv;	/* bytes received */
-	u16			tag;		/* current fragment tag */
-	struct timer_list	timer;		/* assembling timer */
-	struct list_head	list;		/* fragments list */
-};
-
-static LIST_HEAD(lowpan_fragments);
-static DEFINE_SPINLOCK(flist_lock);
-
 static inline struct
 lowpan_dev_info *lowpan_dev_info(const struct net_device *dev)
 {
@@ -179,69 +168,6 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb,
 	return stat;
 }
 
-static void lowpan_fragment_timer_expired(unsigned long entry_addr)
-{
-	struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
-
-	pr_debug("timer expired for frame with tag %d\n", entry->tag);
-
-	list_del(&entry->list);
-	dev_kfree_skb(entry->skb);
-	kfree(entry);
-}
-
-static struct lowpan_fragment *
-lowpan_alloc_new_frame(struct sk_buff *skb, u16 len, u16 tag)
-{
-	struct lowpan_fragment *frame;
-
-	frame = kzalloc(sizeof(struct lowpan_fragment),
-			GFP_ATOMIC);
-	if (!frame)
-		goto frame_err;
-
-	INIT_LIST_HEAD(&frame->list);
-
-	frame->length = len;
-	frame->tag = tag;
-
-	/* allocate buffer for frame assembling */
-	frame->skb = netdev_alloc_skb_ip_align(skb->dev, frame->length +
-					       sizeof(struct ipv6hdr));
-
-	if (!frame->skb)
-		goto skb_err;
-
-	frame->skb->priority = skb->priority;
-
-	/* reserve headroom for uncompressed ipv6 header */
-	skb_reserve(frame->skb, sizeof(struct ipv6hdr));
-	skb_put(frame->skb, frame->length);
-
-	/* copy the first control block to keep a
-	 * trace of the link-layer addresses in case
-	 * of a link-local compressed address
-	 */
-	memcpy(frame->skb->cb, skb->cb, sizeof(skb->cb));
-
-	init_timer(&frame->timer);
-	/* time out is the same as for ipv6 - 60 sec */
-	frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
-	frame->timer.data = (unsigned long)frame;
-	frame->timer.function = lowpan_fragment_timer_expired;
-
-	add_timer(&frame->timer);
-
-	list_add_tail(&frame->list, &lowpan_fragments);
-
-	return frame;
-
-skb_err:
-	kfree(frame);
-frame_err:
-	return NULL;
-}
-
 static int process_data(struct sk_buff *skb)
 {
 	u8 iphc0, iphc1;
@@ -255,94 +181,6 @@ static int process_data(struct sk_buff *skb)
 	if (lowpan_fetch_skb_u8(skb, &iphc0))
 		goto drop;
 
-	/* fragments assembling */
-	switch (iphc0 & LOWPAN_DISPATCH_MASK) {
-	case LOWPAN_DISPATCH_FRAG1:
-	case LOWPAN_DISPATCH_FRAGN:
-	{
-		struct lowpan_fragment *frame;
-		/* slen stores the rightmost 8 bits of the 11 bits length */
-		u8 slen, offset = 0;
-		u16 len, tag;
-		bool found = false;
-
-		if (lowpan_fetch_skb_u8(skb, &slen) || /* frame length */
-		    lowpan_fetch_skb_u16(skb, &tag))  /* fragment tag */
-			goto drop;
-
-		/* adds the 3 MSB to the 8 LSB to retrieve the 11 bits length */
-		len = ((iphc0 & 7) << 8) | slen;
-
-		if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1) {
-			pr_debug("%s received a FRAG1 packet (tag: %d, "
-				 "size of the entire IP packet: %d)",
-				 __func__, tag, len);
-		} else { /* FRAGN */
-			if (lowpan_fetch_skb_u8(skb, &offset))
-				goto unlock_and_drop;
-			pr_debug("%s received a FRAGN packet (tag: %d, "
-				 "size of the entire IP packet: %d, "
-				 "offset: %d)", __func__, tag, len, offset * 8);
-		}
-
-		/*
-		 * check if frame assembling with the same tag is
-		 * already in progress
-		 */
-		spin_lock_bh(&flist_lock);
-
-		list_for_each_entry(frame, &lowpan_fragments, list)
-			if (frame->tag == tag) {
-				found = true;
-				break;
-			}
-
-		/* alloc new frame structure */
-		if (!found) {
-			pr_debug("%s first fragment received for tag %d, "
-				 "begin packet reassembly", __func__, tag);
-			frame = lowpan_alloc_new_frame(skb, len, tag);
-			if (!frame)
-				goto unlock_and_drop;
-		}
-
-		/* if payload fits buffer, copy it */
-		if (likely((offset * 8 + skb->len) <= frame->length))
-			skb_copy_to_linear_data_offset(frame->skb, offset * 8,
-							skb->data, skb->len);
-		else
-			goto unlock_and_drop;
-
-		frame->bytes_rcv += skb->len;
-
-		/* frame assembling complete */
-		if ((frame->bytes_rcv == frame->length) &&
-		     frame->timer.expires > jiffies) {
-			/* if timer haven't expired - first of all delete it */
-			del_timer_sync(&frame->timer);
-			list_del(&frame->list);
-			spin_unlock_bh(&flist_lock);
-
-			pr_debug("%s successfully reassembled fragment "
-				 "(tag %d)", __func__, tag);
-
-			dev_kfree_skb(skb);
-			skb = frame->skb;
-			kfree(frame);
-
-			if (lowpan_fetch_skb_u8(skb, &iphc0))
-				goto drop;
-
-			break;
-		}
-		spin_unlock_bh(&flist_lock);
-
-		return kfree_skb(skb), 0;
-	}
-	default:
-		break;
-	}
-
 	if (lowpan_fetch_skb_u8(skb, &iphc1))
 		goto drop;
 
@@ -355,8 +193,6 @@ static int process_data(struct sk_buff *skb)
 				IEEE802154_ADDR_LEN, iphc0, iphc1,
 				lowpan_give_skb_to_devices);
 
-unlock_and_drop:
-	spin_unlock_bh(&flist_lock);
 drop:
 	kfree_skb(skb);
 	return -EINVAL;
@@ -603,44 +439,53 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
 	struct packet_type *pt, struct net_device *orig_dev)
 {
 	struct sk_buff *local_skb;
+	int ret;
 
 	if (!netif_running(dev))
-		goto drop;
+		goto drop_skb;
 
 	if (dev->type != ARPHRD_IEEE802154)
-		goto drop;
+		goto drop_skb;
+
+	local_skb = skb_clone(skb, GFP_ATOMIC);
+	if (!local_skb)
+		goto drop_skb;
+
+	kfree_skb(skb);
 
 	/* check that it's our buffer */
 	if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
-		/* Copy the packet so that the IPv6 header is
-		 * properly aligned.
-		 */
-		local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
-					    skb_tailroom(skb), GFP_ATOMIC);
-		if (!local_skb)
-			goto drop;
-
 		local_skb->protocol = htons(ETH_P_IPV6);
 		local_skb->pkt_type = PACKET_HOST;
 
 		/* Pull off the 1-byte of 6lowpan header. */
 		skb_pull(local_skb, 1);
 
-		lowpan_give_skb_to_devices(local_skb, NULL);
-
-		kfree_skb(local_skb);
-		kfree_skb(skb);
+		ret = lowpan_give_skb_to_devices(local_skb, NULL);
+		if (ret == NET_RX_DROP)
+			goto drop;
 	} else {
 		switch (skb->data[0] & 0xe0) {
 		case LOWPAN_DISPATCH_IPHC:	/* ipv6 datagram */
+			ret = process_data(local_skb);
+			if (ret == NET_RX_DROP)
+				goto drop;
+			break;
 		case LOWPAN_DISPATCH_FRAG1:	/* first fragment header */
+			ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAG1);
+			if (ret == 1) {
+				ret = process_data(local_skb);
+				if (ret == NET_RX_DROP)
+					goto drop;
+			}
+			break;
 		case LOWPAN_DISPATCH_FRAGN:	/* next fragments headers */
-			local_skb = skb_clone(skb, GFP_ATOMIC);
-			if (!local_skb)
-				goto drop;
-			process_data(local_skb);
-
-			kfree_skb(skb);
+			ret = lowpan_frag_rcv(local_skb, LOWPAN_DISPATCH_FRAGN);
+			if (ret == 1) {
+				ret = process_data(local_skb);
+				if (ret == NET_RX_DROP)
+					goto drop;
+			}
 			break;
 		default:
 			break;
@@ -648,9 +493,9 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
 	}
 
 	return NET_RX_SUCCESS;
-
-drop:
+drop_skb:
 	kfree_skb(skb);
+drop:
 	return NET_RX_DROP;
 }
 
@@ -778,43 +623,40 @@ static int __init lowpan_init_module(void)
 {
 	int err = 0;
 
-	err = lowpan_netlink_init();
+	err = lowpan_net_frag_init();
 	if (err < 0)
 		goto out;
 
+	err = lowpan_netlink_init();
+	if (err < 0)
+		goto out_frag;
+
 	dev_add_pack(&lowpan_packet_type);
 
 	err = register_netdevice_notifier(&lowpan_dev_notifier);
-	if (err < 0) {
-		dev_remove_pack(&lowpan_packet_type);
-		lowpan_netlink_fini();
-	}
+	if (err < 0)
+		goto out_pack;
+
+	return 0;
+
+out_pack:
+	dev_remove_pack(&lowpan_packet_type);
+	lowpan_netlink_fini();
+out_frag:
+	lowpan_net_frag_exit();
 out:
 	return err;
 }
 
 static void __exit lowpan_cleanup_module(void)
 {
-	struct lowpan_fragment *frame, *tframe;
-
 	lowpan_netlink_fini();
 
 	dev_remove_pack(&lowpan_packet_type);
 
-	unregister_netdevice_notifier(&lowpan_dev_notifier);
+	lowpan_net_frag_exit();
 
-	/* Now 6lowpan packet_type is removed, so no new fragments are
-	 * expected on RX, therefore that's the time to clean incomplete
-	 * fragments.
-	 */
-	spin_lock_bh(&flist_lock);
-	list_for_each_entry_safe(frame, tframe, &lowpan_fragments, list) {
-		del_timer_sync(&frame->timer);
-		list_del(&frame->list);
-		dev_kfree_skb(frame->skb);
-		kfree(frame);
-	}
-	spin_unlock_bh(&flist_lock);
+	unregister_netdevice_notifier(&lowpan_dev_notifier);
 }
 
 module_init(lowpan_init_module);
diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile
index 3d08adf..b113fc4 100644
--- a/net/ieee802154/Makefile
+++ b/net/ieee802154/Makefile
@@ -2,6 +2,6 @@ obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
 obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
 obj-$(CONFIG_6LOWPAN_IPHC) += 6lowpan_iphc.o
 
-6lowpan-y := 6lowpan_rtnl.o
+6lowpan-y := 6lowpan_rtnl.o reassembly.o
 ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
 af_802154-y := af_ieee802154.o raw.o dgram.o
diff --git a/net/ieee802154/reassembly.c b/net/ieee802154/reassembly.c
new file mode 100644
index 0000000..e7825b6
--- /dev/null
+++ b/net/ieee802154/reassembly.c
@@ -0,0 +1,565 @@
+/*	6LoWPAN fragment reassembly
+ *
+ *
+ *	Authors:
+ *	Alexander Aring		<aar@pengutronix.de>
+ *
+ *	Based on: net/ipv6/reassembly.c
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "6LoWPAN: " fmt
+
+#include <linux/net.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/random.h>
+#include <linux/jhash.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include <net/ieee802154_netdev.h>
+#include <net/ipv6.h>
+#include <net/inet_frag.h>
+
+#include "6lowpan.h"
+#include "reassembly.h"
+
+static struct inet_frags lowpan_frags;
+
+static int lowpan_frag_reasm(struct lowpan_frag_queue *fq,
+			     struct sk_buff *prev, struct net_device *dev);
+
+static unsigned int lowpan_hash_frag(__be16 tag, __be16 d_size,
+				     const struct ieee802154_addr *saddr,
+				     const struct ieee802154_addr *daddr)
+{
+	u32 c;
+
+	net_get_random_once(&lowpan_frags.rnd, sizeof(lowpan_frags.rnd));
+	c = jhash_3words(ieee802154_addr_hash(saddr),
+			 ieee802154_addr_hash(daddr),
+			 (__force u32)(tag + (d_size << 16)),
+			 lowpan_frags.rnd);
+
+	return c & (INETFRAGS_HASHSZ - 1);
+}
+
+static unsigned int lowpan_hashfn(struct inet_frag_queue *q)
+{
+	struct lowpan_frag_queue *fq;
+
+	fq = container_of(q, struct lowpan_frag_queue, q);
+	return lowpan_hash_frag(fq->tag, fq->d_size, &fq->saddr, &fq->daddr);
+}
+
+bool lowpan_frag_match(struct inet_frag_queue *q, void *a)
+{
+	struct lowpan_frag_queue *fq;
+	struct lowpan_create_arg *arg = a;
+
+	fq = container_of(q, struct lowpan_frag_queue, q);
+	return	fq->tag == arg->tag && fq->d_size == arg->d_size &&
+		ieee802154_addr_addr_equal(&fq->saddr, arg->src) &&
+		ieee802154_addr_addr_equal(&fq->daddr, arg->dst);
+}
+EXPORT_SYMBOL(lowpan_frag_match);
+
+void lowpan_frag_init(struct inet_frag_queue *q, void *a)
+{
+	struct lowpan_frag_queue *fq;
+	struct lowpan_create_arg *arg = a;
+
+	fq = container_of(q, struct lowpan_frag_queue, q);
+
+	fq->tag = arg->tag;
+	fq->d_size = arg->d_size;
+	fq->saddr = *arg->src;
+	fq->daddr = *arg->dst;
+}
+EXPORT_SYMBOL(lowpan_frag_init);
+
+void lowpan_expire_frag_queue(struct frag_queue *fq, struct inet_frags *frags)
+{
+	spin_lock(&fq->q.lock);
+
+	if (fq->q.last_in & INET_FRAG_COMPLETE)
+		goto out;
+
+	inet_frag_kill(&fq->q, frags);
+out:
+	spin_unlock(&fq->q.lock);
+	inet_frag_put(&fq->q, frags);
+}
+EXPORT_SYMBOL(lowpan_expire_frag_queue);
+
+static void lowpan_frag_expire(unsigned long data)
+{
+	struct frag_queue *fq;
+	struct net *net;
+
+	fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q);
+	net = container_of(fq->q.net, struct net, ieee802154_lowpan.frags);
+
+	lowpan_expire_frag_queue(fq, &lowpan_frags);
+}
+
+static inline struct lowpan_frag_queue *
+fq_find(struct net *net, const struct ieee802154_frag_info *frag_info,
+	const struct ieee802154_addr *src, const struct ieee802154_addr *dst)
+{
+	struct inet_frag_queue *q;
+	struct lowpan_create_arg arg;
+	unsigned int hash;
+
+	arg.tag = frag_info->d_tag;
+	arg.d_size = frag_info->d_size;
+	arg.src = src;
+	arg.dst = dst;
+
+	read_lock(&lowpan_frags.lock);
+	hash = lowpan_hash_frag(frag_info->d_tag, frag_info->d_size, src, dst);
+
+	q = inet_frag_find(&net->ieee802154_lowpan.frags,
+			   &lowpan_frags, &arg, hash);
+	if (IS_ERR_OR_NULL(q)) {
+		inet_frag_maybe_warn_overflow(q, pr_fmt());
+		return NULL;
+	}
+	return container_of(q, struct lowpan_frag_queue, q);
+}
+
+static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
+			     struct sk_buff *skb, const u8 frag_type,
+			     const struct ieee802154_frag_info *frag_info)
+{
+	struct sk_buff *prev, *next;
+	struct net_device *dev;
+	int end, offset;
+
+	if (fq->q.last_in & INET_FRAG_COMPLETE)
+		goto err;
+
+	offset = mac_cb(skb)->frag_info.d_offset << 3;
+	end = mac_cb(skb)->frag_info.d_size;
+
+	/* Is this the final fragment? */
+	if (offset + skb->len == end) {
+		/* If we already have some bits beyond end
+		 * or have different end, the segment is corrupted.
+		 */
+		if (end < fq->q.len ||
+		    ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len))
+			goto err;
+		fq->q.last_in |= INET_FRAG_LAST_IN;
+		fq->q.len = end;
+	} else {
+		if (end > fq->q.len) {
+			/* Some bits beyond end -> corruption. */
+			if (fq->q.last_in & INET_FRAG_LAST_IN)
+				goto err;
+			fq->q.len = end;
+		}
+	}
+
+	/* Find out which fragments are in front and at the back of us
+	 * in the chain of fragments so far.  We must know where to put
+	 * this fragment, right?
+	 */
+	prev = fq->q.fragments_tail;
+	if (!prev || mac_cb(prev)->frag_info.d_offset <
+		     mac_cb(skb)->frag_info.d_offset) {
+		next = NULL;
+		goto found;
+	}
+	prev = NULL;
+	for (next = fq->q.fragments; next != NULL; next = next->next) {
+		if (mac_cb(next)->frag_info.d_offset >=
+		    mac_cb(skb)->frag_info.d_offset)
+			break;	/* bingo! */
+		prev = next;
+	}
+
+found:
+	/* Insert this fragment in the chain of fragments. */
+	skb->next = next;
+	if (!next)
+		fq->q.fragments_tail = skb;
+	if (prev)
+		prev->next = skb;
+	else
+		fq->q.fragments = skb;
+
+	dev = skb->dev;
+	if (dev)
+		skb->dev = NULL;
+
+	fq->q.stamp = skb->tstamp;
+	if (frag_type == LOWPAN_DISPATCH_FRAG1) {
+		/* Calculate uncomp. 6lowpan header to estimate full size */
+		fq->q.meat += lowpan_uncompress_size(skb, NULL);
+		fq->q.last_in |= INET_FRAG_FIRST_IN;
+	} else {
+		fq->q.meat += skb->len;
+	}
+	add_frag_mem_limit(&fq->q, skb->truesize);
+
+	if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
+	    fq->q.meat == fq->q.len) {
+		int res;
+		unsigned long orefdst = skb->_skb_refdst;
+
+		skb->_skb_refdst = 0UL;
+		res = lowpan_frag_reasm(fq, prev, dev);
+		skb->_skb_refdst = orefdst;
+		return res;
+	}
+
+	inet_frag_lru_move(&fq->q);
+	return -1;
+err:
+	kfree_skb(skb);
+	return -1;
+}
+
+/*	Check if this packet is complete.
+ *	Returns NULL on failure by any reason, and pointer
+ *	to current nexthdr field in reassembled frame.
+ *
+ *	It is called with locked fq, and caller must check that
+ *	queue is eligible for reassembly i.e. it is not COMPLETE,
+ *	the last and the first frames arrived and all the bits are here.
+ */
+static int lowpan_frag_reasm(struct lowpan_frag_queue *fq, struct sk_buff *prev,
+			     struct net_device *dev)
+{
+	struct sk_buff *fp, *head = fq->q.fragments;
+	int sum_truesize;
+
+	inet_frag_kill(&fq->q, &lowpan_frags);
+
+	/* Make the one we just received the head. */
+	if (prev) {
+		head = prev->next;
+		fp = skb_clone(head, GFP_ATOMIC);
+
+		if (!fp)
+			goto out_oom;
+
+		fp->next = head->next;
+		if (!fp->next)
+			fq->q.fragments_tail = fp;
+		prev->next = fp;
+
+		skb_morph(head, fq->q.fragments);
+		head->next = fq->q.fragments->next;
+
+		consume_skb(fq->q.fragments);
+		fq->q.fragments = head;
+	}
+
+	/* Head of list must not be cloned. */
+	if (skb_unclone(head, GFP_ATOMIC))
+		goto out_oom;
+
+	/* If the first fragment is fragmented itself, we split
+	 * it to two chunks: the first with data and paged part
+	 * and the second, holding only fragments.
+	 */
+	if (skb_has_frag_list(head)) {
+		struct sk_buff *clone;
+		int i, plen = 0;
+
+		clone = alloc_skb(0, GFP_ATOMIC);
+		if (!clone)
+			goto out_oom;
+		clone->next = head->next;
+		head->next = clone;
+		skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
+		skb_frag_list_init(head);
+		for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
+			plen += skb_frag_size(&skb_shinfo(head)->frags[i]);
+		clone->len = head->data_len - plen;
+		clone->data_len = clone->len;
+		head->data_len -= clone->len;
+		head->len -= clone->len;
+		add_frag_mem_limit(&fq->q, clone->truesize);
+	}
+
+	WARN_ON(head == NULL);
+
+	sum_truesize = head->truesize;
+	for (fp = head->next; fp;) {
+		bool headstolen;
+		int delta;
+		struct sk_buff *next = fp->next;
+
+		sum_truesize += fp->truesize;
+		if (skb_try_coalesce(head, fp, &headstolen, &delta)) {
+			kfree_skb_partial(fp, headstolen);
+		} else {
+			if (!skb_shinfo(head)->frag_list)
+				skb_shinfo(head)->frag_list = fp;
+			head->data_len += fp->len;
+			head->len += fp->len;
+			head->truesize += fp->truesize;
+		}
+		fp = next;
+	}
+	sub_frag_mem_limit(&fq->q, sum_truesize);
+
+	head->next = NULL;
+	head->dev = dev;
+	head->tstamp = fq->q.stamp;
+
+	fq->q.fragments = NULL;
+	fq->q.fragments_tail = NULL;
+
+	return 1;
+out_oom:
+	net_dbg_ratelimited("lowpan_frag_reasm: no memory for reassembly\n");
+	return -1;
+}
+
+static int lowpan_get_frag_info(struct sk_buff *skb, const u8 frag_type,
+				struct ieee802154_frag_info *frag_info)
+{
+	bool fail;
+	u8 pattern = 0, low = 0;
+
+	fail = lowpan_fetch_skb(skb, &pattern, 1);
+	fail |= lowpan_fetch_skb(skb, &low, 1);
+	frag_info->d_size = (pattern & 7) << 8 | low;
+	fail |= lowpan_fetch_skb(skb, &frag_info->d_tag, 2);
+
+	if (frag_type == LOWPAN_DISPATCH_FRAGN) {
+		fail |= lowpan_fetch_skb(skb, &frag_info->d_offset, 1);
+	} else {
+		skb_reset_network_header(skb);
+		frag_info->d_offset = 0;
+	}
+
+	if (unlikely(fail))
+		return -EIO;
+
+	return 0;
+}
+
+int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type)
+{
+	struct lowpan_frag_queue *fq;
+	struct net *net = dev_net(skb->dev);
+	struct ieee802154_frag_info *frag_info = &mac_cb(skb)->frag_info;
+	int err;
+
+	err = lowpan_get_frag_info(skb, frag_type, frag_info);
+	if (err < 0)
+		goto err;
+
+	if (frag_info->d_size > net->ieee802154_lowpan.max_dsize)
+		goto err;
+
+	inet_frag_evictor(&net->ieee802154_lowpan.frags, &lowpan_frags, false);
+
+	fq = fq_find(net, frag_info, &mac_cb(skb)->sa, &mac_cb(skb)->da);
+	if (fq != NULL) {
+		int ret;
+		spin_lock(&fq->q.lock);
+		ret = lowpan_frag_queue(fq, skb, frag_type, frag_info);
+		spin_unlock(&fq->q.lock);
+
+		inet_frag_put(&fq->q, &lowpan_frags);
+		return ret;
+	}
+
+err:
+	kfree_skb(skb);
+	return -1;
+}
+EXPORT_SYMBOL(lowpan_frag_rcv);
+
+#ifdef CONFIG_SYSCTL
+static struct ctl_table lowpan_frags_ns_ctl_table[] = {
+	{
+		.procname	= "6lowpanfrag_high_thresh",
+		.data		= &init_net.ieee802154_lowpan.frags.high_thresh,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+	{
+		.procname	= "6lowpanfrag_low_thresh",
+		.data		= &init_net.ieee802154_lowpan.frags.low_thresh,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+	{
+		.procname	= "6lowpanfrag_time",
+		.data		= &init_net.ieee802154_lowpan.frags.timeout,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_jiffies,
+	},
+	{
+		.procname	= "6lowpanfrag_max_datagram_size",
+		.data		= &init_net.ieee802154_lowpan.max_dsize,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec
+	},
+	{ }
+};
+
+static struct ctl_table lowpan_frags_ctl_table[] = {
+	{
+		.procname	= "6lowpanfrag_secret_interval",
+		.data		= &lowpan_frags.secret_interval,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec_jiffies,
+	},
+	{ }
+};
+
+static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
+{
+	struct ctl_table *table;
+	struct ctl_table_header *hdr;
+
+	table = lowpan_frags_ns_ctl_table;
+	if (!net_eq(net, &init_net)) {
+		table = kmemdup(table, sizeof(lowpan_frags_ns_ctl_table),
+				GFP_KERNEL);
+		if (table == NULL)
+			goto err_alloc;
+
+		table[0].data = &net->ieee802154_lowpan.frags.high_thresh;
+		table[1].data = &net->ieee802154_lowpan.frags.low_thresh;
+		table[2].data = &net->ieee802154_lowpan.frags.timeout;
+		table[2].data = &net->ieee802154_lowpan.max_dsize;
+
+		/* Don't export sysctls to unprivileged users */
+		if (net->user_ns != &init_user_ns)
+			table[0].procname = NULL;
+	}
+
+	hdr = register_net_sysctl(net, "net/ieee802154/6lowpan", table);
+	if (hdr == NULL)
+		goto err_reg;
+
+	net->ieee802154_lowpan.sysctl.frags_hdr = hdr;
+	return 0;
+
+err_reg:
+	if (!net_eq(net, &init_net))
+		kfree(table);
+err_alloc:
+	return -ENOMEM;
+}
+
+static void __net_exit lowpan_frags_ns_sysctl_unregister(struct net *net)
+{
+	struct ctl_table *table;
+
+	table = net->ieee802154_lowpan.sysctl.frags_hdr->ctl_table_arg;
+	unregister_net_sysctl_table(net->ieee802154_lowpan.sysctl.frags_hdr);
+	if (!net_eq(net, &init_net))
+		kfree(table);
+}
+
+static struct ctl_table_header *lowpan_ctl_header;
+
+static int lowpan_frags_sysctl_register(void)
+{
+	lowpan_ctl_header = register_net_sysctl(&init_net,
+						"net/ieee802154/6lowpan",
+						lowpan_frags_ctl_table);
+	return lowpan_ctl_header == NULL ? -ENOMEM : 0;
+}
+
+static void lowpan_frags_sysctl_unregister(void)
+{
+	unregister_net_sysctl_table(lowpan_ctl_header);
+}
+#else
+static inline int lowpan_frags_ns_sysctl_register(struct net *net)
+{
+	return 0;
+}
+
+static inline void lowpan_frags_ns_sysctl_unregister(struct net *net)
+{
+}
+
+static inline int lowpan_frags_sysctl_register(void)
+{
+	return 0;
+}
+
+static inline void lowpan_frags_sysctl_unregister(void)
+{
+}
+#endif
+
+static int __net_init lowpan_frags_init_net(struct net *net)
+{
+	net->ieee802154_lowpan.frags.high_thresh = IPV6_FRAG_HIGH_THRESH;
+	net->ieee802154_lowpan.frags.low_thresh = IPV6_FRAG_LOW_THRESH;
+	net->ieee802154_lowpan.frags.timeout = IPV6_FRAG_TIMEOUT;
+	net->ieee802154_lowpan.max_dsize = 0xFFFF;
+
+	inet_frags_init_net(&net->ieee802154_lowpan.frags);
+
+	return lowpan_frags_ns_sysctl_register(net);
+}
+
+static void __net_exit lowpan_frags_exit_net(struct net *net)
+{
+	lowpan_frags_ns_sysctl_unregister(net);
+	inet_frags_exit_net(&net->ieee802154_lowpan.frags, &lowpan_frags);
+}
+
+static struct pernet_operations lowpan_frags_ops = {
+	.init = lowpan_frags_init_net,
+	.exit = lowpan_frags_exit_net,
+};
+
+int __init lowpan_net_frag_init(void)
+{
+	int ret;
+
+	ret = lowpan_frags_sysctl_register();
+	if (ret)
+		goto out;
+
+	ret = register_pernet_subsys(&lowpan_frags_ops);
+	if (ret)
+		goto err_pernet;
+
+	lowpan_frags.hashfn = lowpan_hashfn;
+	lowpan_frags.constructor = lowpan_frag_init;
+	lowpan_frags.destructor = NULL;
+	lowpan_frags.skb_free = NULL;
+	lowpan_frags.qsize = sizeof(struct frag_queue);
+	lowpan_frags.match = lowpan_frag_match;
+	lowpan_frags.frag_expire = lowpan_frag_expire;
+	lowpan_frags.secret_interval = 10 * 60 * HZ;
+	inet_frags_init(&lowpan_frags);
+err_pernet:
+	lowpan_frags_sysctl_unregister();
+out:
+	return ret;
+}
+
+void lowpan_net_frag_exit(void)
+{
+	inet_frags_fini(&lowpan_frags);
+	lowpan_frags_sysctl_unregister();
+	unregister_pernet_subsys(&lowpan_frags_ops);
+}
diff --git a/net/ieee802154/reassembly.h b/net/ieee802154/reassembly.h
new file mode 100644
index 0000000..055518b
--- /dev/null
+++ b/net/ieee802154/reassembly.h
@@ -0,0 +1,66 @@
+#ifndef __IEEE802154_6LOWPAN_REASSEMBLY_H__
+#define __IEEE802154_6LOWPAN_REASSEMBLY_H__
+
+#include <net/inet_frag.h>
+
+struct lowpan_create_arg {
+	__be16 tag;
+	u16 d_size;
+	const struct ieee802154_addr *src;
+	const struct ieee802154_addr *dst;
+};
+
+/* Equivalent of ipv4 struct ip
+ */
+struct lowpan_frag_queue {
+	struct inet_frag_queue	q;
+
+	__be16			tag;
+	u16			d_size;
+	struct ieee802154_addr	saddr;
+	struct ieee802154_addr	daddr;
+};
+
+static inline u32 ieee802154_addr_hash(const struct ieee802154_addr *a)
+{
+	switch (a->addr_type) {
+	case IEEE802154_ADDR_LONG:
+		return (__force u32)((((u32 *)a->hwaddr))[0] ^
+				      ((u32 *)(a->hwaddr))[1]);
+	case IEEE802154_ADDR_SHORT:
+		return (__force u32)(a->short_addr);
+	default:
+		return 0;
+	}
+}
+
+static inline bool ieee802154_addr_addr_equal(const struct ieee802154_addr *a1,
+				   const struct ieee802154_addr *a2)
+{
+	if (a1->pan_id != a2->pan_id)
+		return false;
+
+	if (a1->addr_type != a2->addr_type)
+		return false;
+
+	switch (a1->addr_type) {
+	case IEEE802154_ADDR_LONG:
+		if (memcmp(a1->hwaddr, a2->hwaddr, IEEE802154_ADDR_LEN))
+			return false;
+		break;
+	case IEEE802154_ADDR_SHORT:
+		if (a1->short_addr != a2->short_addr)
+			return false;
+		break;
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+int lowpan_frag_rcv(struct sk_buff *skb, const u8 frag_type);
+void lowpan_net_frag_exit(void);
+int lowpan_net_frag_init(void);
+
+#endif /* __IEEE802154_6LOWPAN_REASSEMBLY_H__ */
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* RE: [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function
  2014-02-26 16:05 ` [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function Alexander Aring
@ 2014-02-26 16:10   ` David Laight
  2014-02-26 16:20     ` Alexander Aring
                       ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: David Laight @ 2014-02-26 16:10 UTC (permalink / raw)
  To: 'Alexander Aring', alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend

From: Alexander Aring
> Signed-off-by: Alexander Aring <alex.aring@gmail.com>
> ---
>  net/ieee802154/6lowpan.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 116 insertions(+)
> 
> diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
> index 2b835db..b6ae0bc 100644
> --- a/net/ieee802154/6lowpan.h
> +++ b/net/ieee802154/6lowpan.h
> @@ -306,6 +306,122 @@ static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
>  	*hc_ptr += len;
>  }
> 
> +static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
> +{
> +	switch (addr_mode) {
> +	case LOWPAN_IPHC_ADDR_00:
> +		return 16;
> +	case LOWPAN_IPHC_ADDR_01:
> +		return 8;
> +	case LOWPAN_IPHC_ADDR_02:
> +		return 2;
> +	default:
> +		return 0;
> +	}
> +}

The compiler will generate much better code if you index an array instead
of using a switch statement.

	David

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function
  2014-02-26 16:10   ` David Laight
@ 2014-02-26 16:20     ` Alexander Aring
  2014-02-26 17:05       ` David Laight
  2014-02-26 18:24     ` Joe Perches
  2014-02-26 18:56     ` David Miller
  2 siblings, 1 reply; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 16:20 UTC (permalink / raw)
  To: David Laight
  Cc: alex.bluesman.smirnov, dbaryshkov, davem, linux-zigbee-devel,
	netdev, martin.townsend

Hi David,

thanks for your reply.

On Wed, Feb 26, 2014 at 04:10:05PM +0000, David Laight wrote:
> From: Alexander Aring
> > Signed-off-by: Alexander Aring <alex.aring@gmail.com>
> > ---
> >  net/ieee802154/6lowpan.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 116 insertions(+)
> > 
> > diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
> > index 2b835db..b6ae0bc 100644
> > --- a/net/ieee802154/6lowpan.h
> > +++ b/net/ieee802154/6lowpan.h
> > @@ -306,6 +306,122 @@ static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
> >  	*hc_ptr += len;
> >  }
> > 
> > +static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
> > +{
> > +	switch (addr_mode) {
> > +	case LOWPAN_IPHC_ADDR_00:
> > +		return 16;
> > +	case LOWPAN_IPHC_ADDR_01:
> > +		return 8;
> > +	case LOWPAN_IPHC_ADDR_02:
> > +		return 2;
> > +	default:
> > +		return 0;
> > +	}
> > +}
> 
> The compiler will generate much better code if you index an array instead
> of using a switch statement.
> 
> 

You mean something like:

static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
{
        const u8 res[] = { 16, 8, 2, 0 };
        return res[addr_mode];
}

or should I drop the array from the stack and declare it static?

?

- Alex

^ permalink raw reply	[flat|nested] 18+ messages in thread

* RE: [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function
  2014-02-26 16:20     ` Alexander Aring
@ 2014-02-26 17:05       ` David Laight
  0 siblings, 0 replies; 18+ messages in thread
From: David Laight @ 2014-02-26 17:05 UTC (permalink / raw)
  To: 'Alexander Aring'
  Cc: alex.bluesman.smirnov, dbaryshkov, davem, linux-zigbee-devel,
	netdev, martin.townsend

From: Alexander Aring 
> On Wed, Feb 26, 2014 at 04:10:05PM +0000, David Laight wrote:
> > From: Alexander Aring
...
> > > +static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
> > > +{
> > > +	switch (addr_mode) {
> > > +	case LOWPAN_IPHC_ADDR_00:
> > > +		return 16;
> > > +	case LOWPAN_IPHC_ADDR_01:
> > > +		return 8;
> > > +	case LOWPAN_IPHC_ADDR_02:
> > > +		return 2;
> > > +	default:
> > > +		return 0;
> > > +	}
> > > +}
> >
> > The compiler will generate much better code if you index an array instead
> > of using a switch statement.
> >
> >
> 
> You mean something like:
> 
> static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
> {
>         const u8 res[] = { 16, 8, 2, 0 };
>         return res[addr_mode];
> }
> 
> or should I drop the array from the stack and declare it static?

You definitely want the array to be static (as well as const).
You could also use named initialisers.
If I've got the syntax right that would be:

		static const u8 sizes[] = {
			[LOWPAN_IPHC_ADDR_00] = 16,
			[LOWPAN_IPHC_ADDR_01] = 8,
			[LOWPAN_IPHC_ADDR_02] = 2,
		};
		return sizes[addr_mode];

Whether you need a bound check (or the 4th array index) depends on where
the input value comes from.

	David


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH net-next v4 6/8] 6lowpan: fix some checkpatch issues
       [not found]     ` <1393430712-11298-7-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
@ 2014-02-26 17:24       ` Joe Perches
  2014-02-26 18:59         ` David Miller
  0 siblings, 1 reply; 18+ messages in thread
From: Joe Perches @ 2014-02-26 17:24 UTC (permalink / raw)
  To: Alexander Aring, David Miller
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

On Wed, 2014-02-26 at 17:05 +0100, Alexander Aring wrote:
> Detected with:
> 
> ./scripts/checkpatch.pl --strict -f net/ieee802154/6lowpan_rtnl.c

Hello Alexander.

Can I suggest to you (and to David) that the
multiline comment style:

/*
 * comment
 */

is fine and doesn't need correcting here at the
initial bits of a file before any actual code has
been written?

Assuming David agrees, I'll see about updating
checkpatch to avoid this warning at the beginning
of files.

> diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
[]
> @@ -1,10 +1,8 @@
> -/*
> - * Copyright 2011, Siemens AG
> +/* Copyright 2011, Siemens AG
>   * written by Alexander Smirnov <alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
>   */



------------------------------------------------------------------------------
Flow-based real-time traffic analytics software. Cisco certified tool.
Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer
Customize your own dashboards, set traffic alerts and generate reports.
Network behavioral analysis & security monitoring. All-in-one tool.
http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function
  2014-02-26 16:10   ` David Laight
  2014-02-26 16:20     ` Alexander Aring
@ 2014-02-26 18:24     ` Joe Perches
  2014-02-26 18:32       ` Alexander Aring
  2014-02-26 18:56     ` David Miller
  2 siblings, 1 reply; 18+ messages in thread
From: Joe Perches @ 2014-02-26 18:24 UTC (permalink / raw)
  To: David Laight
  Cc: 'Alexander Aring',
	alex.bluesman.smirnov, dbaryshkov, davem, linux-zigbee-devel,
	netdev, martin.townsend

On Wed, 2014-02-26 at 16:10 +0000, David Laight wrote:
> From: Alexander Aring
[]
> > diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
[]
> > +static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
> > +{
> > +	switch (addr_mode) {
> > +	case LOWPAN_IPHC_ADDR_00:
> > +		return 16;
> > +	case LOWPAN_IPHC_ADDR_01:
> > +		return 8;
> > +	case LOWPAN_IPHC_ADDR_02:
> > +		return 2;
> > +	default:
> > +		return 0;
> > +	}
> > +}
> 
> The compiler will generate much better code if you index an array instead
> of using a switch statement.

Are you sure of that?

Perhaps the compiler would inline the assignment
anyway if addr_mode is __builtin_constant_p

gcc 4.8 here does the same thing with:

static inline unsigned char f1(unsigned char a)
{
	switch (a) {
	case 0: return 16;
	case 1: return 8;
	case 2: return 2;
	default: return 0;
	}
}

static inline unsigned char f2(unsigned char a)
{
	static const unsigned char rtns[] = { 16, 8, 2, 0 };

	return rtns[a & 3];
}

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function
  2014-02-26 18:24     ` Joe Perches
@ 2014-02-26 18:32       ` Alexander Aring
  2014-02-26 18:35         ` Joe Perches
  0 siblings, 1 reply; 18+ messages in thread
From: Alexander Aring @ 2014-02-26 18:32 UTC (permalink / raw)
  To: Joe Perches
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	David Laight, davem-fT/PcQaiUtIeIZ0/mPfg9Q

On Wed, Feb 26, 2014 at 10:24:45AM -0800, Joe Perches wrote:
> On Wed, 2014-02-26 at 16:10 +0000, David Laight wrote:
> > From: Alexander Aring
> []
> > > diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
> []
> > > +static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
> > > +{
> > > +	switch (addr_mode) {
> > > +	case LOWPAN_IPHC_ADDR_00:
> > > +		return 16;
> > > +	case LOWPAN_IPHC_ADDR_01:
> > > +		return 8;
> > > +	case LOWPAN_IPHC_ADDR_02:
> > > +		return 2;
> > > +	default:
> > > +		return 0;
> > > +	}
> > > +}
> > 
> > The compiler will generate much better code if you index an array instead
> > of using a switch statement.
> 
> Are you sure of that?
> 
> Perhaps the compiler would inline the assignment
> anyway if addr_mode is __builtin_constant_p
> 
> gcc 4.8 here does the same thing with:
> 
> static inline unsigned char f1(unsigned char a)
> {
> 	switch (a) {
> 	case 0: return 16;
> 	case 1: return 8;
> 	case 2: return 2;
> 	default: return 0;
> 	}
> }
> 
> static inline unsigned char f2(unsigned char a)
> {
> 	static const unsigned char rtns[] = { 16, 8, 2, 0 };
> 
> 	return rtns[a & 3];
> }

to make a mask with & 3 is already done, so we don't need that.
I am not sure what I should do now, change or not change? :-)

- Alex

------------------------------------------------------------------------------
Flow-based real-time traffic analytics software. Cisco certified tool.
Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer
Customize your own dashboards, set traffic alerts and generate reports.
Network behavioral analysis & security monitoring. All-in-one tool.
http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function
  2014-02-26 18:32       ` Alexander Aring
@ 2014-02-26 18:35         ` Joe Perches
  0 siblings, 0 replies; 18+ messages in thread
From: Joe Perches @ 2014-02-26 18:35 UTC (permalink / raw)
  To: Alexander Aring
  Cc: David Laight, alex.bluesman.smirnov, dbaryshkov, davem,
	linux-zigbee-devel, netdev, martin.townsend

On Wed, 2014-02-26 at 19:32 +0100, Alexander Aring wrote:
> On Wed, Feb 26, 2014 at 10:24:45AM -0800, Joe Perches wrote:
[]
> > Perhaps the compiler would inline the assignment
> > anyway if addr_mode is __builtin_constant_p
[]
> I am not sure what I should do now, change or not change? :-)

Whatever you choose will be fine with me.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function
  2014-02-26 16:10   ` David Laight
  2014-02-26 16:20     ` Alexander Aring
  2014-02-26 18:24     ` Joe Perches
@ 2014-02-26 18:56     ` David Miller
  2 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2014-02-26 18:56 UTC (permalink / raw)
  To: David.Laight
  Cc: alex.aring, alex.bluesman.smirnov, dbaryshkov,
	linux-zigbee-devel, netdev, martin.townsend

From: David Laight <David.Laight@ACULAB.COM>
Date: Wed, 26 Feb 2014 16:10:05 +0000

> From: Alexander Aring
>> Signed-off-by: Alexander Aring <alex.aring@gmail.com>
>> ---
>>  net/ieee802154/6lowpan.h | 116 +++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 116 insertions(+)
>> 
>> diff --git a/net/ieee802154/6lowpan.h b/net/ieee802154/6lowpan.h
>> index 2b835db..b6ae0bc 100644
>> --- a/net/ieee802154/6lowpan.h
>> +++ b/net/ieee802154/6lowpan.h
>> @@ -306,6 +306,122 @@ static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
>>  	*hc_ptr += len;
>>  }
>> 
>> +static inline u8 lowpan_addr_mode_size(const u8 addr_mode)
>> +{
>> +	switch (addr_mode) {
>> +	case LOWPAN_IPHC_ADDR_00:
>> +		return 16;
>> +	case LOWPAN_IPHC_ADDR_01:
>> +		return 8;
>> +	case LOWPAN_IPHC_ADDR_02:
>> +		return 2;
>> +	default:
>> +		return 0;
>> +	}
>> +}
> 
> The compiler will generate much better code if you index an array instead
> of using a switch statement.

And please mark the array const :-)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH net-next v4 6/8] 6lowpan: fix some checkpatch issues
  2014-02-26 17:24       ` Joe Perches
@ 2014-02-26 18:59         ` David Miller
  0 siblings, 0 replies; 18+ messages in thread
From: David Miller @ 2014-02-26 18:59 UTC (permalink / raw)
  To: joe-6d6DIl74uiNBDgjK7y7TUQ
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f

From: Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>
Date: Wed, 26 Feb 2014 09:24:56 -0800

> On Wed, 2014-02-26 at 17:05 +0100, Alexander Aring wrote:
>> Detected with:
>> 
>> ./scripts/checkpatch.pl --strict -f net/ieee802154/6lowpan_rtnl.c
> 
> Hello Alexander.
> 
> Can I suggest to you (and to David) that the
> multiline comment style:
> 
> /*
>  * comment
>  */
> 
> is fine and doesn't need correcting here at the
> initial bits of a file before any actual code has
> been written?
> 
> Assuming David agrees, I'll see about updating
> checkpatch to avoid this warning at the beginning
> of files.

I'm largely ambivalent but prefer avoiding that wasted "/*" line.

------------------------------------------------------------------------------
Flow-based real-time traffic analytics software. Cisco certified tool.
Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer
Customize your own dashboards, set traffic alerts and generate reports.
Network behavioral analysis & security monitoring. All-in-one tool.
http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2014-02-26 18:59 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-26 16:05 [PATCH net-next v4 0/8] 6lowpan: reimplementation of fragmentation handling Alexander Aring
2014-02-26 16:05 ` [PATCH net-next v4 2/8] 6lowpan: add uncompress header size function Alexander Aring
2014-02-26 16:10   ` David Laight
2014-02-26 16:20     ` Alexander Aring
2014-02-26 17:05       ` David Laight
2014-02-26 18:24     ` Joe Perches
2014-02-26 18:32       ` Alexander Aring
2014-02-26 18:35         ` Joe Perches
2014-02-26 18:56     ` David Miller
2014-02-26 16:05 ` [PATCH net-next v4 3/8] 6lowpan: fix fragmentation on sending side Alexander Aring
     [not found] ` <1393430712-11298-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2014-02-26 16:05   ` [PATCH net-next v4 1/8] 6lowpan: add frag information struct Alexander Aring
2014-02-26 16:05   ` [PATCH net-next v4 4/8] 6lowpan: change tag type to __be16 Alexander Aring
2014-02-26 16:05   ` [PATCH net-next v4 6/8] 6lowpan: fix some checkpatch issues Alexander Aring
     [not found]     ` <1393430712-11298-7-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2014-02-26 17:24       ` Joe Perches
2014-02-26 18:59         ` David Miller
2014-02-26 16:05 ` [PATCH net-next v4 5/8] 6lowpan: move 6lowpan.c to 6lowpan_rtnl.c Alexander Aring
2014-02-26 16:05 ` [PATCH net-next v4 7/8] net: ns: add ieee802154_6lowpan namespace Alexander Aring
2014-02-26 16:05 ` [PATCH net-next v4 8/8] 6lowpan: handling 6lowpan fragmentation via inet_frag api Alexander Aring

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.