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