2007-11-22 17:49:56

by Ron Rindjunsky

[permalink] [raw]
Subject: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability

This patch adds the ability to receive and handle A-MSDU frames.

Signed-off-by: Ron Rindjunsky <[email protected]>
---
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/rx.c | 216 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 217 insertions(+), 0 deletions(-)

Index: wl2_6_24_HT/net/mac80211/ieee80211_i.h
===================================================================
--- wl2_6_24_HT.orig/net/mac80211/ieee80211_i.h
+++ wl2_6_24_HT/net/mac80211/ieee80211_i.h
@@ -155,6 +155,7 @@ struct ieee80211_txrx_data {
int load;
u32 tkip_iv32;
u16 tkip_iv16;
+ u8 amsdu_frame;
} rx;
} u;
};
Index: wl2_6_24_HT/net/mac80211/rx.c
===================================================================
--- wl2_6_24_HT.orig/net/mac80211/rx.c
+++ wl2_6_24_HT/net/mac80211/rx.c
@@ -243,6 +243,10 @@ ieee80211_rx_h_parse_qos(struct ieee8021
u8 *qc = data + ieee80211_get_hdrlen(rx->fc) - QOS_CONTROL_LEN;
/* frame has qos control */
tid = qc[0] & QOS_CONTROL_TID_MASK;
+ if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
+ rx->u.rx.amsdu_frame = 1;
+ else
+ rx->u.rx.amsdu_frame = 0;
} else {
if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) {
/* Separate TID for management frames */
@@ -1191,6 +1195,125 @@ ieee80211_deliver_skb(struct ieee80211_t
}

static ieee80211_txrx_result
+ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx)
+{
+ struct net_device *dev = rx->dev;
+ struct ieee80211_local *local = rx->local;
+ u16 fc, ethertype;
+ u8 *payload;
+ struct sk_buff *skb = rx->skb, *frame = NULL;
+ const struct ethhdr *eth;
+ int remaining, err;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ DECLARE_MAC_BUF(mac);
+
+ fc = rx->fc;
+ if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA))
+ return TXRX_CONTINUE;
+
+ if (unlikely(!WLAN_FC_DATA_PRESENT(fc)))
+ return TXRX_DROP;
+
+ if (!rx->u.rx.amsdu_frame)
+ return TXRX_CONTINUE;
+
+ err = ieee80211_data_to_8023(rx);
+ if (unlikely(err))
+ return TXRX_DROP;
+
+ 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)
+ return TXRX_DROP;
+
+ 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) {
+ printk(KERN_DEBUG "%s: wrong buffer size", dev->name);
+ return TXRX_DROP;
+ }
+
+ skb_pull(skb, sizeof(struct ethhdr));
+ /* if last subframe reuse skb */
+ if (remaining <= subframe_len + padding)
+ frame = skb;
+ else {
+ frame = dev_alloc_skb(local->hw.extra_tx_headroom +
+ subframe_len);
+
+ if (frame == NULL)
+ return TXRX_DROP;
+
+ skb_reserve(frame, local->hw.extra_tx_headroom +
+ sizeof(struct ethhdr));
+ memcpy(skb_put(frame, ntohs(len)), skb->data,
+ ntohs(len));
+
+ eth = (struct ethhdr *) skb_pull(skb, ntohs(len) +
+ padding);
+ if (!eth) {
+ printk(KERN_DEBUG "%s: wrong buffer size ",
+ dev->name);
+ dev_kfree_skb(frame);
+ return TXRX_DROP;
+ }
+ }
+
+ skb_set_network_header(frame, 0);
+ frame->dev = dev;
+ frame->priority = skb->priority;
+ rx->skb = frame;
+
+ if ((ieee80211_drop_802_1x_pae(rx, 0)) ||
+ (ieee80211_drop_unencrypted(rx, 0))) {
+ if (skb == frame) /* last frame */
+ return TXRX_DROP;
+ dev_kfree_skb(frame);
+ continue;
+ }
+
+ 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);
+ }
+
+
+ ieee80211_deliver_skb(rx);
+ }
+
+ return TXRX_QUEUED;
+}
+
+static ieee80211_txrx_result
ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
{
struct net_device *dev = rx->dev;
@@ -1368,6 +1491,7 @@ ieee80211_rx_handler ieee80211_rx_handle
* are not passed to user space by these functions
*/
ieee80211_rx_h_remove_qos_control,
+ ieee80211_rx_h_amsdu,
ieee80211_rx_h_data,
ieee80211_rx_h_mgmt,
NULL
---------------------------------------------------------------------
Intel Israel (74) Limited

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.


2007-11-26 16:35:25

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability


On Mon, 2007-11-26 at 16:14 +0200, Ron Rindjunsky wrote:
> This patch adds the ability to receive and handle A-MSDU frames.
>
> Signed-off-by: Ron Rindjunsky <[email protected]>

Acked-by: Johannes Berg <[email protected]>

Thanks for your patience on this. I have another question that is
identical in the other code and that we should, if necessary, fix in a
separate patch to fix both instances of this:


> + payload = frame->data;
> + ethertype = (payload[6] << 8) | payload[7];
> +
> + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
[...]
> + } 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);

Here, as well as in the regular data frame handler, we push the length
of the frame into the ethernet header. Later then, eth_type_trans() will
load up the skb->protocol field. The thing I'm not entirely sure about
is this: We can have frames longer than 1536 bytes, but only if the
length is smaller than 1536 does eth_type_trans() assume that it's a
length, if we have a frame longer won't it go wrong? I haven't quite
managed to wrap my head around the rules for wrapping data into an
802.11 frame nor in an 802.3 setting so this may be totally incorrect.

johannes


Attachments:
signature.asc (828.00 B)
This is a digitally signed message part

2007-11-26 17:25:28

by Tomas Winkler

[permalink] [raw]
Subject: Re: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability

On Nov 26, 2007 6:35 PM, Johannes Berg <[email protected]> wrote:
>
> On Mon, 2007-11-26 at 16:14 +0200, Ron Rindjunsky wrote:
> > This patch adds the ability to receive and handle A-MSDU frames.
> >
> > Signed-off-by: Ron Rindjunsky <[email protected]>
>
> Acked-by: Johannes Berg <[email protected]>
>
> Thanks for your patience on this. I have another question that is
> identical in the other code and that we should, if necessary, fix in a
> separate patch to fix both instances of this:
>
>
> > + payload = frame->data;
> > + ethertype = (payload[6] << 8) | payload[7];
> > +
> > + if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
> [...]
> > + } 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);
>
> Here, as well as in the regular data frame handler, we push the length
> of the frame into the ethernet header. Later then, eth_type_trans() will
> load up the skb->protocol field. The thing I'm not entirely sure about
> is this: We can have frames longer than 1536 bytes, but only if the
> length is smaller than 1536 does eth_type_trans() assume that it's a
> length, if we have a frame longer won't it go wrong? I haven't quite
> managed to wrap my head around the rules for wrapping data into an
> 802.11 frame nor in an 802.3 setting so this may be totally incorrect.
>
Just grabbed this from wikipedia
'
values of that field between 0 and 1500 indicated the use of the
original 802.3 Ethernet format with a length field, while values of
1536 decimal (0600 hexadecimal) and greater indicated the use of the
DIX frame format with an EtherType sub-protocol identifier
'
> johannes
>

2007-11-24 21:44:33

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability


On Thu, 2007-11-22 at 19:49 +0200, Ron Rindjunsky wrote:
> This patch adds the ability to receive and handle A-MSDU frames.
>
> Signed-off-by: Ron Rindjunsky <[email protected]>

Looks good.

I think I'll send acked-by's for the whole series if you repost. If John
thinks he's got it covered then I'll take another look over the whole
series and send them then.

[patch snipped]

johannes


Attachments:
signature.asc (828.00 B)
This is a digitally signed message part