Netdev List
 help / color / mirror / Atom feed
* Re: [Xen-devel] [RFC v2 1/4] bridge: enable interfaces to opt out from becoming the root bridge
From: Luis R. Rodriguez @ 2014-02-21 16:01 UTC (permalink / raw)
  To: Zoltan Kiss
  Cc: Ian Campbell, kvm, netdev@vger.kernel.org, bridge,
	linux-kernel@vger.kernel.org, Stephen Hemminger, xen-devel
In-Reply-To: <53074E6B.6030006@citrix.com>

On Fri, Feb 21, 2014 at 5:02 AM, Zoltan Kiss <zoltan.kiss@citrix.com> wrote:
>> Agreed that's the best strategy and I'll work on sending patches to
>> brctl to enable the root_block preference. This approach however also
>
> I don't think brctl should deal with any Xen specific stuff. I assume there
> is a misunderstanding in this thread: when I (and possibly other Xen folks)
> talk about "userspace" or "toolstack" here, I mean Xen specific tools which
> use e.g. brctl to set up bridges. Not brctl itself.

I did mean brctl, but as I looked at the code it doesn't used
rtnl_open() and not sure if Stephen would want that. Additionally even
if it did handle root_block the other issue with this strategy is that
as you noted upon initialization the bridge, without a static MAC
address, could end up setting the backend as the root port, until you
let userspace turn the root_block knob.

  Luis

^ permalink raw reply

* Re: [Xen-devel] [RFC v2 1/4] bridge: enable interfaces to opt out from becoming the root bridge
From: Luis R. Rodriguez @ 2014-02-21 15:59 UTC (permalink / raw)
  To: Zoltan Kiss
  Cc: Ian Campbell, kvm, netdev@vger.kernel.org, bridge,
	linux-kernel@vger.kernel.org, Stephen Hemminger, xen-devel
In-Reply-To: <53074E69.4060206@citrix.com>

On Fri, Feb 21, 2014 at 5:02 AM, Zoltan Kiss <zoltan.kiss@citrix.com> wrote:
> On 20/02/14 20:01, Luis R. Rodriguez wrote:
>>
>> On Thu, Feb 20, 2014 at 5:19 AM, Zoltan Kiss <zoltan.kiss@citrix.com>
>> wrote:
>>>
>>> How about this: netback sets the root_block flag and a random MAC by
>>> default. So the default behaviour won't change, DAD will be happy, and
>>> userspace don't have to do anything unless it's using netback for STP
>>> root
>>> bridge (I don't think there are too many toolstacks doing that), in which
>>> case it has to remove the root_block flag instead of setting a random
>>> MAC.
>>
>>
>> :D that's exactly what I ended up proposing too. I mentioned how
>> xen-netback could do this as well, we'd keep or rename the flag I
>> added, and then the bridge could would look at it and enable the root
>> block if the flag is set. Stephen however does not like having the
>> bridge code look at magic flags for this behavior and would prefer for
>> us to get the tools to ask for the root block. Let's follow more up on
>> that thread
>
> We don't need that new flag, just forget about it.

Unless I'm missing something the root_block flag is a bridge port
primitive. This means we can't set it *until* the interface gets added
to a bridge, and even then, its a knob that would be available only to
the bridge.

> Another problem with the random addresses, pointed out by Ian earlier, that
> when adding/removing interfaces, the bridge does recalculate it's MAC
> address, and choose the lowest one. In the general usecase I think that's
> normal, but in case of Xen networking, we would like to keep the bridge
> using the physical interface's MAC, because the local port of the bridge is
> used for Dom0 network traffic, therefore changing the bridge MAC when a
> netback device has lower MAC breaks that traffic.

This is a good reason then to actually have an interface general
specific knob to annotate to the bridge that we'd prefer to root_block
by default, the alternative as you point out below is to have the xen
/ kvm utils to set the bridge MAC address statically, but that'll
requires a userspace upgrade. I'm looking for a kernel solution that
is backwards compatible with old userspace.

> I think the best is to
> address this from userspace: if it set the MAC of the bridge explicitly,
> dev_set_mac_address() does dev->addr_assign_type = NET_ADDR_SET;, so
> br_stp_recalculate_bridge_id() will exit before changing anything.

That will certainly work for new xen / kvm util userspace.

  Luis

^ permalink raw reply

* [PATCH net-next 3/6] 6lowpan: move 6lowpan.c to 6lowpan_rtnl.c
From: Alexander Aring @ 2014-02-21 15:15 UTC (permalink / raw)
  To: alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend,
	Alexander Aring
In-Reply-To: <1392995711-19563-1-git-send-email-alex.aring@gmail.com>

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

Signed-off-by: Alexander Aring <alex.aring@gmail.com>
Tested-by: Martin Townsend <martin.townsend@xsilon.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

* [PATCH net-next 1/6] 6lowpan: add frag information struct
From: Alexander Aring @ 2014-02-21 15:15 UTC (permalink / raw)
  To: alex.bluesman.smirnov
  Cc: dbaryshkov, davem, linux-zigbee-devel, netdev, martin.townsend,
	Alexander Aring
In-Reply-To: <1392995711-19563-1-git-send-email-alex.aring@gmail.com>

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@gmail.com>
Tested-by: Martin Townsend <martin.townsend@xsilon.com>
---
 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

^ permalink raw reply related

* [PATCH net-next 0/6] 6lowpan: reimplementation of fragmentation handling
From: Alexander Aring @ 2014-02-21 15:15 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

Alexander Aring (6):
  6lowpan: add frag information struct
  6lowpan: fix fragmentation on sending side
  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                     | 112 ++++++
 net/ieee802154/{6lowpan.c => 6lowpan_rtnl.c} | 327 +++++-----------
 net/ieee802154/Makefile                      |   1 +
 net/ieee802154/reassembly.c                  | 565 +++++++++++++++++++++++++++
 net/ieee802154/reassembly.h                  |  66 ++++
 8 files changed, 869 insertions(+), 235 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

* [PATCH net-next 6/6] 6lowpan: handling 6lowpan fragmentation via inet_frag api
From: Alexander Aring @ 2014-02-21 15:15 UTC (permalink / raw)
  To: alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1392995711-19563-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

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-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Tested-by: Martin Townsend <martin.townsend-I0Qfutc96jjQT0dZR+AlfA@public.gmane.org>
---
 include/net/netns/ieee802154_6lowpan.h |   9 +
 net/ieee802154/6lowpan.h               | 112 +++++++
 net/ieee802154/6lowpan_rtnl.c          | 256 +++------------
 net/ieee802154/Makefile                |   2 +-
 net/ieee802154/reassembly.c            | 565 +++++++++++++++++++++++++++++++++
 net/ieee802154/reassembly.h            |  66 ++++
 6 files changed, 802 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.h b/net/ieee802154/6lowpan.h
index 2b835db..feafa8e 100644
--- a/net/ieee802154/6lowpan.h
+++ b/net/ieee802154/6lowpan.h
@@ -306,6 +306,118 @@ static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
 	*hc_ptr += len;
 }
 
