aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorAvinash Patil <patila@marvell.com>2012-08-03 21:06:08 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-08-06 15:12:54 -0400
commit838e4f44929782a2163c7bc95a7cd2da5d8b47f9 (patch)
tree01f73f71e516e23bdc01fef09cc09f2049ada950 /drivers/net
parent017a92a15a119be3b751456cb04791282721c661 (diff)
mwifiex: improve uAP RX handling
1. Separate file for uAP RX handling. 2. If received packet is broadcast/multicast, send it to kernel as well as requeue it back to uAP TX queue. 3. If received packet is for associated STA (intra-BSS), requeue it back to uAP TX queue. 4. In all other cases (packets for AP or inter-BSS packets), pass packet to kernel to handle it accordingly. 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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/mwifiex/Makefile1
-rw-r--r--drivers/net/wireless/mwifiex/decl.h3
-rw-r--r--drivers/net/wireless/mwifiex/fw.h25
-rw-r--r--drivers/net/wireless/mwifiex/main.h5
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c5
-rw-r--r--drivers/net/wireless/mwifiex/uap_txrx.c205
6 files changed, 244 insertions, 0 deletions
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index 20932f24dc23..dd0410d2d465 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -36,6 +36,7 @@ mwifiex-y += sta_event.o
36mwifiex-y += uap_event.o 36mwifiex-y += uap_event.o
37mwifiex-y += sta_tx.o 37mwifiex-y += sta_tx.o
38mwifiex-y += sta_rx.o 38mwifiex-y += sta_rx.o
39mwifiex-y += uap_txrx.o
39mwifiex-y += cfg80211.o 40mwifiex-y += cfg80211.o
40mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o 41mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
41obj-$(CONFIG_MWIFIEX) += mwifiex.o 42obj-$(CONFIG_MWIFIEX) += mwifiex.o
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 070ef25f5186..400d360ac91f 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -60,6 +60,9 @@
60#define MWIFIEX_SDIO_BLOCK_SIZE 256 60#define MWIFIEX_SDIO_BLOCK_SIZE 256
61 61
62#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) 62#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
63#define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1)
64
65#define MWIFIEX_BRIDGED_PKTS_THRESHOLD 1024
63 66
64enum mwifiex_bss_type { 67enum mwifiex_bss_type {
65 MWIFIEX_BSS_TYPE_STA = 0, 68 MWIFIEX_BSS_TYPE_STA = 0,
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index a0222ec1cc38..1c1274d8d789 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -439,6 +439,31 @@ struct rxpd {
439 u8 reserved; 439 u8 reserved;
440} __packed; 440} __packed;
441 441
442struct uap_txpd {
443 u8 bss_type;
444 u8 bss_num;
445 __le16 tx_pkt_length;
446 __le16 tx_pkt_offset;
447 __le16 tx_pkt_type;
448 __le32 tx_control;
449 u8 priority;
450 u8 flags;
451 u8 pkt_delay_2ms;
452 u8 reserved1;
453 __le32 reserved2;
454};
455
456struct uap_rxpd {
457 u8 bss_type;
458 u8 bss_num;
459 __le16 rx_pkt_length;
460 __le16 rx_pkt_offset;
461 __le16 rx_pkt_type;
462 __le16 seq_num;
463 u8 priority;
464 u8 reserved1;
465};
466
442enum mwifiex_chan_scan_mode_bitmasks { 467enum mwifiex_chan_scan_mode_bitmasks {
443 MWIFIEX_PASSIVE_SCAN = BIT(0), 468 MWIFIEX_PASSIVE_SCAN = BIT(0),
444 MWIFIEX_DISABLE_CHAN_FILT = BIT(1), 469 MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 9a0174d06460..014fe9ab221f 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -710,6 +710,7 @@ struct mwifiex_adapter {
710 u8 scan_delay_cnt; 710 u8 scan_delay_cnt;
711 u8 empty_tx_q_cnt; 711 u8 empty_tx_q_cnt;
712 atomic_t is_tx_received; 712 atomic_t is_tx_received;
713 atomic_t pending_bridged_pkts;
713}; 714};
714 715
715int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); 716int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -800,6 +801,10 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
800 struct host_cmd_ds_command *resp); 801 struct host_cmd_ds_command *resp);
801int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, 802int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
802 struct sk_buff *skb); 803 struct sk_buff *skb);
804int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
805 struct sk_buff *skb);
806int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
807 struct sk_buff *skb);
803int mwifiex_process_sta_event(struct mwifiex_private *); 808int mwifiex_process_sta_event(struct mwifiex_private *);
804int mwifiex_process_uap_event(struct mwifiex_private *); 809int mwifiex_process_uap_event(struct mwifiex_private *);
805struct mwifiex_sta_node * 810struct mwifiex_sta_node *
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index cecb27283196..985073d0df1a 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -51,6 +51,9 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
51 rx_info->bss_num = priv->bss_num; 51 rx_info->bss_num = priv->bss_num;
52 rx_info->bss_type = priv->bss_type; 52 rx_info->bss_type = priv->bss_type;
53 53
54 if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
55 return mwifiex_process_uap_rx_packet(adapter, skb);
56
54 return mwifiex_process_sta_rx_packet(adapter, skb); 57 return mwifiex_process_sta_rx_packet(adapter, skb);
55} 58}
56EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet); 59EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
@@ -157,6 +160,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
157 priv->stats.tx_errors++; 160 priv->stats.tx_errors++;
158 } 161 }
159 162
163 if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
164 atomic_dec_return(&adapter->pending_bridged_pkts);
160 if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING) 165 if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
161 goto done; 166 goto done;
162 167
diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c
new file mode 100644
index 000000000000..f55c5ac3e5e0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/uap_txrx.c
@@ -0,0 +1,205 @@
1/*
2 * Marvell Wireless LAN device driver: AP TX and RX data handling
3 *
4 * Copyright (C) 2012, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License"). You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available by writing to the Free Software Foundation, Inc.,
11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13 *
14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
17 * this warranty disclaimer.
18 */
19
20#include "decl.h"
21#include "ioctl.h"
22#include "main.h"
23#include "wmm.h"
24
25static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
26 struct sk_buff *skb)
27{
28 struct mwifiex_adapter *adapter = priv->adapter;
29 struct uap_rxpd *uap_rx_pd;
30 struct rx_packet_hdr *rx_pkt_hdr;
31 struct sk_buff *new_skb;
32 struct mwifiex_txinfo *tx_info;
33 int hdr_chop;
34 struct timeval tv;
35 u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
36
37 uap_rx_pd = (struct uap_rxpd *)(skb->data);
38 rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
39
40 if ((atomic_read(&adapter->pending_bridged_pkts) >=
41 MWIFIEX_BRIDGED_PKTS_THRESHOLD)) {
42 dev_err(priv->adapter->dev,
43 "Tx: Bridge packet limit reached. Drop packet!\n");
44 kfree_skb(skb);
45 return;
46 }
47
48 if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
49 rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)))
50 /* Chop off the rxpd + the excess memory from
51 * 802.2/llc/snap header that was removed.
52 */
53 hdr_chop = (u8 *)eth_hdr - (u8 *)uap_rx_pd;
54 else
55 /* Chop off the rxpd */
56 hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)uap_rx_pd;
57
58 /* Chop off the leading header bytes so the it points
59 * to the start of either the reconstructed EthII frame
60 * or the 802.2/llc/snap frame.
61 */
62 skb_pull(skb, hdr_chop);
63
64 if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
65 dev_dbg(priv->adapter->dev,
66 "data: Tx: insufficient skb headroom %d\n",
67 skb_headroom(skb));
68 /* Insufficient skb headroom - allocate a new skb */
69 new_skb =
70 skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
71 if (unlikely(!new_skb)) {
72 dev_err(priv->adapter->dev,
73 "Tx: cannot allocate new_skb\n");
74 kfree_skb(skb);
75 priv->stats.tx_dropped++;
76 return;
77 }
78
79 kfree_skb(skb);
80 skb = new_skb;
81 dev_dbg(priv->adapter->dev, "info: new skb headroom %d\n",
82 skb_headroom(skb));
83 }
84
85 tx_info = MWIFIEX_SKB_TXCB(skb);
86 tx_info->bss_num = priv->bss_num;
87 tx_info->bss_type = priv->bss_type;
88 tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
89
90 do_gettimeofday(&tv);
91 skb->tstamp = timeval_to_ktime(tv);
92 mwifiex_wmm_add_buf_txqueue(priv, skb);
93 atomic_inc(&adapter->tx_pending);
94 atomic_inc(&adapter->pending_bridged_pkts);
95
96 if ((atomic_read(&adapter->tx_pending) >= MAX_TX_PENDING)) {
97 mwifiex_set_trans_start(priv->netdev);
98 mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
99 }
100 return;
101}
102
103/*
104 * This function contains logic for AP packet forwarding.
105 *
106 * If a packet is multicast/broadcast, it is sent to kernel/upper layer
107 * as well as queued back to AP TX queue so that it can be sent to other
108 * associated stations.
109 * If a packet is unicast and RA is present in associated station list,
110 * it is again requeued into AP TX queue.
111 * If a packet is unicast and RA is not in associated station list,
112 * packet is forwarded to kernel to handle routing logic.
113 */
114int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
115 struct sk_buff *skb)
116{
117 struct mwifiex_adapter *adapter = priv->adapter;
118 struct uap_rxpd *uap_rx_pd;
119 struct rx_packet_hdr *rx_pkt_hdr;
120 u8 ra[ETH_ALEN];
121 struct sk_buff *skb_uap;
122
123 uap_rx_pd = (struct uap_rxpd *)(skb->data);
124 rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
125
126 /* don't do packet forwarding in disconnected state */
127 if (!priv->media_connected) {
128 dev_err(adapter->dev, "drop packet in disconnected state.\n");
129 dev_kfree_skb_any(skb);
130 return 0;
131 }
132
133 memcpy(ra, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN);
134
135 if (is_multicast_ether_addr(ra)) {
136 skb_uap = skb_copy(skb, GFP_ATOMIC);
137 mwifiex_uap_queue_bridged_pkt(priv, skb_uap);
138 } else {
139 if (mwifiex_get_sta_entry(priv, ra)) {
140 /* Requeue Intra-BSS packet */
141 mwifiex_uap_queue_bridged_pkt(priv, skb);
142 return 0;
143 }
144 }
145
146 /* Forward unicat/Inter-BSS packets to kernel. */
147 return mwifiex_process_rx_packet(adapter, skb);
148}
149
150/*
151 * This function processes the packet received on AP interface.
152 *
153 * The function looks into the RxPD and performs sanity tests on the
154 * received buffer to ensure its a valid packet before processing it
155 * further. If the packet is determined to be aggregated, it is
156 * de-aggregated accordingly. Then skb is passed to AP packet forwarding logic.
157 *
158 * The completion callback is called after processing is complete.
159 */
160int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
161 struct sk_buff *skb)
162{
163 int ret;
164 struct uap_rxpd *uap_rx_pd;
165 struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
166 struct rx_packet_hdr *rx_pkt_hdr;
167 u16 rx_pkt_type;
168 struct mwifiex_private *priv =
169 mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
170 rx_info->bss_type);
171
172 if (!priv)
173 return -1;
174
175 uap_rx_pd = (struct uap_rxpd *)(skb->data);
176 rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
177 rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
178
179 if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
180 le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16) skb->len) {
181 dev_err(adapter->dev,
182 "wrong rx packet: len=%d, offset=%d, length=%d\n",
183 skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
184 le16_to_cpu(uap_rx_pd->rx_pkt_length));
185 priv->stats.rx_dropped++;
186
187 if (adapter->if_ops.data_complete)
188 adapter->if_ops.data_complete(adapter, skb);
189 else
190 dev_kfree_skb_any(skb);
191
192 return 0;
193 }
194 ret = mwifiex_handle_uap_rx_forward(priv, skb);
195
196 if (ret) {
197 priv->stats.rx_dropped++;
198 if (adapter->if_ops.data_complete)
199 adapter->if_ops.data_complete(adapter, skb);
200 else
201 dev_kfree_skb_any(skb);
202 }
203
204 return ret;
205}