Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf00dc22 authored by Xinming Hu's avatar Xinming Hu Committed by Kalle Valo
Browse files

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: default avatarXinming Hu <huxm@marvell.com>
Signed-off-by: default avatarCathy Luo <cluo@marvell.com>
Signed-off-by: default avatarAmitkumar Karwar <akarwar@marvell.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent ad5ca845
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -59,6 +59,9 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
								  skb->len);
			}

			if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
				ret = mwifiex_uap_recv_packet(priv, rx_skb);
			else
				ret = mwifiex_recv_packet(priv, rx_skb);
			if (ret == -1)
				mwifiex_dbg(priv->adapter, ERROR,
+2 −0
Original line number Diff line number Diff line
@@ -1019,6 +1019,8 @@ int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter);
int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *);

int mwifiex_recv_packet(struct mwifiex_private *priv, struct sk_buff *skb);
int mwifiex_uap_recv_packet(struct mwifiex_private *priv,
			    struct sk_buff *skb);

int mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
				struct sk_buff *skb);
+90 −0
Original line number Diff line number Diff line
@@ -265,6 +265,96 @@ int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
	return mwifiex_process_rx_packet(priv, skb);
}

int mwifiex_uap_recv_packet(struct mwifiex_private *priv,
			    struct sk_buff *skb)
{
	struct mwifiex_adapter *adapter = adapter;
	struct mwifiex_sta_node *src_node;
	struct ethhdr *p_ethhdr;
	struct sk_buff *skb_uap;
	struct mwifiex_txinfo *tx_info;

	if (!skb)
		return -1;

	p_ethhdr = (void *)skb->data;
	src_node = mwifiex_get_sta_entry(priv, p_ethhdr->h_source);
	if (src_node) {
		src_node->stats.last_rx = jiffies;
		src_node->stats.rx_bytes += skb->len;
		src_node->stats.rx_packets++;
	}

	skb->dev = priv->netdev;
	skb->protocol = eth_type_trans(skb, priv->netdev);
	skb->ip_summed = CHECKSUM_NONE;

	/* This is required only in case of 11n and USB/PCIE as we alloc
	 * a buffer of 4K only if its 11N (to be able to receive 4K
	 * AMSDU packets). In case of SD we allocate buffers based
	 * on the size of packet and hence this is not needed.
	 *
	 * Modifying the truesize here as our allocation for each
	 * skb is 4K but we only receive 2K packets and this cause
	 * the kernel to start dropping packets in case where
	 * application has allocated buffer based on 2K size i.e.
	 * if there a 64K packet received (in IP fragments and
	 * application allocates 64K to receive this packet but
	 * this packet would almost double up because we allocate
	 * each 1.5K fragment in 4K and pass it up. As soon as the
	 * 64K limit hits kernel will start to drop rest of the
	 * fragments. Currently we fail the Filesndl-ht.scr script
	 * for UDP, hence this fix
	 */
	if ((adapter->iface_type == MWIFIEX_USB ||
	     adapter->iface_type == MWIFIEX_PCIE) &&
	    (skb->truesize > MWIFIEX_RX_DATA_BUF_SIZE))
		skb->truesize += (skb->len - MWIFIEX_RX_DATA_BUF_SIZE);

	if (is_multicast_ether_addr(p_ethhdr->h_dest) ||
	    mwifiex_get_sta_entry(priv, p_ethhdr->h_dest)) {
		if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN)
			skb_uap =
			skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
		else
			skb_uap = skb_copy(skb, GFP_ATOMIC);

		if (likely(skb_uap)) {
			tx_info = MWIFIEX_SKB_TXCB(skb_uap);
			memset(tx_info, 0, sizeof(*tx_info));
			tx_info->bss_num = priv->bss_num;
			tx_info->bss_type = priv->bss_type;
			tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
			__net_timestamp(skb_uap);
			mwifiex_wmm_add_buf_txqueue(priv, skb_uap);
			atomic_inc(&adapter->tx_pending);
			atomic_inc(&adapter->pending_bridged_pkts);
			if ((atomic_read(&adapter->pending_bridged_pkts) >=
					MWIFIEX_BRIDGED_PKTS_THR_HIGH)) {
				mwifiex_dbg(adapter, ERROR,
					    "Tx: Bridge packet limit reached. Drop packet!\n");
				mwifiex_uap_cleanup_tx_queues(priv);
			}

		} else {
			mwifiex_dbg(adapter, ERROR, "failed to allocate skb_uap");
		}

		mwifiex_queue_main_work(adapter);
		/* Don't forward Intra-BSS unicast packet to upper layer*/
		if (mwifiex_get_sta_entry(priv, p_ethhdr->h_dest))
			return 0;
	}

	/* Forward multicast/broadcast packet to upper layer*/
	if (in_interrupt())
		netif_rx(skb);
	else
		netif_rx_ni(skb);

	return 0;
}

/*
 * This function processes the packet received on AP interface.
 *