+static inline size_t lowpan_addr_mode_size(const u8 addr_mode)
+{
+	u16 ret = 0;
+
+	switch (addr_mode) {
+	case LOWPAN_IPHC_ADDR_00:
+		ret += 16;
+		break;
+	case LOWPAN_IPHC_ADDR_01:
+		ret += 8;
+		break;
+	case LOWPAN_IPHC_ADDR_02:
+		ret += 2;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static inline size_t lowpan_next_hdr_size(const u8 h_enc, u16 *uncomp_header)
+{
+	u16 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;
+}
+
+static inline size_t lowpan_header_delta_size(const struct sk_buff *skb)
+{
+	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);
+	}
+
+	return 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,
diff --git a/net/ieee802154/6lowpan_rtnl.c b/net/ieee802154/6lowpan_rtnl.c
index b543488..7e4fd93 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)
 {
@@ -188,69 +177,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;
@@ -264,94 +190,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;
 
@@ -364,8 +202,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;
@@ -609,44 +445,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;
@@ -654,9 +499,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;
 }
 
@@ -784,43 +629,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..3b49b97
--- /dev/null
+++ b/net/ieee802154/reassembly.c
@@ -0,0 +1,565 @@
+/*	6LoWPAN fragment reassembly
+ *
+ *
+ *	Authors:
+ *	Alexander Aring		<aar-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ *	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 += skb->len + lowpan_header_delta_size(skb);
+		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
+		frag_info->d_offset = 0;
+
+	if (unlikely(fail))
+		return -EIO;
+
+	skb_reset_network_header(skb);
+
+	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


------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk

^ permalink raw reply related

* [PATCH net-next 5/6] net: ns: add ieee802154_6lowpan namespace
From: Alexander Aring @ 2014-02-21 15:15 UTC (permalink / raw)
  To: alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1392995711-19563-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

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-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Tested-by: Martin Townsend <martin.townsend-I0Qfutc96jjQT0dZR+AlfA@public.gmane.org>
---
 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


------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk

^ permalink raw reply related

* [PATCH net-next 4/6] 6lowpan: fix some checkpatch issues
From: Alexander Aring @ 2014-02-21 15:15 UTC (permalink / raw)
  To: alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1392995711-19563-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

Detected with:

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

Signed-off-by: Alexander Aring <alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Tested-by: Martin Townsend <martin.townsend-I0Qfutc96jjQT0dZR+AlfA@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 0fe0173..b543488 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:
@@ -133,13 +127,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
 	 */
@@ -154,8 +146,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)) {
@@ -395,7 +386,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;
@@ -484,8 +475,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.", __func__);
+			pr_debug("tag: %d, offset: %d", tag, offset);
 			goto exit;
 		}
 
@@ -692,7 +683,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


------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk

^ permalink raw reply related

* [PATCH net-next 2/6] 6lowpan: fix fragmentation on sending side
From: Alexander Aring @ 2014-02-21 15:15 UTC (permalink / raw)
  To: alex.bluesman.smirnov-Re5JQEeQqe8AvxtiuMwx3w
  Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
	linux-zigbee-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <1392995711-19563-1-git-send-email-alex.aring-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>

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-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Tested-by: Martin Townsend <martin.townsend-I0Qfutc96jjQT0dZR+AlfA@public.gmane.org>
---
 net/ieee802154/6lowpan.c | 44 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 34 insertions(+), 10 deletions(-)

diff --git a/net/ieee802154/6lowpan.c b/net/ieee802154/6lowpan.c
index 8edfea5..0fe0173 100644
--- a/net/ieee802154/6lowpan.c
+++ b/net/ieee802154/6lowpan.c
@@ -106,6 +106,7 @@ static int lowpan_header_create(struct sk_buff *skb,
 			   unsigned short type, const void *_daddr,
 			   const void *_saddr, unsigned int len)
 {
+	struct ipv6hdr *hdr;
 	const u8 *saddr = _saddr;
 	const u8 *daddr = _daddr;
 	struct ieee802154_addr sa, da;
@@ -116,12 +117,20 @@ static int lowpan_header_create(struct sk_buff *skb,
 	if (type != ETH_P_IPV6)
 		return 0;
 
+	hdr = ipv6_hdr(skb);
+
 	if (!saddr)
 		saddr = dev->dev_addr;
 
 	raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
 	raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
 
+	/* Before replace ipv6hdr to 6lowpan header we save the dgram_size */
+	mac_cb(skb)->frag_info.d_size = len;
+	mac_cb(skb)->frag_info.d_offset = sizeof(struct ipv6hdr);
+	if (hdr->nexthdr == UIP_PROTO_UDP)
+		mac_cb(skb)->frag_info.d_offset += sizeof(struct udphdr);
+
 	lowpan_header_compress(skb, dev, type, daddr, saddr, len);
 
 	/*
@@ -422,44 +431,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 >> 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 +490,7 @@ lowpan_skb_fragmentation(struct sk_buff *skb, struct net_device *dev)
 		}
 
 		offset += len;
+		dgram_offset += len;
 	}
 
 exit:
-- 
1.9.0


------------------------------------------------------------------------------
Managing the Performance of Cloud-Based Applications
Take advantage of what the Cloud has to offer - Avoid Common Pitfalls.
Read the Whitepaper.
http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk

^ permalink raw reply related

* Re: [PATCH 1/1] rtlwifi: Convert drivers to use new API for ieee80211_is_robust_mgmt_frame()
From: Larry Finger @ 2014-02-21 15:03 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless, netdev
In-Reply-To: <1392993530.4346.49.camel@jlt4.sipsolutions.net>

On 02/21/2014 08:38 AM, Johannes Berg wrote:
> On Fri, 2014-02-21 at 08:33 -0600, Larry Finger wrote:
>> Drivers rtl8188ee, rtl8192ce, rtl8192se, and rtl8723ae all use this routine.
>> In addition, all callers of ieee80211_is_robust_mgmt_frame() have access to the
>> skb. Thus, it is trivial to use the new API rather than the underscored old version.
>
> Unfortunately, I'm pretty sure this is incorrect. I looked at this code
> before, and take for example:
>
>> +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
>> @@ -334,8 +334,8 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
>>   			/* during testing, hdr could be NULL here */
>>   			return false;
>>   		}
>> -		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
>> -			(ieee80211_has_protected(hdr->frame_control)))
>> +		if ((ieee80211_is_robust_mgmt_frame(skb)) &&
>> +		    (ieee80211_has_protected(hdr->frame_control)))
>
> Here, hdr is set like this:
>
>                  hdr = (struct ieee80211_hdr *)(skb->data +
>                         status->rx_drvinfo_size + status->rx_bufshift);
>
> so the skb clearly contains something else before the hdr, and the
> conversion is probably not right because it assumes hdr == skb->data,
> where here it isn't that but instead (skb->data + something).

