mwifiex: support RX AMSDU aggregation for uAP
authorAvinash Patil <patila@marvell.com>
Sat, 4 Aug 2012 01:06:09 +0000 (18:06 -0700)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 6 Aug 2012 19:12:55 +0000 (15:12 -0400)
This patch adds support for reception and decoding of AMSDU
aggregation frames for AP interface.
Patch also adds support for handling AMSDU aggregation event.

Signed-off-by: Avinash Patil <patila@marvell.com>
Signed-off-by: Kiran Divekar <dkiran@marvell.com>
Signed-off-by: Bing Zhao <bzhao@marvell.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/11n_rxreorder.h
drivers/net/wireless/mwifiex/uap_event.c
drivers/net/wireless/mwifiex/uap_txrx.c

index 591ccd33f83c5482340c6667cf76660e24ac00d7..20367fe1de4499e0eadf9de6f91119bd11032ef9 100644 (file)
@@ -54,8 +54,13 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
                        tbl->rx_reorder_ptr[i] = NULL;
                }
                spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-               if (rx_tmp_ptr)
-                       mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+               if (rx_tmp_ptr) {
+                       if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+                               mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
+                       else
+                               mwifiex_process_rx_packet(priv->adapter,
+                                                         rx_tmp_ptr);
+               }
        }
 
        spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -97,7 +102,11 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
                rx_tmp_ptr = tbl->rx_reorder_ptr[i];
                tbl->rx_reorder_ptr[i] = NULL;
                spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-               mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+
+               if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+                       mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
+               else
+                       mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
        }
 
        spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -148,7 +157,7 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
  * This function returns the pointer to an entry in Rx reordering
  * table which matches the given TA/TID pair.
  */
-static struct mwifiex_rx_reorder_tbl *
+struct mwifiex_rx_reorder_tbl *
 mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
 {
        struct mwifiex_rx_reorder_tbl *tbl;
@@ -396,8 +405,13 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
 
        tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
        if (!tbl) {
-               if (pkt_type != PKT_TYPE_BAR)
-                       mwifiex_process_rx_packet(priv->adapter, payload);
+               if (pkt_type != PKT_TYPE_BAR) {
+                       if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+                               mwifiex_handle_uap_rx_forward(priv, payload);
+                       else
+                               mwifiex_process_rx_packet(priv->adapter,
+                                                         payload);
+               }
                return 0;
        }
        start_win = tbl->start_win;
index 6c9815a0f5d8b0d7aebcb5d6a9953a24819ad45a..1cd51d86fa57c4a913b19eb0d7cb2ca7b45304ab 100644 (file)
@@ -68,5 +68,7 @@ struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
                                                           mwifiex_private
                                                           *priv, int tid,
                                                           u8 *ta);
+struct mwifiex_rx_reorder_tbl *
+mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta);
 
 #endif /* _MWIFIEX_11N_RXREORDER_H_ */
index 37cc642a1b8373f5591290663ee153be7660247d..6270c809130a581a898b17e60bd1761f24180987 100644 (file)
@@ -242,6 +242,19 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
                /* For future development */
                dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
                break;
+       case EVENT_AMSDU_AGGR_CTRL:
+               dev_dbg(adapter->dev, "event:  AMSDU_AGGR_CTRL %d\n",
+                       *(u16 *)adapter->event_body);
+
+               if (priv->media_connected) {
+                       adapter->tx_buf_size =
+                              min(adapter->curr_tx_buf_size,
+                                  le16_to_cpu(*(__le16 *)adapter->event_body));
+
+                       dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
+                               adapter->tx_buf_size);
+               }
+               break;
        default:
                dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
                        eventcause);
index f55c5ac3e5e0100baa3a8ae1e5ed429beefb236b..6d814f0f07f2b4b7d3229e74fc3c3832840c52e9 100644 (file)
@@ -21,6 +21,8 @@
 #include "ioctl.h"
 #include "main.h"
 #include "wmm.h"
+#include "11n_aggr.h"
+#include "11n_rxreorder.h"
 
 static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
                                         struct sk_buff *skb)
@@ -165,6 +167,9 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
        struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
        struct rx_packet_hdr *rx_pkt_hdr;
        u16 rx_pkt_type;
+       u8 ta[ETH_ALEN], pkt_type;
+       struct mwifiex_sta_node *node;
+
        struct mwifiex_private *priv =
                        mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
                                               rx_info->bss_type);
@@ -191,15 +196,60 @@ int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
 
                return 0;
        }
-       ret = mwifiex_handle_uap_rx_forward(priv, skb);
 
-       if (ret) {
-               priv->stats.rx_dropped++;
+       if (le16_to_cpu(uap_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
+               struct sk_buff_head list;
+               struct sk_buff *rx_skb;
+
+               __skb_queue_head_init(&list);
+               skb_pull(skb, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
+               skb_trim(skb, le16_to_cpu(uap_rx_pd->rx_pkt_length));
+
+               ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
+                                        priv->wdev->iftype, 0, false);
+
+               while (!skb_queue_empty(&list)) {
+                       rx_skb = __skb_dequeue(&list);
+                       ret = mwifiex_recv_packet(adapter, rx_skb);
+                       if (ret)
+                               dev_err(adapter->dev,
+                                       "AP:Rx A-MSDU failed");
+               }
+
+               return 0;
+       }
+
+       memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
+
+       if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
+               node = mwifiex_get_sta_entry(priv, ta);
+               if (node)
+                       node->rx_seq[uap_rx_pd->priority] =
+                                               le16_to_cpu(uap_rx_pd->seq_num);
+       }
+
+       if (!priv->ap_11n_enabled ||
+           (!mwifiex_11n_get_rx_reorder_tbl(priv, uap_rx_pd->priority, ta) &&
+           (le16_to_cpu(uap_rx_pd->rx_pkt_type) != PKT_TYPE_AMSDU))) {
+               ret = mwifiex_handle_uap_rx_forward(priv, skb);
+               return ret;
+       }
+
+       /* Reorder and send to kernel */
+       pkt_type = (u8)le16_to_cpu(uap_rx_pd->rx_pkt_type);
+       ret = mwifiex_11n_rx_reorder_pkt(priv, le16_to_cpu(uap_rx_pd->seq_num),
+                                        uap_rx_pd->priority, ta, pkt_type,
+                                        skb);
+
+       if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
                if (adapter->if_ops.data_complete)
                        adapter->if_ops.data_complete(adapter, skb);
                else
                        dev_kfree_skb_any(skb);
        }
 
+       if (ret)
+               priv->stats.rx_dropped++;
+
        return ret;
 }