* [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
2007-11-14 15:29 [PATCH 0/15] mac80211/iwlwifi (#everything): integrate IEEE802.11n support Ron Rindjunsky
@ 2007-11-14 15:29 ` Ron Rindjunsky
0 siblings, 0 replies; 9+ messages in thread
From: Ron Rindjunsky @ 2007-11-14 15:29 UTC (permalink / raw)
To: linville
Cc: johannes, linux-wireless, flamingice, tomas.winkler,
Ron Rindjunsky
This patch adds the ability to receive and handle A-MSDU frames.
Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
---
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/rx.c | 216 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 217 insertions(+), 0 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 915d7b1..5175054 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/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;
};
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 428a9fc..3c4d13e 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -243,6 +243,10 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
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 */
@@ -1008,6 +1012,217 @@ ieee80211_rx_h_drop_unencrypted(struct ieee80211_txrx_data *rx)
}
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, hdrlen, ethertype;
+ u8 *payload;
+ struct sk_buff *skb = rx->skb, *skb2, *frame = NULL;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ const struct ethhdr *eth;
+ int remaining;
+ u8 dst[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
+ 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;
+
+ hdrlen = ieee80211_get_hdrlen(fc);
+
+ switch (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
+ case IEEE80211_FCTL_TODS:
+ /* BSSID SA DA */
+ if (unlikely(sdata->type != IEEE80211_IF_TYPE_AP &&
+ sdata->type != IEEE80211_IF_TYPE_VLAN)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: dropped ToDS frame (BSSID=%s"
+ " SA=%s DA=%s)\n",
+ dev->name, print_mac(mac, hdr->addr1),
+ print_mac(mac, hdr->addr2),
+ print_mac(mac, hdr->addr3));
+ return TXRX_DROP;
+ }
+ break;
+ case (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS):
+ /* RA TA DA SA */
+ if (unlikely(sdata->type != IEEE80211_IF_TYPE_WDS)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: dropped FromDS&ToDS frame"
+ " (RA=%s TA=%s DA=%s SA=%s)\n",
+ rx->dev->name, print_mac(mac, hdr->addr1),
+ print_mac(mac, hdr->addr2),
+ print_mac(mac, hdr->addr3),
+ print_mac(mac, hdr->addr4));
+ return TXRX_DROP;
+ }
+ break;
+ case IEEE80211_FCTL_FROMDS:
+ /* DA BSSID SA */
+ if (sdata->type != IEEE80211_IF_TYPE_STA)
+ return TXRX_DROP;
+ break;
+ case 0:
+ /* DA SA BSSID */
+ if (sdata->type != IEEE80211_IF_TYPE_IBSS) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: dropped IBSS frame"
+ " (DA=%s SA=%s BSSID=%s)\n",
+ dev->name, print_mac(mac, hdr->addr1),
+ print_mac(mac, hdr->addr2),
+ print_mac(mac, hdr->addr3));
+ return TXRX_DROP;
+ }
+ break;
+ }
+
+ if (unlikely((skb->len - hdrlen) < 8)) {
+ if (net_ratelimit())
+ printk(KERN_DEBUG "%s: RX too short data frame "
+ "payload\n", dev->name);
+ return TXRX_DROP;
+ }
+
+ eth = (struct ethhdr *) skb_pull(skb, hdrlen);
+
+ payload = skb->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))
+ eth = (struct ethhdr *) skb_pull(skb, 8);
+
+ 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;
+ }
+ }
+ skb2 = NULL;
+
+ 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);
+ }
+
+ if (local->bridge_packets &&
+ (sdata->type == IEEE80211_IF_TYPE_AP ||
+ sdata->type == IEEE80211_IF_TYPE_VLAN) &&
+ (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+ if (is_multicast_ether_addr(frame->data)) {
+ /* send multicast frames both to higher layers
+ * in local net stack and back to the wireless
+ * media */
+ skb2 = skb_copy(frame, GFP_ATOMIC);
+ if (!skb2)
+ printk(KERN_DEBUG "%s: failed to clone"
+ " multicast frame\n", dev->name);
+ } else {
+ struct sta_info *dsta;
+
+ dsta = sta_info_get(local, frame->data);
+ if (dsta && !dsta->dev)
+ printk(KERN_DEBUG "Station with null "
+ "dev structure!\n");
+ else if (dsta && dsta->dev == dev) {
+ /* Destination station is associated
+ *to this AP, so send the frame
+ * directly to it and do not pass
+ * the frame to local net stack.
+ */
+ skb2 = frame;
+ frame = NULL;
+ }
+ if (dsta)
+ sta_info_put(dsta);
+ }
+ }
+ if (frame) {
+ /* deliver to local stack */
+ skb_set_network_header(frame, 0);
+ frame->protocol = eth_type_trans(frame, dev);
+ frame->priority = skb->priority;
+ netif_rx(frame);
+ }
+
+ if (skb2) {
+ /* send to wireless media */
+ skb2->protocol = __constant_htons(ETH_P_802_3);
+ skb_set_network_header(skb2, 0);
+ skb_set_mac_header(skb2, 0);
+ skb2->priority = skb->priority;
+ skb2->dev = dev;
+ dev_queue_xmit(skb2);
+ }
+ }
+
+ return TXRX_QUEUED;
+}
+
+static ieee80211_txrx_result
ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
{
struct net_device *dev = rx->dev;
@@ -1343,6 +1558,7 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
ieee80211_rx_h_remove_qos_control,
ieee80211_rx_h_802_1x_pae,
ieee80211_rx_h_drop_unencrypted,
+ ieee80211_rx_h_amsdu,
ieee80211_rx_h_data,
ieee80211_rx_h_mgmt,
NULL
--
1.5.3.3
---------------------------------------------------------------------
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.
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
@ 2007-11-21 8:47 Ron Rindjunsky
0 siblings, 0 replies; 9+ messages in thread
From: Ron Rindjunsky @ 2007-11-21 8:47 UTC (permalink / raw)
To: linville
Cc: johannes, linux-wireless, flamingice, tomas.winkler,
Ron Rindjunsky
This patch adds the ability to receive and handle A-MSDU frames.
Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
---
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 */
@@ -1134,6 +1138,165 @@ ieee80211_data_to_8023(struct ieee80211_
}
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, *skb2, *frame = NULL;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ 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;
+
+ /* 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;
+ }
+ }
+ skb2 = NULL;
+
+ 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);
+ }
+
+ rx->skb = frame;
+ if ((ieee80211_drop_802_1x_pae(rx, sizeof(struct ethhdr))) ||
+ (ieee80211_drop_unencrypted(rx, sizeof(struct ethhdr)))) {
+ if (skb == frame) /* last frame */
+ return TXRX_DROP;
+ dev_kfree_skb(frame);
+ continue;
+ }
+
+ if (local->bridge_packets &&
+ (sdata->type == IEEE80211_IF_TYPE_AP ||
+ sdata->type == IEEE80211_IF_TYPE_VLAN) &&
+ (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) {
+ if (is_multicast_ether_addr(frame->data)) {
+ /* send multicast frames both to higher layers
+ * in local net stack and back to the wireless
+ * media */
+ skb2 = skb_copy(frame, GFP_ATOMIC);
+ if (!skb2)
+ printk(KERN_DEBUG "%s: failed to clone"
+ " multicast frame\n", dev->name);
+ } else {
+ struct sta_info *dsta;
+
+ dsta = sta_info_get(local, frame->data);
+ if (dsta && !dsta->dev)
+ printk(KERN_DEBUG "Station with null "
+ "dev structure!\n");
+ else if (dsta && dsta->dev == dev) {
+ /* Destination station is associated
+ *to this AP, so send the frame
+ * directly to it and do not pass
+ * the frame to local net stack.
+ */
+ skb2 = frame;
+ frame = NULL;
+ }
+ if (dsta)
+ sta_info_put(dsta);
+ }
+ }
+ if (frame) {
+ /* deliver to local stack */
+ skb_set_network_header(frame, 0);
+ frame->protocol = eth_type_trans(frame, dev);
+ frame->priority = skb->priority;
+ netif_rx(frame);
+ }
+
+ if (skb2) {
+ /* send to wireless media */
+ skb2->protocol = __constant_htons(ETH_P_802_3);
+ skb_set_network_header(skb2, 0);
+ skb_set_mac_header(skb2, 0);
+ skb2->priority = skb->priority;
+ skb2->dev = dev;
+ dev_queue_xmit(skb2);
+ }
+ }
+
+ return TXRX_QUEUED;
+}
+
+static ieee80211_txrx_result
ieee80211_rx_h_data(struct ieee80211_txrx_data *rx)
{
struct net_device *dev = rx->dev;
@@ -1359,6 +1522,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.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
@ 2007-11-22 17:49 Ron Rindjunsky
2007-11-24 21:44 ` Johannes Berg
0 siblings, 1 reply; 9+ messages in thread
From: Ron Rindjunsky @ 2007-11-22 17:49 UTC (permalink / raw)
To: linville
Cc: johannes, linux-wireless, flamingice, tomas.winkler,
Ron Rindjunsky
This patch adds the ability to receive and handle A-MSDU frames.
Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
---
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.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
2007-11-22 17:49 [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability Ron Rindjunsky
@ 2007-11-24 21:44 ` Johannes Berg
0 siblings, 0 replies; 9+ messages in thread
From: Johannes Berg @ 2007-11-24 21:44 UTC (permalink / raw)
To: Ron Rindjunsky; +Cc: linville, linux-wireless, flamingice, tomas.winkler
[-- Attachment #1: Type: text/plain, Size: 413 bytes --]
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 <ron.rindjunsky@intel.com>
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
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
2007-11-26 14:14 [PATCH 0/15] mac80211/iwlwifi (#everything): integrate IEEE802.11n support Ron Rindjunsky
@ 2007-11-26 14:14 ` Ron Rindjunsky
2007-11-26 16:35 ` Johannes Berg
2007-11-26 18:40 ` Michael Wu
0 siblings, 2 replies; 9+ messages in thread
From: Ron Rindjunsky @ 2007-11-26 14:14 UTC (permalink / raw)
To: linville
Cc: johannes, linux-wireless, flamingice, tomas.winkler,
Ron Rindjunsky
This patch adds the ability to receive and handle A-MSDU frames.
Signed-off-by: Ron Rindjunsky <ron.rindjunsky@intel.com>
---
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/rx.c | 124 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 125 insertions(+), 0 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9caf124..247af42 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/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;
};
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6333c98..878ca20 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -243,6 +243,10 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx)
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_txrx_data *rx)
}
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;
@@ -1373,6 +1496,7 @@ ieee80211_rx_handler ieee80211_rx_handlers[] =
* 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
--
1.5.3.3
---------------------------------------------------------------------
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.
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
2007-11-26 14:14 ` [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability Ron Rindjunsky
@ 2007-11-26 16:35 ` Johannes Berg
2007-11-26 17:25 ` Tomas Winkler
2007-11-26 18:40 ` Michael Wu
1 sibling, 1 reply; 9+ messages in thread
From: Johannes Berg @ 2007-11-26 16:35 UTC (permalink / raw)
To: Ron Rindjunsky; +Cc: linville, linux-wireless, flamingice, tomas.winkler
[-- Attachment #1: Type: text/plain, Size: 1388 bytes --]
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 <ron.rindjunsky@intel.com>
Acked-by: Johannes Berg <johannes@sipsolutions.net>
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
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
2007-11-26 16:35 ` Johannes Berg
@ 2007-11-26 17:25 ` Tomas Winkler
0 siblings, 0 replies; 9+ messages in thread
From: Tomas Winkler @ 2007-11-26 17:25 UTC (permalink / raw)
To: Johannes Berg; +Cc: Ron Rindjunsky, linville, linux-wireless, flamingice
On Nov 26, 2007 6:35 PM, Johannes Berg <johannes@sipsolutions.net> 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 <ron.rindjunsky@intel.com>
>
> Acked-by: Johannes Berg <johannes@sipsolutions.net>
>
> 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
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
2007-11-26 14:14 ` [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability Ron Rindjunsky
2007-11-26 16:35 ` Johannes Berg
@ 2007-11-26 18:40 ` Michael Wu
2007-11-27 9:48 ` Ron Rindjunsky
1 sibling, 1 reply; 9+ messages in thread
From: Michael Wu @ 2007-11-26 18:40 UTC (permalink / raw)
To: Ron Rindjunsky; +Cc: linville, johannes, linux-wireless, tomas.winkler
[-- Attachment #1: Type: text/plain, Size: 404 bytes --]
On Monday 26 November 2007 09:14:33 Ron Rindjunsky wrote:
> diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> index 9caf124..247af42 100644
> --- a/net/mac80211/ieee80211_i.h
> +++ b/net/mac80211/ieee80211_i.h
> @@ -155,6 +155,7 @@ struct ieee80211_txrx_data {
> int load;
> u32 tkip_iv32;
> u16 tkip_iv16;
> + u8 amsdu_frame;
A flag would be preferable.
-Michael Wu
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 194 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability
2007-11-26 18:40 ` Michael Wu
@ 2007-11-27 9:48 ` Ron Rindjunsky
0 siblings, 0 replies; 9+ messages in thread
From: Ron Rindjunsky @ 2007-11-27 9:48 UTC (permalink / raw)
To: Michael Wu; +Cc: linville, johannes, linux-wireless, tomas.winkler
> > diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
> > index 9caf124..247af42 100644
> > --- a/net/mac80211/ieee80211_i.h
> > +++ b/net/mac80211/ieee80211_i.h
> > @@ -155,6 +155,7 @@ struct ieee80211_txrx_data {
> > int load;
> > u32 tkip_iv32;
> > u16 tkip_iv16;
> > + u8 amsdu_frame;
> A flag would be preferable.
>
I agree, will be more efficient.
If no one has a solid objection for altering the variable to a flag I
will issue a patch on top of this patch that will do it.
> -Michael Wu
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2007-11-27 9:48 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-11-22 17:49 [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability Ron Rindjunsky
2007-11-24 21:44 ` Johannes Berg
-- strict thread matches above, loose matches on Subject: below --
2007-11-26 14:14 [PATCH 0/15] mac80211/iwlwifi (#everything): integrate IEEE802.11n support Ron Rindjunsky
2007-11-26 14:14 ` [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability Ron Rindjunsky
2007-11-26 16:35 ` Johannes Berg
2007-11-26 17:25 ` Tomas Winkler
2007-11-26 18:40 ` Michael Wu
2007-11-27 9:48 ` Ron Rindjunsky
2007-11-21 8:47 Ron Rindjunsky
2007-11-14 15:29 [PATCH 0/15] mac80211/iwlwifi (#everything): integrate IEEE802.11n support Ron Rindjunsky
2007-11-14 15:29 ` [PATCH 06/15] mac80211: adding 802.11n essential A-MSDU Rx capability Ron Rindjunsky
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox