All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/2] wireless: add ieee80211_amsdu_to_8023s
@ 2009-11-27  3:18 Zhu Yi
  2009-11-27  3:18 ` [PATCH v2 2/2] iwmc3200wifi: rx aggregation support Zhu Yi
  0 siblings, 1 reply; 5+ messages in thread
From: Zhu Yi @ 2009-11-27  3:18 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi, Johannes Berg

Move the A-MSDU handling code from mac80211 to cfg80211 so that more
drivers can use it. The new created function ieee80211_amsdu_to_8023s
converts an A-MSDU frame to a list of 802.3 frames.

Cc: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
V2: use __ version of sk_buff_head operations and mark addr const

 include/net/cfg80211.h |   21 ++++++++-
 net/mac80211/rx.c      |  107 ++++++++++-------------------------------------
 net/wireless/util.c    |   96 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 136 insertions(+), 88 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 0884b9a..f1353d1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1578,7 +1578,7 @@ unsigned int ieee80211_hdrlen(__le16 fc);
  * @addr: the device MAC address
  * @iftype: the virtual interface type
  */
-int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
 			   enum nl80211_iftype iftype);
 
 /**
@@ -1589,10 +1589,27 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
  * @bssid: the network bssid (used only for iftype STATION and ADHOC)
  * @qos: build 802.11 QoS data frame
  */
-int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
 			     enum nl80211_iftype iftype, u8 *bssid, bool qos);
 
 /**
+ * ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
+ *
+ * Decode an IEEE 802.11n A-MSDU frame and convert it to a list of
+ * 802.3 frames. This function returns 0 on succeess. In this case,
+ * we optimize the code to reuse the @skb to hold the last 802.3
+ * frame in the @list.
+ *
+ * @skb: The input IEEE 802.11n A-MSDU frame.
+ * @list: The output list of 802.3 frames. It must be allocated and
+ *	initialized by by the caller.
+ * @addr: The device MAC address.
+ * @iftype: The device interface type.
+ */
+int ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+                             const u8 *addr, enum nl80211_iftype iftype);
+
+/**
  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
  * @skb: the data frame
  */
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 57b8a0a..539c790 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1556,16 +1556,11 @@ static ieee80211_rx_result debug_noinline
 ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 {
 	struct net_device *dev = rx->sdata->dev;
-	struct ieee80211_local *local = rx->local;
-	u16 ethertype;
-	u8 *payload;
-	struct sk_buff *skb = rx->skb, *frame = NULL;
+	struct sk_buff *skb = rx->skb;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
 	__le16 fc = hdr->frame_control;
-	const struct ethhdr *eth;
-	int remaining, err;
-	u8 dst[ETH_ALEN];
-	u8 src[ETH_ALEN];
+	int err;
+	struct sk_buff_head frame_list;
 
 	if (unlikely(!ieee80211_is_data(fc)))
 		return RX_CONTINUE;
@@ -1576,92 +1571,36 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
 	if (!(rx->flags & IEEE80211_RX_AMSDU))
 		return RX_CONTINUE;
 
-	err = __ieee80211_data_to_8023(rx);
-	if (unlikely(err))
+	if (ieee80211_has_a4(hdr->frame_control) &&
+	    rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+	    !rx->sdata->u.vlan.sta)
 		return RX_DROP_UNUSABLE;
 
-	skb->dev = dev;
-
-	dev->stats.rx_packets++;
-	dev->stats.rx_bytes += skb->len;
-
-	/* skip the wrapping header */
-	eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
-	if (!eth)
+	if (is_multicast_ether_addr(hdr->addr1) &&
+	    ((rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
+	      rx->sdata->u.vlan.sta) ||
+	     (rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
+	      rx->sdata->u.mgd.use_4addr)))
 		return RX_DROP_UNUSABLE;
 
-	while (skb != frame) {
-		u8 padding;
-		__be16 len = eth->h_proto;
-		unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
-
-		remaining = skb->len;
-		memcpy(dst, eth->h_dest, ETH_ALEN);
-		memcpy(src, eth->h_source, ETH_ALEN);
-
-		padding = ((4 - subframe_len) & 0x3);
-		/* the last MSDU has no padding */
-		if (subframe_len > remaining)
-			return RX_DROP_UNUSABLE;
-
-		skb_pull(skb, sizeof(struct ethhdr));
-		/* if last subframe reuse skb */
-		if (remaining <= subframe_len + padding)
-			frame = skb;
-		else {
-			/*
-			 * Allocate and reserve two bytes more for payload
-			 * alignment since sizeof(struct ethhdr) is 14.
-			 */
-			frame = dev_alloc_skb(
-				ALIGN(local->hw.extra_tx_headroom, 4) +
-				subframe_len + 2);
-
-			if (frame == NULL)
-				return RX_DROP_UNUSABLE;
+	skb->dev = dev;
+	__skb_queue_head_init(&frame_list);
 
-			skb_reserve(frame,
-				    ALIGN(local->hw.extra_tx_headroom, 4) +
-				    sizeof(struct ethhdr) + 2);
-			memcpy(skb_put(frame, ntohs(len)), skb->data,
-				ntohs(len));
+	err = ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
+				       rx->sdata->vif.type);
+	if (err)
+		return RX_DROP_UNUSABLE;
 
-			eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
-							padding);
-			if (!eth) {
-				dev_kfree_skb(frame);
-				return RX_DROP_UNUSABLE;
-			}
-		}
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += skb->len;
 
-		skb_reset_network_header(frame);
-		frame->dev = dev;
-		frame->priority = skb->priority;
-		rx->skb = frame;
-
-		payload = frame->data;
-		ethertype = (payload[6] << 8) | payload[7];
-
-		if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
-			    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
-			   compare_ether_addr(payload,
-					      bridge_tunnel_header) == 0)) {
-			/* remove RFC1042 or Bridge-Tunnel
-			 * encapsulation and replace EtherType */
-			skb_pull(frame, 6);
-			memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-		} else {
-			memcpy(skb_push(frame, sizeof(__be16)),
-			       &len, sizeof(__be16));
-			memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
-			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
-		}
+	while (!skb_queue_empty(&frame_list)) {
+		rx->skb = __skb_dequeue(&frame_list);
 
 		if (!ieee80211_frame_allowed(rx, fc)) {
-			if (skb == frame) /* last frame */
+			if (skb == rx->skb) /* last frame */
 				return RX_DROP_UNUSABLE;
-			dev_kfree_skb(frame);
+			dev_kfree_skb(rx->skb);
 			continue;
 		}
 
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 59361fd..63a3d72 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -285,7 +285,7 @@ static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
 	}
 }
 
-int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
 			   enum nl80211_iftype iftype)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -383,7 +383,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
 }
 EXPORT_SYMBOL(ieee80211_data_to_8023);
 
-int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
+int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
 			     enum nl80211_iftype iftype, u8 *bssid, bool qos)
 {
 	struct ieee80211_hdr hdr;
@@ -497,6 +497,98 @@ int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
 }
 EXPORT_SYMBOL(ieee80211_data_from_8023);
 
+
+int ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
+			     const u8 *addr, enum nl80211_iftype iftype)
+{
+	struct sk_buff *frame = NULL;
+	u16 ethertype;
+	u8 *payload;
+	const struct ethhdr *eth;
+	int remaining, err;
+	u8 dst[ETH_ALEN], src[ETH_ALEN];
+
+	err = ieee80211_data_to_8023(skb, addr, iftype);
+	if (err)
+		return err;
+
+	/* skip the wrapping header */
+	eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
+	if (!eth)
+		return -1;
+
+	while (skb != frame) {
+		u8 padding;
+		__be16 len = eth->h_proto;
+		unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
+
+		remaining = skb->len;
+		memcpy(dst, eth->h_dest, ETH_ALEN);
+		memcpy(src, eth->h_source, ETH_ALEN);
+
+		padding = (4 - subframe_len) & 0x3;
+		/* the last MSDU has no padding */
+		if (subframe_len > remaining)
+			goto purge;
+
+		skb_pull(skb, sizeof(struct ethhdr));
+		/* reuse skb for the last subframe */
+		if (remaining <= subframe_len + padding)
+			frame = skb;
+		else {
+			/*
+			 * Allocate and reserve two bytes more for payload
+			 * alignment since sizeof(struct ethhdr) is 14.
+			 */
+			frame = dev_alloc_skb(subframe_len + 2);
+			if (!frame)
+				goto purge;
+
+			skb_reserve(frame, sizeof(struct ethhdr) + 2);
+			memcpy(skb_put(frame, ntohs(len)), skb->data,
+				ntohs(len));
+
+			eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
+							padding);
+			if (!eth) {
+				dev_kfree_skb(frame);
+				goto purge;
+			}
+		}
+
+		skb_reset_network_header(frame);
+		frame->dev = skb->dev;
+		frame->priority = skb->priority;
+
+		payload = frame->data;
+		ethertype = (payload[6] << 8) | payload[7];
+
+		if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+			    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
+			   compare_ether_addr(payload,
+					      bridge_tunnel_header) == 0)) {
+			/* remove RFC1042 or Bridge-Tunnel
+			 * encapsulation and replace EtherType */
+			skb_pull(frame, 6);
+			memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+		} else {
+			memcpy(skb_push(frame, sizeof(__be16)), &len,
+				sizeof(__be16));
+			memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
+			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
+		}
+		__skb_queue_tail(list, frame);
+	}
+
+	return 0;
+
+ purge:
+	__skb_queue_purge(list);
+	return -1;
+}
+EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
+
 /* Given a data frame determine the 802.1p/1d tag to use. */
 unsigned int cfg80211_classify8021d(struct sk_buff *skb)
 {
-- 
1.6.0.4


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

* [PATCH v2 2/2] iwmc3200wifi: rx aggregation support
  2009-11-27  3:18 [PATCH v2 1/2] wireless: add ieee80211_amsdu_to_8023s Zhu Yi
@ 2009-11-27  3:18 ` Zhu Yi
  2009-11-27  9:40   ` Johannes Berg
  0 siblings, 1 reply; 5+ messages in thread
From: Zhu Yi @ 2009-11-27  3:18 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Zhu Yi, Johannes Berg

When the device receives an A-MSDU frame (indicated by flag
IWM_RX_TICKET_AMSDU_MSK), use ieee80211_amsdu_to_8023s to convert
it to a list of 802.3 frames and handled them to upper layer.

Cc: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
---
V2: use __ version of sk_buff_head operations

 drivers/net/wireless/iwmc3200wifi/rx.c |   55 +++++++++++++++++++++++++++-----
 1 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 72c27a3..29e3d1d 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -1534,6 +1534,34 @@ static void classify8023(struct sk_buff *skb)
 	}
 }
 
+static int iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
+{
+	struct wireless_dev *wdev = iwm_to_wdev(iwm);
+	struct net_device *ndev = iwm_to_ndev(iwm);
+	struct sk_buff_head list;
+	struct sk_buff *frame;
+	int ret;
+
+	IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
+
+	__skb_queue_head_init(&list);
+	ret = ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr,
+				       wdev->iftype);
+	if (ret) {
+		IWM_ERR(iwm, "decode A-MSDU frame failed\n");
+		return -EINVAL;
+	}
+
+	while ((frame = __skb_dequeue(&list))) {
+		if (netif_rx_ni(frame) == NET_RX_DROP) {
+			IWM_ERR(iwm, "Packet dropped\n");
+			ndev->stats.rx_dropped++;
+		}
+	}
+
+	return 0;
+}
+
 static void iwm_rx_process_packet(struct iwm_priv *iwm,
 				  struct iwm_rx_packet *packet,
 				  struct iwm_rx_ticket_node *ticket_node)
@@ -1548,25 +1576,36 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
 	switch (le16_to_cpu(ticket_node->ticket->action)) {
 	case IWM_RX_TICKET_RELEASE:
 		IWM_DBG_RX(iwm, DBG, "RELEASE packet\n");
+
+		skb->dev = iwm_to_ndev(iwm);
+		skb->protocol = eth_type_trans(skb, ndev);
+		skb->ip_summed = CHECKSUM_NONE;
+		memset(skb->cb, 0, sizeof(skb->cb));
+
+		ndev->stats.rx_packets++;
+		ndev->stats.rx_bytes += skb->len;
+
 		classify8023(skb);
 		iwm_rx_adjust_packet(iwm, packet, ticket_node);
+
+		if (le16_to_cpu(ticket_node->ticket->flags) &
+		    IWM_RX_TICKET_AMSDU_MSK) {			
+			ret = iwm_rx_process_amsdu(iwm, skb);
+			if (ret < 0)
+				kfree_skb(packet->skb);
+			break;
+		}
+
 		ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype);
 		if (ret < 0) {
 			IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - "
 				   "%d\n", ret);
+			kfree_skb(packet->skb);
 			break;
 		}
 
 		IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len);
 
-		skb->dev = iwm_to_ndev(iwm);
-		skb->protocol = eth_type_trans(skb, ndev);
-		skb->ip_summed = CHECKSUM_NONE;
-		memset(skb->cb, 0, sizeof(skb->cb));
-
-		ndev->stats.rx_packets++;
-		ndev->stats.rx_bytes += skb->len;
-
 		if (netif_rx_ni(skb) == NET_RX_DROP) {
 			IWM_ERR(iwm, "Packet dropped\n");
 			ndev->stats.rx_dropped++;
-- 
1.6.0.4


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

* Re: [PATCH v2 2/2] iwmc3200wifi: rx aggregation support
  2009-11-27  3:18 ` [PATCH v2 2/2] iwmc3200wifi: rx aggregation support Zhu Yi