I thought I had tested the change, but I'm not sure if my AP is using 
ieee802.11w. I need to test this better.

@John: Please drop this patch.

Larry

^ permalink raw reply

* Re: [PATCH net V2] virtio-net: alloc big buffers also when guest can receive UFO
From: Michael S. Tsirkin @ 2014-02-21 14:55 UTC (permalink / raw)
  To: Jason Wang
  Cc: virtio-dev, netdev, linux-kernel, virtualization,
	Sridhar Samudrala
In-Reply-To: <1392959284-11399-1-git-send-email-jasowang@redhat.com>

On Fri, Feb 21, 2014 at 01:08:04PM +0800, Jason Wang wrote:
> We should alloc big buffers also when guest can receive UFO
> pakcets to let the big packets be fit into guest rx buffer.

s/pakcets/packets/

s/be fit/fit/

otherwise:

Acked-by: Michael S. Tsirkin <mst@redhat.com>


> 
> Fixes 5c5167515d80f78f6bb538492c423adcae31ad65
> (virtio-net: Allow UFO feature to be set and advertised.)
> 
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Cc: Sridhar Samudrala <sri@us.ibm.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> Changes from V1:
> - tweak the commit log
> ---
>  drivers/net/virtio_net.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index d75f8ed..5632a99 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -1711,7 +1711,8 @@ static int virtnet_probe(struct virtio_device *vdev)
>  	/* If we can receive ANY GSO packets, we must allocate large ones. */
>  	if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
>  	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
> -	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
> +	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
> +	    virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
>  		vi->big_packets = true;
>  
>  	if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
> -- 
> 1.8.3.2

^ permalink raw reply

* Re: Deliver skbs to intermediate interfaces, when using cascaded rx-handlers
From: Tobias Waldekranz @ 2014-02-21 14:54 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev
In-Reply-To: <20140221144827.GG2870@minipsycho.orion>

On Fri, Feb 21, 2014 at 03:48:27PM +0100, Jiri Pirko wrote:
> Fri, Feb 21, 2014 at 03:31:14PM CET, tobias@waldekranz.com wrote:
> >On Fri, Feb 21, 2014 at 02:05:53PM +0100, Jiri Pirko wrote:
> >> Fri, Feb 21, 2014 at 01:02:44PM CET, tobias@waldekranz.com wrote:
> >> >On Fri, Feb 21, 2014 at 12:37:53PM +0100, Jiri Pirko wrote:
> >> >> Fri, Feb 21, 2014 at 12:12:57PM CET, tobias@waldekranz.com wrote:
> >> >> >> What "switch driver" are you reffering to?
> >> >> >> 
> >> >> >
> >> >> >The driver that is in charge of multiplexing packets from the switch
> >> >> >chip out to the port interfaces. It registers an rx-handler on eth0
> >> >> >and forwards packets to port[1-4] by reading a custom tag (similar to
> >> >> >802.1Q) inserted by the switch.
> >> >> 
> >> >> Allright, but what's the name? I would like to find it and see the code.
> >> >
> >> >There's not really a name :), but I have made the source available on github:
> >> >
> >> >https://github.com/wkz/switchcore
> >> 
> >> Are you aware of existing DSA infrastructure?
> >> 
> >
> >Yes I am, we have our reasons for using our own driver. Most of it
> >having to do with dynamic configuration, multiple hardware channel
> >support and a variety of exotic hardware setups.
> 
> Would not it be better to make DSA better in order to achieve your goal?
> 

Sure, that is something we are considering. But before we do that we
need to make sure that our model works, end-to-end, for all important
use-cases.

> >
> >Do you have any input on the original question?
> 
> I'm not really sure how to handle this. I fail to clearly understand the
> topology you are describing...
> 
> >
> >> >
> >> >The relevant parts for this discussion should be in sc_main.c.
> >> >
> >> >> 
> >> >> >
> >> >> >-- 
> >> >> >Thanks
> >> >> > - wkz
> >> >
> >> >-- 
> >> >Thanks
> >> > - wkz
> >
> >-- 
> >Thanks
> > - wkz

-- 
Thanks
 - wkz

^ permalink raw reply

* Re: Deliver skbs to intermediate interfaces, when using cascaded rx-handlers
From: Jiri Pirko @ 2014-02-21 14:48 UTC (permalink / raw)
  To: Tobias Waldekranz; +Cc: netdev
In-Reply-To: <20140221143114.GC25406@gmail.com>

Fri, Feb 21, 2014 at 03:31:14PM CET, tobias@waldekranz.com wrote:
>On Fri, Feb 21, 2014 at 02:05:53PM +0100, Jiri Pirko wrote:
>> Fri, Feb 21, 2014 at 01:02:44PM CET, tobias@waldekranz.com wrote:
>> >On Fri, Feb 21, 2014 at 12:37:53PM +0100, Jiri Pirko wrote:
>> >> Fri, Feb 21, 2014 at 12:12:57PM CET, tobias@waldekranz.com wrote:
>> >> >> What "switch driver" are you reffering to?
>> >> >> 
>> >> >
>> >> >The driver that is in charge of multiplexing packets from the switch
>> >> >chip out to the port interfaces. It registers an rx-handler on eth0
>> >> >and forwards packets to port[1-4] by reading a custom tag (similar to
>> >> >802.1Q) inserted by the switch.
>> >> 
>> >> Allright, but what's the name? I would like to find it and see the code.
>> >
>> >There's not really a name :), but I have made the source available on github:
>> >
>> >https://github.com/wkz/switchcore
>> 
>> Are you aware of existing DSA infrastructure?
>> 
>
>Yes I am, we have our reasons for using our own driver. Most of it
>having to do with dynamic configuration, multiple hardware channel
>support and a variety of exotic hardware setups.

