diff options
author | Xinming Hu <huxm@marvell.com> | 2016-04-05 04:04:39 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2016-04-07 12:42:25 -0400 |
commit | bf00dc22bc7a72d58fd1945814321b30948dc83b (patch) | |
tree | 55945622e909dafed3cd7fe4837d7896b27a4cf5 | |
parent | ad5ca845e3d194703be82ad4a2f3042f2e198e2b (diff) |
mwifiex: AMSDU Rx frame handling in AP mode
This patch processes sub AMSDU frame received in AP mode.
If a packet is multicast/broadcast, it is sent to kernel/upper
layer as well as queued back to AP TX queue so that it can be
sent to other associated stations.
If a packet is unicast and RA is present in associated station list,
it is again requeued into AP TX queue.
If a packet is unicast and RA is not in associated station list,
packet is forwarded to kernel to handle routing logic.
Signed-off-by: Xinming Hu <huxm@marvell.com>
Signed-off-by: Cathy Luo <cluo@marvell.com>
Signed-off-by: Amitkumar Karwar <akarwar@marvell.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/main.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/marvell/mwifiex/uap_txrx.c | 90 |
3 files changed, 96 insertions, 1 deletions
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c index 09578c6cde59..a74cc43b1953 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c | |||
@@ -59,7 +59,10 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv, | |||
59 | skb->len); | 59 | skb->len); |
60 | } | 60 | } |
61 | 61 | ||
62 | ret = mwifiex_recv_packet(priv, rx_skb); | 62 | if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) |
63 | ret = mwifiex_uap_recv_packet(priv, rx_skb); | ||
64 | else | ||
65 | ret = mwifiex_recv_packet(priv, rx_skb); | ||
63 | if (ret == -1) | 66 | if (ret == -1) |
64 | mwifiex_dbg(priv->adapter, ERROR, | 67 | mwifiex_dbg(priv->adapter, ERROR, |
65 | "Rx of A-MSDU failed"); | 68 | "Rx of A-MSDU failed"); |
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index aafc4ab4e5ae..a159fbef20cd 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h | |||
@@ -1019,6 +1019,8 @@ int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter); | |||
1019 | int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); | 1019 | int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *); |
1020 | 1020 | ||
1021 | int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb); | 1021 | int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb); |
1022 | int mwifiex_uap_recv_packet(struct mwifiex_private *priv, | ||
1023 | struct sk_buff *skb); | ||
1022 | 1024 | ||
1023 | int mwifiex_process_mgmt_packet(struct mwifiex_private *priv, | 1025 | int mwifiex_process_mgmt_packet(struct mwifiex_private *priv, |
1024 | struct sk_buff *skb); | 1026 | struct sk_buff *skb); |
diff --git a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c index ee7fe58dd266..c95b61dc87c2 100644 --- a/drivers/net/wireless/marvell/mwifiex/uap_txrx.c +++ b/drivers/net/wireless/marvell/mwifiex/uap_txrx.c | |||
@@ -265,6 +265,96 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv, | |||
265 | return mwifiex_process_rx_packet(priv, skb); | 265 | return mwifiex_process_rx_packet(priv, skb); |
266 | } | 266 | } |
267 | 267 | ||
268 | int mwifiex_uap_recv_packet(struct mwifiex_private *priv, | ||
269 | struct sk_buff *skb) | ||
270 | { | ||
271 | struct mwifiex_adapter *adapter = adapter; | ||
272 | struct mwifiex_sta_node *src_node; | ||
273 | struct ethhdr *p_ethhdr; | ||
274 | struct sk_buff *skb_uap; | ||
275 | struct mwifiex_txinfo *tx_info; | ||
276 | |||
277 | if (!skb) | ||
278 | return -1; | ||
279 | |||
280 | p_ethhdr = (void *)skb->data; | ||
281 | src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source); | ||
282 | if (src_node) { | ||
283 | src_node->stats.last_rx = jiffies; | ||
284 | src_node->stats.rx_bytes += skb->len; | ||
285 | src_node->stats.rx_packets++; | ||
286 | } | ||
287 | |||
288 | skb->dev = priv->netdev; | ||
289 | skb->protocol = eth_type_trans(skb, priv->netdev); | ||
290 | skb->ip_summed = CHECKSUM_NONE; | ||
291 | |||
292 | /* This is required only in case of 11n and USB/PCIE as we alloc | ||
293 | * a buffer of 4K only if its 11N (to be able to receive 4K | ||
294 | * AMSDU packets). In case of SD we allocate buffers based | ||
295 | * on the size of packet and hence this is not needed. | ||
296 | * | ||
297 | * Modifying the truesize here as our allocation for each | ||
298 | * skb is 4K but we only receive 2K packets and this cause | ||
299 | * the kernel to start dropping packets in case where | ||
300 | * application has allocated buffer based on 2K size i.e. | ||
301 | * if there a 64K packet received (in IP fragments and | ||
302 | * application allocates 64K to receive this packet but | ||
303 | * this packet would almost double up because we allocate | ||
304 | * each 1.5K fragment in 4K and pass it up. As soon as the | ||
305 | * 64K limit hits kernel will start to drop rest of the | ||
306 | * fragments. Currently we fail the Filesndl-ht.scr script | ||
307 | * for UDP, hence this fix | ||
308 | */ | ||
309 | if ((adapter->iface_type == MWIFIEX_USB || | ||
310 | adapter->iface_type == MWIFIEX_PCIE) && | ||
311 | (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE)) | ||
312 | skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE); | ||
313 | |||
314 | if (is_multicast_ether_addr(p_ethhdr->h_dest) || | ||
315 | mwifiex_get_sta_entry(priv, p_ethhdr->h_dest)) { | ||
316 | if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) | ||
317 | skb_uap = | ||
318 | skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN); | ||
319 | else | ||
320 | skb_uap = skb_copy(skb, GFP_ATOMIC); | ||
321 | |||
322 | if (likely(skb_uap)) { | ||
323 | tx_info = MWIFIEX_SKB_TXCB(skb_uap); | ||
324 | memset(tx_info, 0, sizeof(*tx_info)); | ||
325 | tx_info->bss_num = priv->bss_num; | ||
326 | tx_info->bss_type = priv->bss_type; | ||
327 | tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT; | ||
328 | __net_timestamp(skb_uap); | ||
329 | mwifiex_wmm_add_buf_txqueue(priv, skb_uap); | ||
330 | atomic_inc(&adapter->tx_pending); | ||
331 | atomic_inc(&adapter->pending_bridged_pkts); | ||
332 | if ((atomic_read(&adapter->pending_bridged_pkts) >= | ||
333 | MWIFIEX_BRIDGED_PKTS_THR_HIGH)) { | ||
334 | mwifiex_dbg(adapter, ERROR, | ||
335 | "Tx: Bridge packet limit reached. Drop packet!\n"); | ||
336 | mwifiex_uap_cleanup_tx_queues(priv); | ||
337 | } | ||
338 | |||
339 | } else { | ||
340 | mwifiex_dbg(adapter, ERROR, "failed to allocate skb_uap"); | ||
341 | } | ||
342 | |||
343 | mwifiex_queue_main_work(adapter); | ||
344 | /* Don't forward Intra-BSS unicast packet to upper layer*/ | ||
345 | if (mwifiex_get_sta_entry(priv, p_ethhdr->h_dest)) | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | /* Forward multicast/broadcast packet to upper layer*/ | ||
350 | if (in_interrupt()) | ||
351 | netif_rx(skb); | ||
352 | else | ||
353 | netif_rx_ni(skb); | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
268 | /* | 358 | /* |
269 | * This function processes the packet received on AP interface. | 359 | * This function processes the packet received on AP interface. |
270 | * | 360 | * |