@ 2009-11-27  9:40   ` Johannes Berg
  2009-11-30  1:11     ` Zhu Yi
  0 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2009-11-27  9:40 UTC (permalink / raw)
  To: Zhu Yi; +Cc: linville, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 584 bytes --]

On Fri, 2009-11-27 at 11:18 +0800, Zhu Yi wrote:

> +	__skb_queue_head_init(&list);
> +	ret = ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr,
> +				       wdev->iftype);
> +	if (ret) {
> +		IWM_ERR(iwm, "decode A-MSDU frame failed\n");
> +		return -EINVAL;
> +	}

You did the right thing in mac80211, but not here -- if it returns an
error it hasn't freed 'skb', only modified it.

I think that we should have ieee80211_amsdu_to_8023s() consume it in all
cases, just not fill the list (and return an error I guess) when it
can't be decoded properly.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [PATCH v2 2/2] iwmc3200wifi: rx aggregation support
  2009-11-27  9:40   ` Johannes Berg
@ 2009-11-30  1:11     ` Zhu Yi
  2009-11-30  3:56       ` Zhu Yi
  0 siblings, 1 reply; 5+ messages in thread
From: Zhu Yi @ 2009-11-30  1:11 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless

On Fri, 2009-11-27 at 17:40 +0800, Johannes Berg wrote:
> You did the right thing in mac80211, but not here -- if it returns an
> error it hasn't freed 'skb', only modified it.

Indeed.

> I think that we should have ieee80211_amsdu_to_8023s() consume it in
> all cases, just not fill the list (and return an error I guess) when
> it can't be decoded properly. 

Yeah, since I didn't even use it correctly myself, I couldn't expect
others do. Besides, the nontransparent reuse of skb for the last item in
the list (skb == rx->skb) looks dirty. I'll use RX_QUEUED in v3.

Thanks,
-yi


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

* Re: [PATCH v2 2/2] iwmc3200wifi: rx aggregation support
  2009-11-30  1:11     ` Zhu Yi
@ 2009-11-30  3:56       ` Zhu Yi
  0 siblings, 0 replies; 5+ messages in thread
From: Zhu Yi @ 2009-11-30  3:56 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linville, linux-wireless

On Mon, 2009-11-30 at 09:11 +0800, Zhu Yi wrote:
> > You did the right thing in mac80211, but not here -- if it returns
> an error it hasn't freed 'skb', only modified it.
> 
> Indeed. 

Speak too soon. I freed it in the calling function. But I'll still use
your suggestion to consume the skb here, for the reason I mentioned
early.

Thanks,
-yi


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

end of thread, other threads:[~2009-11-30  3:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-27  3:18 [PATCH v2 1/2] wireless: add ieee80211_amsdu_to_8023s Zhu Yi
2009-11-27  3:18 ` [PATCH v2 2/2] iwmc3200wifi: rx aggregation support Zhu Yi
2009-11-27  9:40   ` Johannes Berg
2009-11-30  1:11     ` Zhu Yi
2009-11-30  3:56       ` Zhu Yi

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.