Would not it be better to make DSA better in order to achieve your goal?

>
>Do you have any input on the original question?

I'm not really sure how to handle this. I fail to clearly understand the
topology you are describing...

>
>> >
>> >The relevant parts for this discussion should be in sc_main.c.
>> >
>> >> 
>> >> >
>> >> >-- 
>> >> >Thanks
>> >> > - wkz
>> >
>> >-- 
>> >Thanks
>> > - wkz
>
>-- 
>Thanks
> - wkz

^ permalink raw reply

* [PATCH] NewCWV for Linux
From: Raffaello Secchi @ 2014-02-21 14:42 UTC (permalink / raw)
  To: netdev, Hossain, Ziaul, Gorry Fairhurst, Alexander.Zimmermann

Hi,

Sorry for posting from a different account (and creating problems to
this list anyway),
I could not handle replies from the previous account.

Of course we are going to sign this patch (please find the signed code below),
sorry for missing it the first time.

In reply to Alex's question:

At the moment the module supports Reno only. We thought we could add
a call-back in our "cong_avoid" to call another CC from our
tcp_newcwv_cong_avoid,
but then we realised that there could be incompatibilities with other CCs.

The best approach would be probably to modify the core TCP code using
conditional programming to add NewCWV. However, we thought this approach would
be more invasive than a module, which is meant for initial experimentation.

I'll be happy to rewrite a patch to modify core TCP files if you think
is the case.

Regards,

Raffaello


Signed-off-by: Raffaello Secchi <r.secchi@gmail.com>
Signed-off-by: Ziaul Hossain <zia@erg.abdn.ac.uk>
---
 net/ipv4/Kconfig      |   17 +++
 net/ipv4/Makefile     |    1 +
 net/ipv4/tcp_newcwv.c |  317 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 335 insertions(+)
 create mode 100644 net/ipv4/tcp_newcwv.c

diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 05c57f0..72294d8 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -556,6 +556,23 @@ config TCP_CONG_ILLINOIS
     For further details see:
       http://www.ews.uiuc.edu/~shaoliu/tcpillinois/index.html

+config TCP_CONG_NEWCWV
+    tristate "TCP New-CWV"
+    default n
+    ---help---
+    TCP new-CWV is a send-side modification of TCP to improve
+    congestion control for rate-limited applications. new-CWV allows
+    faster restarts after long idle periods and better congestion control
+    during periods the cwnd cannot be fully utilised.
+
+    If you select this congestion control method, it is recommended
+    to disable tcp_slow_start_after_idle:
+
+    echo "0" > /proc/sys/net/ipv4/tcp_slow_start_after_idle
+
+    For further details see:
+      http://tools.ietf.org/html/draft-ietf-tcpm-newcwv-05
+
 choice
     prompt "Default TCP congestion control"
     default DEFAULT_CUBIC
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index f8c49ce..9424160 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
 obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o
 obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o
 obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o
+obj-$(CONFIG_TCP_CONG_NEWCWV) += tcp_newcwv.o
 obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o
 obj-$(CONFIG_NETLABEL) += cipso_ipv4.o

