xref: /linux/drivers/net/wireless/nxp/nxpwifi/uap_txrx.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1*73b01e57SJeff Chen // SPDX-License-Identifier: GPL-2.0-only
2*73b01e57SJeff Chen /*
3*73b01e57SJeff Chen  * NXP Wireless LAN device driver: AP TX and RX data handling
4*73b01e57SJeff Chen  *
5*73b01e57SJeff Chen  * Copyright 2011-2024 NXP
6*73b01e57SJeff Chen  */
7*73b01e57SJeff Chen 
8*73b01e57SJeff Chen #include "cfg.h"
9*73b01e57SJeff Chen #include "main.h"
10*73b01e57SJeff Chen #include "wmm.h"
11*73b01e57SJeff Chen #include "11n_aggr.h"
12*73b01e57SJeff Chen #include "11n_rxreorder.h"
13*73b01e57SJeff Chen 
14*73b01e57SJeff Chen /*
15*73b01e57SJeff Chen  * Drop bridged pkts from RA list until pending <= low threshold; return true if
16*73b01e57SJeff Chen  * any.
17*73b01e57SJeff Chen  */
18*73b01e57SJeff Chen static bool
nxpwifi_uap_del_tx_pkts_in_ralist(struct nxpwifi_private * priv,struct list_head * ra_list_head,int tid)19*73b01e57SJeff Chen nxpwifi_uap_del_tx_pkts_in_ralist(struct nxpwifi_private *priv,
20*73b01e57SJeff Chen 				  struct list_head *ra_list_head,
21*73b01e57SJeff Chen 				  int tid)
22*73b01e57SJeff Chen {
23*73b01e57SJeff Chen 	struct nxpwifi_ra_list_tbl *ra_list;
24*73b01e57SJeff Chen 	struct sk_buff *skb, *tmp;
25*73b01e57SJeff Chen 	bool pkt_deleted = false;
26*73b01e57SJeff Chen 	struct nxpwifi_txinfo *tx_info;
27*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
28*73b01e57SJeff Chen 
29*73b01e57SJeff Chen 	list_for_each_entry(ra_list, ra_list_head, list) {
30*73b01e57SJeff Chen 		if (skb_queue_empty(&ra_list->skb_head))
31*73b01e57SJeff Chen 			continue;
32*73b01e57SJeff Chen 
33*73b01e57SJeff Chen 		skb_queue_walk_safe(&ra_list->skb_head, skb, tmp) {
34*73b01e57SJeff Chen 			tx_info = NXPWIFI_SKB_TXCB(skb);
35*73b01e57SJeff Chen 			if (tx_info->flags & NXPWIFI_BUF_FLAG_BRIDGED_PKT) {
36*73b01e57SJeff Chen 				__skb_unlink(skb, &ra_list->skb_head);
37*73b01e57SJeff Chen 				nxpwifi_write_data_complete(adapter, skb, 0,
38*73b01e57SJeff Chen 							    -1);
39*73b01e57SJeff Chen 				if (ra_list->tx_paused)
40*73b01e57SJeff Chen 					priv->wmm.pkts_paused[tid]--;
41*73b01e57SJeff Chen 				else
42*73b01e57SJeff Chen 					atomic_dec(&priv->wmm.tx_pkts_queued);
43*73b01e57SJeff Chen 				pkt_deleted = true;
44*73b01e57SJeff Chen 			}
45*73b01e57SJeff Chen 			if ((atomic_read(&adapter->pending_bridged_pkts) <=
46*73b01e57SJeff Chen 					     NXPWIFI_BRIDGED_PKTS_THR_LOW))
47*73b01e57SJeff Chen 				break;
48*73b01e57SJeff Chen 		}
49*73b01e57SJeff Chen 	}
50*73b01e57SJeff Chen 
51*73b01e57SJeff Chen 	return pkt_deleted;
52*73b01e57SJeff Chen }
53*73b01e57SJeff Chen 
54*73b01e57SJeff Chen /* Delete bridged pkts from one RA list; rotate index to keep fairness. */
nxpwifi_uap_cleanup_tx_queues(struct nxpwifi_private * priv)55*73b01e57SJeff Chen static void nxpwifi_uap_cleanup_tx_queues(struct nxpwifi_private *priv)
56*73b01e57SJeff Chen {
57*73b01e57SJeff Chen 	struct list_head *ra_list;
58*73b01e57SJeff Chen 	int i;
59*73b01e57SJeff Chen 
60*73b01e57SJeff Chen 	spin_lock_bh(&priv->wmm.ra_list_spinlock);
61*73b01e57SJeff Chen 
62*73b01e57SJeff Chen 	for (i = 0; i < MAX_NUM_TID; i++, priv->del_list_idx++) {
63*73b01e57SJeff Chen 		if (priv->del_list_idx == MAX_NUM_TID)
64*73b01e57SJeff Chen 			priv->del_list_idx = 0;
65*73b01e57SJeff Chen 		ra_list = &priv->wmm.tid_tbl_ptr[priv->del_list_idx].ra_list;
66*73b01e57SJeff Chen 		if (nxpwifi_uap_del_tx_pkts_in_ralist(priv, ra_list, i)) {
67*73b01e57SJeff Chen 			priv->del_list_idx++;
68*73b01e57SJeff Chen 			break;
69*73b01e57SJeff Chen 		}
70*73b01e57SJeff Chen 	}
71*73b01e57SJeff Chen 
72*73b01e57SJeff Chen 	spin_unlock_bh(&priv->wmm.ra_list_spinlock);
73*73b01e57SJeff Chen }
74*73b01e57SJeff Chen 
75*73b01e57SJeff Chen static void
nxpwifi_uap_queue_bridged_pkt(struct nxpwifi_private * priv,struct sk_buff * skb)76*73b01e57SJeff Chen nxpwifi_uap_queue_bridged_pkt(struct nxpwifi_private *priv,
77*73b01e57SJeff Chen 			      struct sk_buff *skb)
78*73b01e57SJeff Chen {
79*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
80*73b01e57SJeff Chen 	struct uap_rxpd *uap_rx_pd;
81*73b01e57SJeff Chen 	struct rx_packet_hdr *rx_pkt_hdr;
82*73b01e57SJeff Chen 	struct sk_buff *new_skb;
83*73b01e57SJeff Chen 	struct nxpwifi_txinfo *tx_info;
84*73b01e57SJeff Chen 	int hdr_chop;
85*73b01e57SJeff Chen 	struct ethhdr *p_ethhdr;
86*73b01e57SJeff Chen 	struct nxpwifi_sta_node *src_node;
87*73b01e57SJeff Chen 	int index;
88*73b01e57SJeff Chen 
89*73b01e57SJeff Chen 	uap_rx_pd = (struct uap_rxpd *)(skb->data);
90*73b01e57SJeff Chen 	rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
91*73b01e57SJeff Chen 
92*73b01e57SJeff Chen 	if ((atomic_read(&adapter->pending_bridged_pkts) >=
93*73b01e57SJeff Chen 					     NXPWIFI_BRIDGED_PKTS_THR_HIGH)) {
94*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
95*73b01e57SJeff Chen 			    "Tx: Bridge packet limit reached. Drop packet!\n");
96*73b01e57SJeff Chen 		kfree_skb(skb);
97*73b01e57SJeff Chen 		nxpwifi_uap_cleanup_tx_queues(priv);
98*73b01e57SJeff Chen 		return;
99*73b01e57SJeff Chen 	}
100*73b01e57SJeff Chen 
101*73b01e57SJeff Chen 	if (sizeof(*rx_pkt_hdr) +
102*73b01e57SJeff Chen 	    le16_to_cpu(uap_rx_pd->rx_pkt_offset) > skb->len) {
103*73b01e57SJeff Chen 		priv->stats.rx_dropped++;
104*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
105*73b01e57SJeff Chen 		return;
106*73b01e57SJeff Chen 	}
107*73b01e57SJeff Chen 
108*73b01e57SJeff Chen 	if ((!memcmp(&rx_pkt_hdr->rfc1042_hdr, bridge_tunnel_header,
109*73b01e57SJeff Chen 		     sizeof(bridge_tunnel_header))) ||
110*73b01e57SJeff Chen 	    (!memcmp(&rx_pkt_hdr->rfc1042_hdr, rfc1042_header,
111*73b01e57SJeff Chen 		     sizeof(rfc1042_header)) &&
112*73b01e57SJeff Chen 	     rx_pkt_hdr->rfc1042_hdr.snap_type != htons(ETH_P_AARP) &&
113*73b01e57SJeff Chen 	     rx_pkt_hdr->rfc1042_hdr.snap_type != htons(ETH_P_IPX))) {
114*73b01e57SJeff Chen 		/*
115*73b01e57SJeff Chen 		 * Replace the 803 header and rfc1042 header (llc/snap) with
116*73b01e57SJeff Chen 		 * an Ethernet II header, keep the src/dst and snap_type
117*73b01e57SJeff Chen 		 * (ethertype).
118*73b01e57SJeff Chen 		 *
119*73b01e57SJeff Chen 		 * The firmware only passes up SNAP frames converting all RX
120*73b01e57SJeff Chen 		 * data from 802.11 to 802.2/LLC/SNAP frames.
121*73b01e57SJeff Chen 		 *
122*73b01e57SJeff Chen 		 * To create the Ethernet II, just move the src, dst address
123*73b01e57SJeff Chen 		 * right before the snap_type.
124*73b01e57SJeff Chen 		 */
125*73b01e57SJeff Chen 		p_ethhdr = (struct ethhdr *)
126*73b01e57SJeff Chen 			((u8 *)(&rx_pkt_hdr->eth803_hdr)
127*73b01e57SJeff Chen 			 + sizeof(rx_pkt_hdr->eth803_hdr)
128*73b01e57SJeff Chen 			 + sizeof(rx_pkt_hdr->rfc1042_hdr)
129*73b01e57SJeff Chen 			 - sizeof(rx_pkt_hdr->eth803_hdr.h_dest)
130*73b01e57SJeff Chen 			 - sizeof(rx_pkt_hdr->eth803_hdr.h_source)
131*73b01e57SJeff Chen 			 - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type));
132*73b01e57SJeff Chen 		memcpy(p_ethhdr->h_source, rx_pkt_hdr->eth803_hdr.h_source,
133*73b01e57SJeff Chen 		       sizeof(p_ethhdr->h_source));
134*73b01e57SJeff Chen 		memcpy(p_ethhdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest,
135*73b01e57SJeff Chen 		       sizeof(p_ethhdr->h_dest));
136*73b01e57SJeff Chen 		/*
137*73b01e57SJeff Chen 		 * Chop off the rxpd + the excess memory from
138*73b01e57SJeff Chen 		 * 802.2/llc/snap header that was removed.
139*73b01e57SJeff Chen 		 */
140*73b01e57SJeff Chen 		hdr_chop = (u8 *)p_ethhdr - (u8 *)uap_rx_pd;
141*73b01e57SJeff Chen 	} else {
142*73b01e57SJeff Chen 		/* Chop off the rxpd */
143*73b01e57SJeff Chen 		hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)uap_rx_pd;
144*73b01e57SJeff Chen 	}
145*73b01e57SJeff Chen 
146*73b01e57SJeff Chen 	/*
147*73b01e57SJeff Chen 	 * Chop off the leading header bytes so that it points
148*73b01e57SJeff Chen 	 * to the start of either the reconstructed EthII frame
149*73b01e57SJeff Chen 	 * or the 802.2/llc/snap frame.
150*73b01e57SJeff Chen 	 */
151*73b01e57SJeff Chen 	skb_pull(skb, hdr_chop);
152*73b01e57SJeff Chen 
153*73b01e57SJeff Chen 	if (skb_headroom(skb) < NXPWIFI_MIN_DATA_HEADER_LEN) {
154*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
155*73b01e57SJeff Chen 			    "data: Tx: insufficient skb headroom %d\n",
156*73b01e57SJeff Chen 			    skb_headroom(skb));
157*73b01e57SJeff Chen 		/* Insufficient skb headroom - allocate a new skb */
158*73b01e57SJeff Chen 		new_skb =
159*73b01e57SJeff Chen 			skb_realloc_headroom(skb, NXPWIFI_MIN_DATA_HEADER_LEN);
160*73b01e57SJeff Chen 		if (unlikely(!new_skb)) {
161*73b01e57SJeff Chen 			nxpwifi_dbg(adapter, ERROR,
162*73b01e57SJeff Chen 				    "Tx: cannot allocate new_skb\n");
163*73b01e57SJeff Chen 			kfree_skb(skb);
164*73b01e57SJeff Chen 			priv->stats.tx_dropped++;
165*73b01e57SJeff Chen 			return;
166*73b01e57SJeff Chen 		}
167*73b01e57SJeff Chen 
168*73b01e57SJeff Chen 		kfree_skb(skb);
169*73b01e57SJeff Chen 		skb = new_skb;
170*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, INFO,
171*73b01e57SJeff Chen 			    "info: new skb headroom %d\n",
172*73b01e57SJeff Chen 			    skb_headroom(skb));
173*73b01e57SJeff Chen 	}
174*73b01e57SJeff Chen 
175*73b01e57SJeff Chen 	tx_info = NXPWIFI_SKB_TXCB(skb);
176*73b01e57SJeff Chen 	memset(tx_info, 0, sizeof(*tx_info));
177*73b01e57SJeff Chen 	tx_info->bss_num = priv->bss_num;
178*73b01e57SJeff Chen 	tx_info->bss_type = priv->bss_type;
179*73b01e57SJeff Chen 	tx_info->flags |= NXPWIFI_BUF_FLAG_BRIDGED_PKT;
180*73b01e57SJeff Chen 
181*73b01e57SJeff Chen 	rcu_read_lock();
182*73b01e57SJeff Chen 	src_node = nxpwifi_get_sta_entry(priv, rx_pkt_hdr->eth803_hdr.h_source);
183*73b01e57SJeff Chen 	if (src_node) {
184*73b01e57SJeff Chen 		src_node->stats.last_rx = jiffies;
185*73b01e57SJeff Chen 		src_node->stats.rx_bytes += skb->len;
186*73b01e57SJeff Chen 		src_node->stats.rx_packets++;
187*73b01e57SJeff Chen 		src_node->stats.last_tx_rate = uap_rx_pd->rx_rate;
188*73b01e57SJeff Chen 		src_node->stats.last_tx_htinfo = uap_rx_pd->ht_info;
189*73b01e57SJeff Chen 	}
190*73b01e57SJeff Chen 	rcu_read_unlock();
191*73b01e57SJeff Chen 
192*73b01e57SJeff Chen 	if (is_unicast_ether_addr(rx_pkt_hdr->eth803_hdr.h_dest)) {
193*73b01e57SJeff Chen 		/*
194*73b01e57SJeff Chen 		 * Update bridge packet statistics as the
195*73b01e57SJeff Chen 		 * packet is not going to kernel/upper layer.
196*73b01e57SJeff Chen 		 */
197*73b01e57SJeff Chen 		priv->stats.rx_bytes += skb->len;
198*73b01e57SJeff Chen 		priv->stats.rx_packets++;
199*73b01e57SJeff Chen 
200*73b01e57SJeff Chen 		/*
201*73b01e57SJeff Chen 		 * Sending bridge packet to TX queue, so save the packet
202*73b01e57SJeff Chen 		 * length in TXCB to update statistics in TX complete.
203*73b01e57SJeff Chen 		 */
204*73b01e57SJeff Chen 		tx_info->pkt_len = skb->len;
205*73b01e57SJeff Chen 	}
206*73b01e57SJeff Chen 
207*73b01e57SJeff Chen 	__net_timestamp(skb);
208*73b01e57SJeff Chen 
209*73b01e57SJeff Chen 	index = nxpwifi_1d_to_wmm_queue[skb->priority];
210*73b01e57SJeff Chen 	atomic_inc(&priv->wmm_tx_pending[index]);
211*73b01e57SJeff Chen 	nxpwifi_wmm_add_buf_txqueue(priv, skb);
212*73b01e57SJeff Chen 	atomic_inc(&adapter->tx_pending);
213*73b01e57SJeff Chen 	atomic_inc(&adapter->pending_bridged_pkts);
214*73b01e57SJeff Chen 
215*73b01e57SJeff Chen 	nxpwifi_queue_work(adapter, &adapter->main_work);
216*73b01e57SJeff Chen }
217*73b01e57SJeff Chen 
218*73b01e57SJeff Chen /* AP fwd: mcast/bcast -> up + bridge; unicast -> bridge if RA assoc, else up. */
nxpwifi_handle_uap_rx_forward(struct nxpwifi_private * priv,struct sk_buff * skb)219*73b01e57SJeff Chen int nxpwifi_handle_uap_rx_forward(struct nxpwifi_private *priv,
220*73b01e57SJeff Chen 				  struct sk_buff *skb)
221*73b01e57SJeff Chen {
222*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
223*73b01e57SJeff Chen 	struct uap_rxpd *uap_rx_pd;
224*73b01e57SJeff Chen 	struct rx_packet_hdr *rx_pkt_hdr;
225*73b01e57SJeff Chen 	u8 ra[ETH_ALEN];
226*73b01e57SJeff Chen 	struct sk_buff *skb_uap;
227*73b01e57SJeff Chen 	struct nxpwifi_sta_node *node;
228*73b01e57SJeff Chen 
229*73b01e57SJeff Chen 	uap_rx_pd = (struct uap_rxpd *)(skb->data);
230*73b01e57SJeff Chen 	rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
231*73b01e57SJeff Chen 
232*73b01e57SJeff Chen 	/* don't do packet forwarding in disconnected state */
233*73b01e57SJeff Chen 	if (!priv->media_connected) {
234*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
235*73b01e57SJeff Chen 			    "drop packet in disconnected state.\n");
236*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
237*73b01e57SJeff Chen 		return 0;
238*73b01e57SJeff Chen 	}
239*73b01e57SJeff Chen 
240*73b01e57SJeff Chen 	memcpy(ra, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN);
241*73b01e57SJeff Chen 
242*73b01e57SJeff Chen 	if (is_multicast_ether_addr(ra)) {
243*73b01e57SJeff Chen 		skb_uap = skb_copy(skb, GFP_ATOMIC);
244*73b01e57SJeff Chen 		if (likely(skb_uap)) {
245*73b01e57SJeff Chen 			nxpwifi_uap_queue_bridged_pkt(priv, skb_uap);
246*73b01e57SJeff Chen 		} else {
247*73b01e57SJeff Chen 			nxpwifi_dbg(adapter, ERROR,
248*73b01e57SJeff Chen 				    "failed to copy skb for uAP\n");
249*73b01e57SJeff Chen 			priv->stats.rx_dropped++;
250*73b01e57SJeff Chen 			dev_kfree_skb_any(skb);
251*73b01e57SJeff Chen 			return -ENOMEM;
252*73b01e57SJeff Chen 		}
253*73b01e57SJeff Chen 	} else {
254*73b01e57SJeff Chen 		node = nxpwifi_get_sta_entry_rcu(priv, ra);
255*73b01e57SJeff Chen 		if (node) {
256*73b01e57SJeff Chen 			/* Requeue Intra-BSS packet */
257*73b01e57SJeff Chen 			nxpwifi_uap_queue_bridged_pkt(priv, skb);
258*73b01e57SJeff Chen 			return 0;
259*73b01e57SJeff Chen 		}
260*73b01e57SJeff Chen 	}
261*73b01e57SJeff Chen 
262*73b01e57SJeff Chen 	/* Forward unicat/Inter-BSS packets to kernel. */
263*73b01e57SJeff Chen 	return nxpwifi_process_rx_packet(priv, skb);
264*73b01e57SJeff Chen }
265*73b01e57SJeff Chen 
nxpwifi_uap_recv_packet(struct nxpwifi_private * priv,struct sk_buff * skb)266*73b01e57SJeff Chen int nxpwifi_uap_recv_packet(struct nxpwifi_private *priv,
267*73b01e57SJeff Chen 			    struct sk_buff *skb)
268*73b01e57SJeff Chen {
269*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
270*73b01e57SJeff Chen 	struct nxpwifi_sta_node *src_node, *dst_node;
271*73b01e57SJeff Chen 	struct ethhdr *p_ethhdr;
272*73b01e57SJeff Chen 	struct sk_buff *skb_uap;
273*73b01e57SJeff Chen 	struct nxpwifi_txinfo *tx_info;
274*73b01e57SJeff Chen 
275*73b01e57SJeff Chen 	if (!skb)
276*73b01e57SJeff Chen 		return -ENOMEM;
277*73b01e57SJeff Chen 
278*73b01e57SJeff Chen 	p_ethhdr = (void *)skb->data;
279*73b01e57SJeff Chen 	rcu_read_lock();
280*73b01e57SJeff Chen 	src_node = nxpwifi_get_sta_entry(priv, p_ethhdr->h_source);
281*73b01e57SJeff Chen 	if (src_node) {
282*73b01e57SJeff Chen 		src_node->stats.last_rx = jiffies;
283*73b01e57SJeff Chen 		src_node->stats.rx_bytes += skb->len;
284*73b01e57SJeff Chen 		src_node->stats.rx_packets++;
285*73b01e57SJeff Chen 	}
286*73b01e57SJeff Chen 	dst_node = nxpwifi_get_sta_entry(priv, p_ethhdr->h_dest);
287*73b01e57SJeff Chen 	rcu_read_unlock();
288*73b01e57SJeff Chen 
289*73b01e57SJeff Chen 	if (is_multicast_ether_addr(p_ethhdr->h_dest) || dst_node) {
290*73b01e57SJeff Chen 		if (skb_headroom(skb) < NXPWIFI_MIN_DATA_HEADER_LEN)
291*73b01e57SJeff Chen 			skb_uap =
292*73b01e57SJeff Chen 			skb_realloc_headroom(skb, NXPWIFI_MIN_DATA_HEADER_LEN);
293*73b01e57SJeff Chen 		else
294*73b01e57SJeff Chen 			skb_uap = skb_copy(skb, GFP_ATOMIC);
295*73b01e57SJeff Chen 
296*73b01e57SJeff Chen 		if (likely(skb_uap)) {
297*73b01e57SJeff Chen 			tx_info = NXPWIFI_SKB_TXCB(skb_uap);
298*73b01e57SJeff Chen 			memset(tx_info, 0, sizeof(*tx_info));
299*73b01e57SJeff Chen 			tx_info->bss_num = priv->bss_num;
300*73b01e57SJeff Chen 			tx_info->bss_type = priv->bss_type;
301*73b01e57SJeff Chen 			tx_info->flags |= NXPWIFI_BUF_FLAG_BRIDGED_PKT;
302*73b01e57SJeff Chen 			__net_timestamp(skb_uap);
303*73b01e57SJeff Chen 			nxpwifi_wmm_add_buf_txqueue(priv, skb_uap);
304*73b01e57SJeff Chen 			atomic_inc(&adapter->tx_pending);
305*73b01e57SJeff Chen 			atomic_inc(&adapter->pending_bridged_pkts);
306*73b01e57SJeff Chen 			if ((atomic_read(&adapter->pending_bridged_pkts) >=
307*73b01e57SJeff Chen 					NXPWIFI_BRIDGED_PKTS_THR_HIGH)) {
308*73b01e57SJeff Chen 				nxpwifi_dbg(adapter, ERROR,
309*73b01e57SJeff Chen 					    "Tx: Bridge packet limit reached. Drop packet!\n");
310*73b01e57SJeff Chen 				nxpwifi_uap_cleanup_tx_queues(priv);
311*73b01e57SJeff Chen 			}
312*73b01e57SJeff Chen 
313*73b01e57SJeff Chen 		} else {
314*73b01e57SJeff Chen 			nxpwifi_dbg(adapter, ERROR, "failed to allocate skb_uap");
315*73b01e57SJeff Chen 		}
316*73b01e57SJeff Chen 
317*73b01e57SJeff Chen 		nxpwifi_queue_work(adapter, &adapter->main_work);
318*73b01e57SJeff Chen 		/* Don't forward Intra-BSS unicast packet to upper layer*/
319*73b01e57SJeff Chen 
320*73b01e57SJeff Chen 		if (dst_node)
321*73b01e57SJeff Chen 			return 0;
322*73b01e57SJeff Chen 	}
323*73b01e57SJeff Chen 
324*73b01e57SJeff Chen 	skb->dev = priv->netdev;
325*73b01e57SJeff Chen 	skb->protocol = eth_type_trans(skb, priv->netdev);
326*73b01e57SJeff Chen 	skb->ip_summed = CHECKSUM_NONE;
327*73b01e57SJeff Chen 
328*73b01e57SJeff Chen 	/* Forward multicast/broadcast packet to upper layer*/
329*73b01e57SJeff Chen 	netif_rx(skb);
330*73b01e57SJeff Chen 	return 0;
331*73b01e57SJeff Chen }
332*73b01e57SJeff Chen 
333*73b01e57SJeff Chen /* Process AP RX: check RxPD/len, handle mgmt or 11n reorder/AMSDU, then forward. */
nxpwifi_process_uap_rx_packet(struct nxpwifi_private * priv,struct sk_buff * skb)334*73b01e57SJeff Chen int nxpwifi_process_uap_rx_packet(struct nxpwifi_private *priv,
335*73b01e57SJeff Chen 				  struct sk_buff *skb)
336*73b01e57SJeff Chen {
337*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
338*73b01e57SJeff Chen 	int ret;
339*73b01e57SJeff Chen 	struct uap_rxpd *uap_rx_pd;
340*73b01e57SJeff Chen 	struct rx_packet_hdr *rx_pkt_hdr;
341*73b01e57SJeff Chen 	u16 rx_pkt_type;
342*73b01e57SJeff Chen 	u8 ta[ETH_ALEN], pkt_type;
343*73b01e57SJeff Chen 	struct nxpwifi_sta_node *node;
344*73b01e57SJeff Chen 
345*73b01e57SJeff Chen 	uap_rx_pd = (struct uap_rxpd *)(skb->data);
346*73b01e57SJeff Chen 	rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
347*73b01e57SJeff Chen 	rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
348*73b01e57SJeff Chen 
349*73b01e57SJeff Chen 	if (le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
350*73b01e57SJeff Chen 	    sizeof(rx_pkt_hdr->eth803_hdr) > skb->len) {
351*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
352*73b01e57SJeff Chen 			    "wrong rx packet for struct ethhdr: len=%d, offset=%d\n",
353*73b01e57SJeff Chen 			    skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
354*73b01e57SJeff Chen 		priv->stats.rx_dropped++;
355*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
356*73b01e57SJeff Chen 		return 0;
357*73b01e57SJeff Chen 	}
358*73b01e57SJeff Chen 
359*73b01e57SJeff Chen 	ether_addr_copy(ta, rx_pkt_hdr->eth803_hdr.h_source);
360*73b01e57SJeff Chen 
361*73b01e57SJeff Chen 	if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
362*73b01e57SJeff Chen 	     le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16)skb->len) {
363*73b01e57SJeff Chen 		nxpwifi_dbg(adapter, ERROR,
364*73b01e57SJeff Chen 			    "wrong rx packet: len=%d, offset=%d, length=%d\n",
365*73b01e57SJeff Chen 			    skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
366*73b01e57SJeff Chen 			    le16_to_cpu(uap_rx_pd->rx_pkt_length));
367*73b01e57SJeff Chen 		priv->stats.rx_dropped++;
368*73b01e57SJeff Chen 		rcu_read_lock();
369*73b01e57SJeff Chen 		node = nxpwifi_get_sta_entry(priv, ta);
370*73b01e57SJeff Chen 		if (node)
371*73b01e57SJeff Chen 			node->stats.tx_failed++;
372*73b01e57SJeff Chen 		rcu_read_unlock();
373*73b01e57SJeff Chen 
374*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
375*73b01e57SJeff Chen 		return 0;
376*73b01e57SJeff Chen 	}
377*73b01e57SJeff Chen 
378*73b01e57SJeff Chen 	if (rx_pkt_type == PKT_TYPE_MGMT) {
379*73b01e57SJeff Chen 		ret = nxpwifi_process_mgmt_packet(priv, skb);
380*73b01e57SJeff Chen 		if (ret && (ret != -EINPROGRESS))
381*73b01e57SJeff Chen 			nxpwifi_dbg(adapter, DATA, "Rx of mgmt packet failed");
382*73b01e57SJeff Chen 		if (ret != -EINPROGRESS)
383*73b01e57SJeff Chen 			dev_kfree_skb_any(skb);
384*73b01e57SJeff Chen 		return ret;
385*73b01e57SJeff Chen 	}
386*73b01e57SJeff Chen 
387*73b01e57SJeff Chen 	if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
388*73b01e57SJeff Chen 		rcu_read_lock();
389*73b01e57SJeff Chen 		node = nxpwifi_get_sta_entry(priv, ta);
390*73b01e57SJeff Chen 		if (node)
391*73b01e57SJeff Chen 			node->rx_seq[uap_rx_pd->priority] =
392*73b01e57SJeff Chen 						le16_to_cpu(uap_rx_pd->seq_num);
393*73b01e57SJeff Chen 		rcu_read_unlock();
394*73b01e57SJeff Chen 	}
395*73b01e57SJeff Chen 
396*73b01e57SJeff Chen 	if (!priv->ap_11n_enabled ||
397*73b01e57SJeff Chen 	    (!nxpwifi_11n_get_rx_reorder_tbl(priv, uap_rx_pd->priority, ta) &&
398*73b01e57SJeff Chen 	    (le16_to_cpu(uap_rx_pd->rx_pkt_type) != PKT_TYPE_AMSDU))) {
399*73b01e57SJeff Chen 		ret = nxpwifi_handle_uap_rx_forward(priv, skb);
400*73b01e57SJeff Chen 		return ret;
401*73b01e57SJeff Chen 	}
402*73b01e57SJeff Chen 
403*73b01e57SJeff Chen 	/* Reorder and send to kernel */
404*73b01e57SJeff Chen 	pkt_type = (u8)le16_to_cpu(uap_rx_pd->rx_pkt_type);
405*73b01e57SJeff Chen 	ret = nxpwifi_11n_rx_reorder_pkt(priv, le16_to_cpu(uap_rx_pd->seq_num),
406*73b01e57SJeff Chen 					 uap_rx_pd->priority, ta, pkt_type, skb);
407*73b01e57SJeff Chen 
408*73b01e57SJeff Chen 	if (ret || rx_pkt_type == PKT_TYPE_BAR)
409*73b01e57SJeff Chen 		dev_kfree_skb_any(skb);
410*73b01e57SJeff Chen 
411*73b01e57SJeff Chen 	if (ret)
412*73b01e57SJeff Chen 		priv->stats.rx_dropped++;
413*73b01e57SJeff Chen 
414*73b01e57SJeff Chen 	return ret;
415*73b01e57SJeff Chen }
416*73b01e57SJeff Chen 
417*73b01e57SJeff Chen /*
418*73b01e57SJeff Chen  * Build TxPD for AP TX: push aligned TxPD; set bss, len/off, prio, delay, txctl,
419*73b01e57SJeff Chen  * flags.
420*73b01e57SJeff Chen  */
nxpwifi_process_uap_txpd(struct nxpwifi_private * priv,struct sk_buff * skb)421*73b01e57SJeff Chen void nxpwifi_process_uap_txpd(struct nxpwifi_private *priv,
422*73b01e57SJeff Chen 			      struct sk_buff *skb)
423*73b01e57SJeff Chen {
424*73b01e57SJeff Chen 	struct nxpwifi_adapter *adapter = priv->adapter;
425*73b01e57SJeff Chen 	struct uap_txpd *txpd;
426*73b01e57SJeff Chen 	struct nxpwifi_txinfo *tx_info = NXPWIFI_SKB_TXCB(skb);
427*73b01e57SJeff Chen 	int pad;
428*73b01e57SJeff Chen 	u16 pkt_type, pkt_offset;
429*73b01e57SJeff Chen 	int hroom = adapter->intf_hdr_len;
430*73b01e57SJeff Chen 
431*73b01e57SJeff Chen 	pkt_type = nxpwifi_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
432*73b01e57SJeff Chen 
433*73b01e57SJeff Chen 	pad = ((uintptr_t)skb->data - (sizeof(*txpd) + hroom)) &
434*73b01e57SJeff Chen 	       (NXPWIFI_DMA_ALIGN_SZ - 1);
435*73b01e57SJeff Chen 
436*73b01e57SJeff Chen 	skb_push(skb, sizeof(*txpd) + pad);
437*73b01e57SJeff Chen 
438*73b01e57SJeff Chen 	txpd = (struct uap_txpd *)skb->data;
439*73b01e57SJeff Chen 	memset(txpd, 0, sizeof(*txpd));
440*73b01e57SJeff Chen 	txpd->bss_num = priv->bss_num;
441*73b01e57SJeff Chen 	txpd->bss_type = priv->bss_type;
442*73b01e57SJeff Chen 	txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - (sizeof(*txpd) +
443*73b01e57SJeff Chen 						pad)));
444*73b01e57SJeff Chen 	txpd->priority = (u8)skb->priority;
445*73b01e57SJeff Chen 
446*73b01e57SJeff Chen 	txpd->pkt_delay_2ms = nxpwifi_wmm_compute_drv_pkt_delay(priv, skb);
447*73b01e57SJeff Chen 
448*73b01e57SJeff Chen 	if (tx_info->flags & NXPWIFI_BUF_FLAG_EAPOL_TX_STATUS ||
449*73b01e57SJeff Chen 	    tx_info->flags & NXPWIFI_BUF_FLAG_ACTION_TX_STATUS) {
450*73b01e57SJeff Chen 		txpd->tx_token_id = tx_info->ack_frame_id;
451*73b01e57SJeff Chen 		txpd->flags |= NXPWIFI_TXPD_FLAGS_REQ_TX_STATUS;
452*73b01e57SJeff Chen 	}
453*73b01e57SJeff Chen 
454*73b01e57SJeff Chen 	if (txpd->priority < ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
455*73b01e57SJeff Chen 		/*
456*73b01e57SJeff Chen 		 * Set the priority specific tx_control field, setting of 0 will
457*73b01e57SJeff Chen 		 * cause the default value to be used later in this function.
458*73b01e57SJeff Chen 		 */
459*73b01e57SJeff Chen 		txpd->tx_control =
460*73b01e57SJeff Chen 		    cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[txpd->priority]);
461*73b01e57SJeff Chen 
462*73b01e57SJeff Chen 	/* Offset of actual data */
463*73b01e57SJeff Chen 	pkt_offset = sizeof(*txpd) + pad;
464*73b01e57SJeff Chen 	if (pkt_type == PKT_TYPE_MGMT) {
465*73b01e57SJeff Chen 		/* Set the packet type and add header for management frame */
466*73b01e57SJeff Chen 		txpd->tx_pkt_type = cpu_to_le16(pkt_type);
467*73b01e57SJeff Chen 		pkt_offset += NXPWIFI_MGMT_FRAME_HEADER_SIZE;
468*73b01e57SJeff Chen 	}
469*73b01e57SJeff Chen 
470*73b01e57SJeff Chen 	txpd->tx_pkt_offset = cpu_to_le16(pkt_offset);
471*73b01e57SJeff Chen 
472*73b01e57SJeff Chen 	/* make space for adapter->intf_hdr_len */
473*73b01e57SJeff Chen 	skb_push(skb, hroom);
474*73b01e57SJeff Chen 
475*73b01e57SJeff Chen 	if (!txpd->tx_control)
476*73b01e57SJeff Chen 		/* TxCtrl set by user or default */
477*73b01e57SJeff Chen 		txpd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
478*73b01e57SJeff Chen }
479