diff --git a/net/ipv4/tcp_newcwv.c b/net/ipv4/tcp_newcwv.c
new file mode 100644
index 0000000..6f669e4
--- /dev/null
+++ b/net/ipv4/tcp_newcwv.c
@@ -0,0 +1,317 @@
+/*
+ * New-CWV implementation for Linux: draft-ietf-tcpm-newcwv-05.txt
+ */
+
+#include <linux/module.h>
+#include <net/tcp.h>
+
+#define UNDEF_PIPEACK                     -1
+#define PIPEACK_INIT              TCP_INFINITE_SSTHRESH
+#define TCP_RESTART_WINDOW        1
+#define FIVEMINS              (HZ*300)
+#define NO_OF_BINS                      4
+#define IS_VALID                        0x0002
+#define IS_RECOVERY                     0x0001
+#define nextbin(x)  (((x)+1) & 0x03)
+#define prevbin(x)  (((x)-1) & 0x03)
+
+/* contains newcwv state variables */
+struct newcwv {
+    int psample[NO_OF_BINS];    /* pipeACK samples circular buffer */
+    u32 time_stamp[NO_OF_BINS];    /* pipeACK sample timestamps */
+    int pipeack;        /* pipeACK value after filtering */
+    u8 rsvd;
+    u8 head;        /* index for psample array */
+    u16 flags;
+    u32 prior_in_flight;    /* Packets in flight for cwnd reduction */
+    u32 prior_retrans;    /* Retransmission before going into FR */
+    u32 prev_snd_una;    /* snd_una when last record kept */
+    u32 prev_snd_nxt;    /* snd_una when last record kept */
+    u32 cwnd_valid_ts;    /* last time cwnd was found 'validated' */
+    u32 psp;        /* pipeACK Sampling Period */
+};
+
+/* helper function for division */
+static u32 divide_or_zero(u32 dividend, u32 divisor)
+{
+    if (divisor == 0)
+        return 0;
+    else
+        return (u32) (dividend / divisor);
+}
+
+/* adds an element to the circular buffer for maximum filter */
+static void add_element(struct newcwv *nc, int val)
+{
+    nc->head = nextbin(nc->head);
+    nc->psample[nc->head] = val;
+    nc->time_stamp[nc->head] = tcp_time_stamp;
+}
+
+/* This fuction removes all the expired elements from the circular buffer
+ * and returns the maximum from the remaining elements
+ */
+static int remove_expired_element(struct newcwv *nc)
+{
+    int k = nc->head;
+    int tmp = nc->psample[nc->head];
+
+    while (nc->psample[k] != UNDEF_PIPEACK) {
+        /* remove expired */
+        if (nc->time_stamp[k] < tcp_time_stamp - nc->psp) {
+            nc->psample[k] = UNDEF_PIPEACK;
+            return tmp;
+        }
+
+        /* search the maximum */
+        if (nc->psample[k] > tmp)
+            tmp = nc->psample[k];
+
+        k = prevbin(k);
+        if (k == nc->head)
+            return tmp;
+    }
+
+    return tmp;
+}
+
+/* is TCP in the validated phase? */
+static inline bool tcp_is_in_vp(struct tcp_sock *tp, int pa)
+{
+    if (pa == UNDEF_PIPEACK)
+        return true;
+    else
+        return ((pa << 1) >= (tp->snd_cwnd * tp->mss_cache));
+}
+
+/* reduces the cwnd after 5mins of non-validated phase */
+static void datalim_closedown(struct sock *sk)
+{
+    struct newcwv *nc = inet_csk_ca(sk);
+    struct tcp_sock *tp = tcp_sk(sk);
+    u32 nc_ts;
+
+    nc_ts = nc->cwnd_valid_ts;
+    while ((tcp_time_stamp - nc_ts) > FIVEMINS) {
+        nc_ts += FIVEMINS;
+        nc->cwnd_valid_ts = nc_ts;
+        tp->snd_ssthresh =
+            max((3 * tp->snd_cwnd) >> 2, tp->snd_ssthresh);
+        tp->snd_cwnd =
+            max_t(u32, tp->snd_cwnd >> 1, TCP_INIT_CWND);
+    }
+}
+
+
+/* updates pipeack when an ACK is received */
+static void update_pipeack(struct sock *sk)
+{
+    struct newcwv *nc = inet_csk_ca(sk);
+    struct tcp_sock *tp = tcp_sk(sk);
+    int tmp_pipeack;
+
+    nc->psp = max(3 * (tp->srtt >> 3), (u32) HZ);
+
+    if (tp->snd_una >= nc->prev_snd_nxt) {
+
+        /* now get a new pipeack sample */
+        tmp_pipeack = tp->snd_una - nc->prev_snd_una;
+        nc->prev_snd_una = tp->snd_una;
+        nc->prev_snd_nxt = tp->snd_nxt;
+
+        /* create a new element at the end of current pmp */
+        if (tcp_time_stamp > nc->time_stamp[nc->head] + (nc->psp >> 2))
+            add_element(nc, tmp_pipeack);
+        else if (tmp_pipeack > nc->psample[nc->head])
+            nc->psample[nc->head] = tmp_pipeack;
+    }
+
+    nc->pipeack = remove_expired_element(nc);
+
+    /* check if cwnd is validated */
+    if (tcp_is_in_vp(tp, nc->pipeack)) {
+        nc->flags |= IS_VALID;
+        nc->cwnd_valid_ts = tcp_time_stamp;
+    } else {
+        nc->flags &= ~IS_VALID;
+        datalim_closedown(sk);
+    }
+}
+
+/* initialises newcwv variables */
+static void tcp_newcwv_init(struct sock *sk)
+{
+    struct newcwv *nc = inet_csk_ca(sk);
+    struct tcp_sock *tp = tcp_sk(sk);
+
+    nc->prev_snd_una = tp->snd_una;
+    nc->prev_snd_nxt = tp->snd_nxt;
+
+    nc->cwnd_valid_ts = tcp_time_stamp;
+    nc->flags = IS_VALID;
+
+    nc->psp = max(3 * (tp->srtt >> 3), (u32) HZ);
+
+    nc->head = 0;
+    nc->psample[0] = UNDEF_PIPEACK;
+    nc->pipeack = UNDEF_PIPEACK;
+}
+
+
+/* cong_avoid action: non dubious ACK received */
+static void tcp_newcwv_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
+{
+    struct newcwv *nc = inet_csk_ca(sk);
+    struct tcp_sock *tp = tcp_sk(sk);
+
+    nc->prior_in_flight = in_flight;
+    nc->prior_retrans = tp->total_retrans;
+
+    update_pipeack(sk);
+
+    /* Check if cwnd is validated */
+    if (!(nc->flags & IS_VALID) && !tcp_is_cwnd_limited(sk, in_flight))
+        return;
+
+    /* The following is the Reno behaviour */
+
+    /* In "safe" area, increase. */
+    if (tp->snd_cwnd <= tp->snd_ssthresh)
+        tcp_slow_start(tp);
+
+    /* In dangerous area, increase slowly. */
+    else
+        tcp_cong_avoid_ai(tp, tp->snd_cwnd);
+
+}
+
+/* newcwv actions in fast recovery */
+static void tcp_newcwv_enter_recovery(struct sock *sk)
+{
+    struct newcwv *nc = inet_csk_ca(sk);
+    struct tcp_sock *tp = tcp_sk(sk);
+    u32 pipeack;
+
+    nc->flags |= IS_RECOVERY;
+
+    pipeack = (nc->pipeack == UNDEF_PIPEACK) ? 0 : (u32)
+        nc->pipeack;
+    pipeack = divide_or_zero(pipeack, (u32) tp->mss_cache);
+    tp->snd_cwnd = max(pipeack, nc->prior_in_flight) >> 1;
+
+    /* make sure the min. value for cwnd is 1 */
+    tp->snd_cwnd = (tp->snd_cwnd < 1) ? 1 : tp->snd_cwnd;
+
+}
+
+/* newcwv actions at the end of recovery */
+static void tcp_newcwv_end_recovery(struct sock *sk)
+{
+    struct newcwv *nc = inet_csk_ca(sk);
+    struct tcp_sock *tp = tcp_sk(sk);
+    u32 retrans, pipeack;
+
+    pipeack = (nc->pipeack == UNDEF_PIPEACK) ? 0 : (u32)
+        nc->pipeack;
+
+    pipeack = divide_or_zero(pipeack, (u32) tp->mss_cache);
+    retrans = tp->total_retrans - nc->prior_retrans;
+    tp->snd_cwnd = (max(pipeack, nc->prior_in_flight) - retrans) >> 1;
+    if (tp->snd_cwnd < TCP_RESTART_WINDOW)
+        tp->snd_cwnd = TCP_RESTART_WINDOW;
+
+    tp->snd_ssthresh = tp->snd_cwnd;
+    nc->flags &= ~IS_RECOVERY;
+
+    /* restart cwv machine */
+    tcp_newcwv_init(sk);
+
+}
+
+/* newcwv actions corresponding to event */
+static void tcp_newcwv_event(struct sock *sk, enum tcp_ca_event event)
+{
+    struct newcwv *nc = inet_csk_ca(sk);
+    const struct inet_connection_sock *icsk = inet_csk(sk);
+
+    switch (event) {
+    case CA_EVENT_TX_START:
+        datalim_closedown(sk);
+        break;
+
+    case CA_EVENT_COMPLETE_CWR:
+        if (!(nc->flags & IS_VALID))
+            tcp_newcwv_end_recovery(sk);
+        break;
+
+    case CA_EVENT_LOSS:
+        tcp_newcwv_init(sk);
+        break;
+
+    case CA_EVENT_SLOW_ACK:
+
+        switch (icsk->icsk_ca_state) {
+        case TCP_CA_Recovery:
+            if (!nc->flags)
+                tcp_newcwv_enter_recovery(sk);
+            break;
+
+        case TCP_CA_Open:
+        case TCP_CA_Disorder:
+        default:
+            break;
+        }
+        break;
+
+    case CA_EVENT_CWND_RESTART:
+    case CA_EVENT_FAST_ACK:
+    default:
+        break;
+    }
+
+}
+
+/* Slow start threshold resetting after loss */
+u32 tcp_newcwv_ssthresh(struct sock *sk)
+{
+    const struct tcp_sock *tp = tcp_sk(sk);
+
+    /* This is tcp_packets_in_flight */
+    u32 prior_in_flight =
+        tp->packets_out - tp->sacked_out - tp->lost_out + tp->retrans_out;
+
+    return max(prior_in_flight >> 1U, 2U);
+}
+
+struct tcp_congestion_ops tcp_newcwv = {
+    .flags = TCP_CONG_NON_RESTRICTED,
+    .name = "newcwv",
+    .init = tcp_newcwv_init,
+    .owner = THIS_MODULE,
+    .ssthresh = tcp_newcwv_ssthresh,
+    .cong_avoid = tcp_newcwv_cong_avoid,
+    .cwnd_event = tcp_newcwv_event,
+    .min_cwnd = tcp_reno_min_cwnd,
+};
+
+/* newcwv registered as congestion control in Linux */
+static int __init tcp_newcwv_register(void)
+{
+    BUILD_BUG_ON(sizeof(struct newcwv) > ICSK_CA_PRIV_SIZE);
+    tcp_register_congestion_control(&tcp_newcwv);
+
+    return 0;
+}
+
+/* unregister when module is disabled */
+static void __exit tcp_newcwv_unregister(void)
+{
+    tcp_unregister_congestion_control(&tcp_newcwv);
+}
+
+module_init(tcp_newcwv_register);
+module_exit(tcp_newcwv_unregister);
+
+MODULE_AUTHOR("Ziaul Hossain, Raffaello Secchi");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("NewCwv Reno variant");
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH] MAINTAINERS: add entry for the PHY library
From: Ben Dooks @ 2014-02-21 14:41 UTC (permalink / raw)
  To: Florian Fainelli; +Cc: netdev, davem, Grant Likely, Shaohui Xie, Andy Fleming
In-Reply-To: <1392745669-26645-1-git-send-email-f.fainelli@gmail.com>

On 18/02/14 17:47, Florian Fainelli wrote:
> The PHY library has been subject to some changes, new drivers and DT
> interactions over the past few months. Add myself as a maintainer for
> the core PHY library parts and drivers. Make sure the PHY library entry
> also covers the Device Tree files which have a close interaction with
> the MDIO bus, PHY connection and Ethernet PHY mode parsing.
>
> CC: Grant Likely <grant.likely@linaro.org>
> CC: Shaohui Xie <shaohui.xie@freescale.com>
> CC: Andy Fleming <afleming@gmail.com>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
>   MAINTAINERS | 11 +++++++++++
>   1 file changed, 11 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 5a7b3ec..2bfdb79 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -3330,6 +3330,17 @@ S:	Maintained
>   F:	include/linux/netfilter_bridge/
>   F:	net/bridge/
>
> +ETHERNET PHY LIBRARY
> +M:	Florian Fainelli <f.fainelli@gmail.com>
> +L:	netdev@vger.kernel.org
> +S:	Maintained
> +F:	include/linux/phy.h
> +F:	include/linux/phy_fixed.h
> +F:	drivers/net/phy/
> +F:	Documentation/networking/phy.txt
> +F:	drivers/of/of_mdio.c
> +F:	drivers/of/of_net.c

Did you miss out:
  Documentation/devicetree/bindings/net/phy.txt



-- 
Ben Dooks				http://www.codethink.co.uk/
Senior Engineer				Codethink - Providing Genius

^ permalink raw reply

* Re: [PATCH 1/1] rtlwifi: Convert drivers to use new API for ieee80211_is_robust_mgmt_frame()
From: Johannes Berg @ 2014-02-21 14:38 UTC (permalink / raw)
  To: Larry Finger
  Cc: linville-2XuSBdqkA4R54TAoqtyWWQ,
	linux-wireless-u79uwXL29TY76Z2rM5mHXA,
	netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1392993211-3848-1-git-send-email-Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ@public.gmane.org>

On Fri, 2014-02-21 at 08:33 -0600, Larry Finger wrote:
> Drivers rtl8188ee, rtl8192ce, rtl8192se, and rtl8723ae all use this routine.
> In addition, all callers of ieee80211_is_robust_mgmt_frame() have access to the
> skb. Thus, it is trivial to use the new API rather than the underscored old version.

Unfortunately, I'm pretty sure this is incorrect. I looked at this code
before, and take for example:

> +++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
> @@ -334,8 +334,8 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
>  			/* during testing, hdr could be NULL here */
>  			return false;
>  		}
> -		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
> -			(ieee80211_has_protected(hdr->frame_control)))
> +		if ((ieee80211_is_robust_mgmt_frame(skb)) &&
> +		    (ieee80211_has_protected(hdr->frame_control)))

Here, hdr is set like this:

                hdr = (struct ieee80211_hdr *)(skb->data +
                       status->rx_drvinfo_size + status->rx_bufshift);  

so the skb clearly contains something else before the hdr, and the
conversion is probably not right because it assumes hdr == skb->data,
where here it isn't that but instead (skb->data + something).

johannes

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH net 5/5] qlcnic: reset firmware API lock during driver load
From: Sergei Shtylyov @ 2014-02-21 14:36 UTC (permalink / raw)
  To: Shahed Shaikh, davem; +Cc: netdev, Dept-HSGLinuxNICDev, Sony Chacko
In-Reply-To: <1392963788-18341-6-git-send-email-shahed.shaikh@qlogic.com>

Hello.

On 21-02-2014 10:23, Shahed Shaikh wrote:

> From: Sony Chacko <sony.chacko@qlogic.com>

> Firmware is not resetting API lock at initialization,
> reset the lock at driver load time.

> Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
> ---
>   drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 13 +++++++++++++
>   1 file changed, 13 insertions(+)

> diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
> index 1222865..61f8893 100644
> --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
> +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
> @@ -2305,6 +2305,18 @@ void qlcnic_set_drv_version(struct qlcnic_adapter *adapter)
>   		qlcnic_fw_cmd_set_drv_version(adapter, fw_cmd);
>   }
>
> +static void qlcnic_reset_api_lock(struct qlcnic_adapter *adapter)
> +{
> +	/* Check lock availability*/
> +	if (qlcnic_api_lock(adapter)) {
> +		/* Lock not available, force release the lock */
> +		qlcnic_api_unlock(adapter);
> +	} else {
> +		/* Lock available, release it before proceeding */
> +		qlcnic_api_unlock(adapter);
> +	}

    Isn't it simpler to just do:

	qlcnic_api_lock(adapter);
	qlcnic_api_unlock(adapter);

> +}
> +
>   static int
>   qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
>   {

WBR, Sergei

^ permalink raw reply

* [PATCH 1/1] rtlwifi: Convert drivers to use new API for ieee80211_is_robust_mgmt_frame()
From: Larry Finger @ 2014-02-21 14:33 UTC (permalink / raw)
  To: linville-2XuSBdqkA4R54TAoqtyWWQ
  Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA, Larry Finger,
	netdev-u79uwXL29TY76Z2rM5mHXA, Johannes Berg

Drivers rtl8188ee, rtl8192ce, rtl8192se, and rtl8723ae all use this routine.
In addition, all callers of ieee80211_is_robust_mgmt_frame() have access to the
skb. Thus, it is trivial to use the new API rather than the underscored old version.

Signed-off-by: Larry Finger <Larry.Finger-tQ5ms3gMjBLk1uMJSBkQmQ@public.gmane.org>
Cc: Johannes Berg <johannes-cdvu00un1VgdHxzADdlk8Q@public.gmane.org>
---

Johannes,

I think this patch removes all callers of the old API.

Larry
---

 drivers/net/wireless/rtlwifi/rtl8188ee/trx.c | 2 +-
 drivers/net/wireless/rtlwifi/rtl8192ce/trx.c | 2 +-
 drivers/net/wireless/rtlwifi/rtl8192se/trx.c | 2 +-
 drivers/net/wireless/rtlwifi/rtl8723ae/trx.c | 4 ++--
 4 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
index 27ace30..384245f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
@@ -452,7 +452,7 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
 			/* During testing, hdr was NULL */
 			return false;
 		}
-		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+		if ((ieee80211_is_robust_mgmt_frame(skb)) &&
 		    (ieee80211_has_protected(hdr->frame_control)))
 			rx_status->flag &= ~RX_FLAG_DECRYPTED;
 		else
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index 114858d..0d05bac 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -393,7 +393,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
 			/* In testing, hdr was NULL here */
 			return false;
 		}
-		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+		if ((ieee80211_is_robust_mgmt_frame(skb)) &&
 		    (ieee80211_has_protected(hdr->frame_control)))
 			rx_status->flag &= ~RX_FLAG_DECRYPTED;
 		else
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 163a681..af1bb3d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -310,7 +310,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
 			/* during testing, hdr was NULL here */
 			return false;
 		}
-		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
+		if ((ieee80211_is_robust_mgmt_frame(skb)) &&
 			(ieee80211_has_protected(hdr->frame_control)))
 			rx_status->flag &= ~RX_FLAG_DECRYPTED;
 		else
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
index 721162c..8f20226 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -334,8 +334,8 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
 			/* during testing, hdr could be NULL here */
 			return false;
 		}
-		if ((_ieee80211_is_robust_mgmt_frame(hdr)) &&
-			(ieee80211_has_protected(hdr->frame_control)))
+		if ((ieee80211_is_robust_mgmt_frame(skb)) &&
+		    (ieee80211_has_protected(hdr->frame_control)))
 			rx_status->flag &= ~RX_FLAG_DECRYPTED;
 		else
 			rx_status->flag |= RX_FLAG_DECRYPTED;
-- 
1.8.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: Deliver skbs to intermediate interfaces, when using cascaded rx-handlers
From: Tobias Waldekranz @ 2014-02-21 14:31 UTC (permalink / raw)
  To: Jiri Pirko; +Cc: netdev
In-Reply-To: <20140221130553.GE2870@minipsycho.orion>

On Fri, Feb 21, 2014 at 02:05:53PM +0100, Jiri Pirko wrote:
> Fri, Feb 21, 2014 at 01:02:44PM CET, tobias@waldekranz.com wrote:
> >On Fri, Feb 21, 2014 at 12:37:53PM +0100, Jiri Pirko wrote:
> >> Fri, Feb 21, 2014 at 12:12:57PM CET, tobias@waldekranz.com wrote:
> >> >> What "switch driver" are you reffering to?
> >> >> 
> >> >
> >> >The driver that is in charge of multiplexing packets from the switch
> >> >chip out to the port interfaces. It registers an rx-handler on eth0
> >> >and forwards packets to port[1-4] by reading a custom tag (similar to
> >> >802.1Q) inserted by the switch.
> >> 
> >> Allright, but what's the name? I would like to find it and see the code.
> >
> >There's not really a name :), but I have made the source available on github:
> >
> >https://github.com/wkz/switchcore
> 
> Are you aware of existing DSA infrastructure?
> 

Yes I am, we have our reasons for using our own driver. Most of it
having to do with dynamic configuration, multiple hardware channel
support and a variety of exotic hardware setups.

Do you have any input on the original question?

> >
> >The relevant parts for this discussion should be in sc_main.c.
> >
> >> 
> >> >
> >> >-- 
> >> >Thanks
> >> > - wkz
> >
> >-- 
> >Thanks
> > - wkz

-- 
Thanks
 - wkz

^ permalink raw reply

* Re: [PATCH 1/4] net: rfkill: gpio: remove unused and obsolete platform parameters
From: Heikki Krogerus @ 2014-02-21 14:23 UTC (permalink / raw)
  To: Marc Dietrich
  Cc: Johannes Berg, David S. Miller, Chen-Yu Tsai, Rhyland Klein,
	linux-wireless, netdev, linux-kernel
In-Reply-To: <1723302.jKkc8NDNRI@fb07-iapwap2>

Hi,

On Fri, Feb 21, 2014 at 02:55:14PM +0100, Marc Dietrich wrote:
> Am Donnerstag, 20. Februar 2014, 14:51:34 schrieb Heikki Krogerus:
> > After upgrading to descriptor based gpios, the gpio numbers
> > are not used anymore. The power_clk_name and the platform
> > specific setup and close hooks are not used by anybody, and
> > we should not encourage use of such things, so removing them.
> 
> arch/arm/mach-tegra/board-paz00.c is still using platform data. Is there some 
> prerequisite patch I'm missing (3.14-rc3) or how can this file be converted? 
> We are waiting for DT support to arrive so we can finally remove this file.

True! It still set's the shutdown_gpio and reset_gpio members. I think
I'll leave the header untouched and just clean net/rfkill/rfkill-gpio.c
in this patch. We can remove the whole header after you guys have moved
to DT.

I'll prepare v2 next week.

Thanks!

-- 
heikki

^ permalink raw reply

* RE: [PATCH net 0/7] qlcnic: Re-factoring and enhancements
From: Shahed Shaikh @ 2014-02-21 14:00 UTC (permalink / raw)
  To: David Miller; +Cc: netdev, Dept-HSG Linux NIC Dev
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

> -----Original Message-----
> From: Shahed Shaikh [mailto:shahed.shaikh@qlogic.com]
> Sent: Friday, February 21, 2014 6:50 PM
> To: David Miller
> Cc: netdev; Dept-HSG Linux NIC Dev; Shahed Shaikh
> Subject: [PATCH net 0/7] qlcnic: Re-factoring and enhancements
> 
> From: Shahed Shaikh <shahed.shaikh@qlogic.com>
> 
> Hi David,
> 
> This patch series includes following changes -
> * Re-factored firmware minidump template header handling
> * Support to make 8 vNIC mode application to work with 16 vNIC mode
> * Enhance error message logging when adapter is in failed state and
>   when adapter lock access fails.
> * Allow vlan0 traffic
> * update MAINTAINERS
> 
> Please apply this series to net-next

Please discard this series. Subject prefix should have been "net-next" instead of "net".
I will send this series again with correct subject prefix.
Sorry for the trouble caused.

Thanks,
Shahed

^ permalink raw reply

* [PATCH net 5/7] qlcnic: Enhance semaphore lock access failure error message
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Harish Patil
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

From: Harish Patil <harish.patil@qlogic.com>

Signed-off-by: Harish Patil <harish.patil@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 03d18a0..9f3adf4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -317,9 +317,7 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data)
 int
 qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 {
-	int timeout = 0;
-	int err = 0;
-	u32 done = 0;
+	int timeout = 0, err = 0, done = 0;
 
 	while (!done) {
 		done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)),
@@ -327,10 +325,20 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
 		if (done == 1)
 			break;
 		if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
-			dev_err(&adapter->pdev->dev,
-				"Failed to acquire sem=%d lock; holdby=%d\n",
-				sem,
-				id_reg ? QLCRD32(adapter, id_reg, &err) : -1);
+			if (id_reg) {
+				done = QLCRD32(adapter, id_reg, &err);
+				if (done != -1)
+					dev_err(&adapter->pdev->dev,
+						"Failed to acquire sem=%d lock held by=%d\n",
+						sem, done);
+				else
+					dev_err(&adapter->pdev->dev,
+						"Failed to acquire sem=%d lock",
+						sem);
+			} else {
+				dev_err(&adapter->pdev->dev,
+					"Failed to acquire sem=%d lock", sem);
+			}
 			return -EIO;
 		}
 		msleep(1);
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net 7/7] Update MAINTAINERS for qlcnic driver
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Shahed Shaikh
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

From: Shahed Shaikh <shahed.shaikh@qlogic.com>

Keep myself as only maintainer for qlcnic driver and update
group email alias to Dept-HSGLinuxNICDev@qlogic.com

Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
---
 MAINTAINERS | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index db8bb0d..c970557 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7037,13 +7037,8 @@ F:	Documentation/networking/LICENSE.qla3xxx
 F:	drivers/net/ethernet/qlogic/qla3xxx.*
 
 QLOGIC QLCNIC (1/10)Gb ETHERNET DRIVER
-M:	Himanshu Madhani <himanshu.madhani@qlogic.com>
-M:	Rajesh Borundia <rajesh.borundia@qlogic.com>
 M:	Shahed Shaikh <shahed.shaikh@qlogic.com>
-M:	Jitendra Kalsaria <jitendra.kalsaria@qlogic.com>
-M:	Sony Chacko <sony.chacko@qlogic.com>
-M:	Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
-M:	linux-driver@qlogic.com
+M:	Dept-HSGLinuxNICDev@qlogic.com
 L:	netdev@vger.kernel.org
 S:	Supported
 F:	drivers/net/ethernet/qlogic/qlcnic/
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net 6/7] qlcnic: Update version to 5.3.56
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Shahed Shaikh
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

From: Shahed Shaikh <shahed.shaikh@qlogic.com>

Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 6ad1bce..df9daa3 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -38,8 +38,8 @@
 
 #define _QLCNIC_LINUX_MAJOR 5
 #define _QLCNIC_LINUX_MINOR 3
-#define _QLCNIC_LINUX_SUBVERSION 55
-#define QLCNIC_LINUX_VERSIONID  "5.3.55"
+#define _QLCNIC_LINUX_SUBVERSION 56
+#define QLCNIC_LINUX_VERSIONID  "5.3.56"
 #define QLCNIC_DRV_IDC_VER  0x01
 #define QLCNIC_DRIVER_VERSION  ((_QLCNIC_LINUX_MAJOR << 16) |\
 		 (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
-- 
1.8.1.4

^ permalink raw reply related

* [PATCH net 4/7] qlcnic: Allow vlan0 traffic
From: Shahed Shaikh @ 2014-02-21 13:19 UTC (permalink / raw)
  To: davem; +Cc: netdev, Dept-HSGLinuxNICDev, Rajesh Borundia
In-Reply-To: <1392988795-19380-1-git-send-email-shahed.shaikh@qlogic.com>

From: Rajesh Borundia <rajesh.borundia@qlogic.com>

o Adapter allows vlan0 traffic in case of SR-IOV after setting
  QLC_SRIOV_ALLOW_VLAN0 bit even though we do not add vlan0 filters.

Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
---
 drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
index 09acf15..a28460c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c
@@ -17,6 +17,7 @@
 #define QLC_MAC_STAR_DEL	7
 #define QLC_VF_FLOOD_BIT	BIT_16
 #define QLC_FLOOD_MODE		0x5
+#define QLC_SRIOV_ALLOW_VLAN0	BIT_19
 
 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8);
 
@@ -337,8 +338,11 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter,
 		return err;
 
 	cmd.req.arg[1] = 0x4;
-	if (enable)
+	if (enable) {
 		cmd.req.arg[1] |= BIT_16;
+		if (qlcnic_84xx_check(adapter))
+			cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0;
+	}
 
 	err = qlcnic_issue_cmd(adapter, &cmd);
 	if (err)
-- 
1.8.1.4

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox