xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/marvell/mwifiex/txrx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * NXP Wireless LAN device driver: generic TX/RX data handling
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright 2011-2020 NXP
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This software file (the "File") is distributed by NXP
7*4882a593Smuzhiyun  * under the terms of the GNU General Public License Version 2, June 1991
8*4882a593Smuzhiyun  * (the "License").  You may use, redistribute and/or modify this File in
9*4882a593Smuzhiyun  * accordance with the terms and conditions of the License, a copy of which
10*4882a593Smuzhiyun  * is available by writing to the Free Software Foundation, Inc.,
11*4882a593Smuzhiyun  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
12*4882a593Smuzhiyun  * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
15*4882a593Smuzhiyun  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
16*4882a593Smuzhiyun  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
17*4882a593Smuzhiyun  * this warranty disclaimer.
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "decl.h"
21*4882a593Smuzhiyun #include "ioctl.h"
22*4882a593Smuzhiyun #include "util.h"
23*4882a593Smuzhiyun #include "fw.h"
24*4882a593Smuzhiyun #include "main.h"
25*4882a593Smuzhiyun #include "wmm.h"
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun  * This function processes the received buffer.
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  * Main responsibility of this function is to parse the RxPD to
31*4882a593Smuzhiyun  * identify the correct interface this packet is headed for and
32*4882a593Smuzhiyun  * forwarding it to the associated handling function, where the
33*4882a593Smuzhiyun  * packet will be further processed and sent to kernel/upper layer
34*4882a593Smuzhiyun  * if required.
35*4882a593Smuzhiyun  */
mwifiex_handle_rx_packet(struct mwifiex_adapter * adapter,struct sk_buff * skb)36*4882a593Smuzhiyun int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
37*4882a593Smuzhiyun 			     struct sk_buff *skb)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	struct mwifiex_private *priv =
40*4882a593Smuzhiyun 		mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
41*4882a593Smuzhiyun 	struct rxpd *local_rx_pd;
42*4882a593Smuzhiyun 	struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
43*4882a593Smuzhiyun 	int ret;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	local_rx_pd = (struct rxpd *) (skb->data);
46*4882a593Smuzhiyun 	/* Get the BSS number from rxpd, get corresponding priv */
47*4882a593Smuzhiyun 	priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num &
48*4882a593Smuzhiyun 				      BSS_NUM_MASK, local_rx_pd->bss_type);
49*4882a593Smuzhiyun 	if (!priv)
50*4882a593Smuzhiyun 		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	if (!priv) {
53*4882a593Smuzhiyun 		mwifiex_dbg(adapter, ERROR,
54*4882a593Smuzhiyun 			    "data: priv not found. Drop RX packet\n");
55*4882a593Smuzhiyun 		dev_kfree_skb_any(skb);
56*4882a593Smuzhiyun 		return -1;
57*4882a593Smuzhiyun 	}
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	mwifiex_dbg_dump(adapter, DAT_D, "rx pkt:", skb->data,
60*4882a593Smuzhiyun 			 min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	memset(rx_info, 0, sizeof(*rx_info));
63*4882a593Smuzhiyun 	rx_info->bss_num = priv->bss_num;
64*4882a593Smuzhiyun 	rx_info->bss_type = priv->bss_type;
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
67*4882a593Smuzhiyun 		ret = mwifiex_process_uap_rx_packet(priv, skb);
68*4882a593Smuzhiyun 	else
69*4882a593Smuzhiyun 		ret = mwifiex_process_sta_rx_packet(priv, skb);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	return ret;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun /*
76*4882a593Smuzhiyun  * This function sends a packet to device.
77*4882a593Smuzhiyun  *
78*4882a593Smuzhiyun  * It processes the packet to add the TxPD, checks condition and
79*4882a593Smuzhiyun  * sends the processed packet to firmware for transmission.
80*4882a593Smuzhiyun  *
81*4882a593Smuzhiyun  * On successful completion, the function calls the completion callback
82*4882a593Smuzhiyun  * and logs the time.
83*4882a593Smuzhiyun  */
mwifiex_process_tx(struct mwifiex_private * priv,struct sk_buff * skb,struct mwifiex_tx_param * tx_param)84*4882a593Smuzhiyun int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
85*4882a593Smuzhiyun 		       struct mwifiex_tx_param *tx_param)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	int hroom, ret = -1;
88*4882a593Smuzhiyun 	struct mwifiex_adapter *adapter = priv->adapter;
89*4882a593Smuzhiyun 	u8 *head_ptr;
90*4882a593Smuzhiyun 	struct txpd *local_tx_pd = NULL;
91*4882a593Smuzhiyun 	struct mwifiex_sta_node *dest_node;
92*4882a593Smuzhiyun 	struct ethhdr *hdr = (void *)skb->data;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	hroom = adapter->intf_hdr_len;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
97*4882a593Smuzhiyun 		dest_node = mwifiex_get_sta_entry(priv, hdr->h_dest);
98*4882a593Smuzhiyun 		if (dest_node) {
99*4882a593Smuzhiyun 			dest_node->stats.tx_bytes += skb->len;
100*4882a593Smuzhiyun 			dest_node->stats.tx_packets++;
101*4882a593Smuzhiyun 		}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 		head_ptr = mwifiex_process_uap_txpd(priv, skb);
104*4882a593Smuzhiyun 	} else {
105*4882a593Smuzhiyun 		head_ptr = mwifiex_process_sta_txpd(priv, skb);
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	if ((adapter->data_sent || adapter->tx_lock_flag) && head_ptr) {
109*4882a593Smuzhiyun 		skb_queue_tail(&adapter->tx_data_q, skb);
110*4882a593Smuzhiyun 		atomic_inc(&adapter->tx_queued);
111*4882a593Smuzhiyun 		return 0;
112*4882a593Smuzhiyun 	}
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	if (head_ptr) {
115*4882a593Smuzhiyun 		if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
116*4882a593Smuzhiyun 			local_tx_pd = (struct txpd *)(head_ptr + hroom);
117*4882a593Smuzhiyun 		if (adapter->iface_type == MWIFIEX_USB) {
118*4882a593Smuzhiyun 			ret = adapter->if_ops.host_to_card(adapter,
119*4882a593Smuzhiyun 							   priv->usb_port,
120*4882a593Smuzhiyun 							   skb, tx_param);
121*4882a593Smuzhiyun 		} else {
122*4882a593Smuzhiyun 			ret = adapter->if_ops.host_to_card(adapter,
123*4882a593Smuzhiyun 							   MWIFIEX_TYPE_DATA,
124*4882a593Smuzhiyun 							   skb, tx_param);
125*4882a593Smuzhiyun 		}
126*4882a593Smuzhiyun 	}
127*4882a593Smuzhiyun 	mwifiex_dbg_dump(adapter, DAT_D, "tx pkt:", skb->data,
128*4882a593Smuzhiyun 			 min_t(size_t, skb->len, DEBUG_DUMP_DATA_MAX_LEN));
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	switch (ret) {
131*4882a593Smuzhiyun 	case -ENOSR:
132*4882a593Smuzhiyun 		mwifiex_dbg(adapter, DATA, "data: -ENOSR is returned\n");
133*4882a593Smuzhiyun 		break;
134*4882a593Smuzhiyun 	case -EBUSY:
135*4882a593Smuzhiyun 		if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
136*4882a593Smuzhiyun 		    (adapter->pps_uapsd_mode) && (adapter->tx_lock_flag)) {
137*4882a593Smuzhiyun 				priv->adapter->tx_lock_flag = false;
138*4882a593Smuzhiyun 				if (local_tx_pd)
139*4882a593Smuzhiyun 					local_tx_pd->flags = 0;
140*4882a593Smuzhiyun 		}
141*4882a593Smuzhiyun 		mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
142*4882a593Smuzhiyun 		break;
143*4882a593Smuzhiyun 	case -1:
144*4882a593Smuzhiyun 		mwifiex_dbg(adapter, ERROR,
145*4882a593Smuzhiyun 			    "mwifiex_write_data_async failed: 0x%X\n",
146*4882a593Smuzhiyun 			    ret);
147*4882a593Smuzhiyun 		adapter->dbg.num_tx_host_to_card_failure++;
148*4882a593Smuzhiyun 		mwifiex_write_data_complete(adapter, skb, 0, ret);
149*4882a593Smuzhiyun 		break;
150*4882a593Smuzhiyun 	case -EINPROGRESS:
151*4882a593Smuzhiyun 		break;
152*4882a593Smuzhiyun 	case 0:
153*4882a593Smuzhiyun 		mwifiex_write_data_complete(adapter, skb, 0, ret);
154*4882a593Smuzhiyun 		break;
155*4882a593Smuzhiyun 	default:
156*4882a593Smuzhiyun 		break;
157*4882a593Smuzhiyun 	}
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	return ret;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
mwifiex_host_to_card(struct mwifiex_adapter * adapter,struct sk_buff * skb,struct mwifiex_tx_param * tx_param)162*4882a593Smuzhiyun static int mwifiex_host_to_card(struct mwifiex_adapter *adapter,
163*4882a593Smuzhiyun 				struct sk_buff *skb,
164*4882a593Smuzhiyun 				struct mwifiex_tx_param *tx_param)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	struct txpd *local_tx_pd = NULL;
167*4882a593Smuzhiyun 	u8 *head_ptr = skb->data;
168*4882a593Smuzhiyun 	int ret = 0;
169*4882a593Smuzhiyun 	struct mwifiex_private *priv;
170*4882a593Smuzhiyun 	struct mwifiex_txinfo *tx_info;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	tx_info = MWIFIEX_SKB_TXCB(skb);
173*4882a593Smuzhiyun 	priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
174*4882a593Smuzhiyun 				      tx_info->bss_type);
175*4882a593Smuzhiyun 	if (!priv) {
176*4882a593Smuzhiyun 		mwifiex_dbg(adapter, ERROR,
177*4882a593Smuzhiyun 			    "data: priv not found. Drop TX packet\n");
178*4882a593Smuzhiyun 		adapter->dbg.num_tx_host_to_card_failure++;
179*4882a593Smuzhiyun 		mwifiex_write_data_complete(adapter, skb, 0, 0);
180*4882a593Smuzhiyun 		return ret;
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 	if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
183*4882a593Smuzhiyun 		local_tx_pd = (struct txpd *)(head_ptr + adapter->intf_hdr_len);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (adapter->iface_type == MWIFIEX_USB) {
186*4882a593Smuzhiyun 		ret = adapter->if_ops.host_to_card(adapter,
187*4882a593Smuzhiyun 						   priv->usb_port,
188*4882a593Smuzhiyun 						   skb, tx_param);
189*4882a593Smuzhiyun 	} else {
190*4882a593Smuzhiyun 		ret = adapter->if_ops.host_to_card(adapter,
191*4882a593Smuzhiyun 						   MWIFIEX_TYPE_DATA,
192*4882a593Smuzhiyun 						   skb, tx_param);
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 	switch (ret) {
195*4882a593Smuzhiyun 	case -ENOSR:
196*4882a593Smuzhiyun 		mwifiex_dbg(adapter, ERROR, "data: -ENOSR is returned\n");
197*4882a593Smuzhiyun 		break;
198*4882a593Smuzhiyun 	case -EBUSY:
199*4882a593Smuzhiyun 		if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
200*4882a593Smuzhiyun 		    (adapter->pps_uapsd_mode) &&
201*4882a593Smuzhiyun 		    (adapter->tx_lock_flag)) {
202*4882a593Smuzhiyun 			priv->adapter->tx_lock_flag = false;
203*4882a593Smuzhiyun 			if (local_tx_pd)
204*4882a593Smuzhiyun 				local_tx_pd->flags = 0;
205*4882a593Smuzhiyun 		}
206*4882a593Smuzhiyun 		skb_queue_head(&adapter->tx_data_q, skb);
207*4882a593Smuzhiyun 		if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
208*4882a593Smuzhiyun 			atomic_add(tx_info->aggr_num, &adapter->tx_queued);
209*4882a593Smuzhiyun 		else
210*4882a593Smuzhiyun 			atomic_inc(&adapter->tx_queued);
211*4882a593Smuzhiyun 		mwifiex_dbg(adapter, ERROR, "data: -EBUSY is returned\n");
212*4882a593Smuzhiyun 		break;
213*4882a593Smuzhiyun 	case -1:
214*4882a593Smuzhiyun 		mwifiex_dbg(adapter, ERROR,
215*4882a593Smuzhiyun 			    "mwifiex_write_data_async failed: 0x%X\n", ret);
216*4882a593Smuzhiyun 		adapter->dbg.num_tx_host_to_card_failure++;
217*4882a593Smuzhiyun 		mwifiex_write_data_complete(adapter, skb, 0, ret);
218*4882a593Smuzhiyun 		break;
219*4882a593Smuzhiyun 	case -EINPROGRESS:
220*4882a593Smuzhiyun 		break;
221*4882a593Smuzhiyun 	case 0:
222*4882a593Smuzhiyun 		mwifiex_write_data_complete(adapter, skb, 0, ret);
223*4882a593Smuzhiyun 		break;
224*4882a593Smuzhiyun 	default:
225*4882a593Smuzhiyun 		break;
226*4882a593Smuzhiyun 	}
227*4882a593Smuzhiyun 	return ret;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun static int
mwifiex_dequeue_tx_queue(struct mwifiex_adapter * adapter)231*4882a593Smuzhiyun mwifiex_dequeue_tx_queue(struct mwifiex_adapter *adapter)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct sk_buff *skb, *skb_next;
234*4882a593Smuzhiyun 	struct mwifiex_txinfo *tx_info;
235*4882a593Smuzhiyun 	struct mwifiex_tx_param tx_param;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	skb = skb_dequeue(&adapter->tx_data_q);
238*4882a593Smuzhiyun 	if (!skb)
239*4882a593Smuzhiyun 		return -1;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	tx_info = MWIFIEX_SKB_TXCB(skb);
242*4882a593Smuzhiyun 	if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
243*4882a593Smuzhiyun 		atomic_sub(tx_info->aggr_num, &adapter->tx_queued);
244*4882a593Smuzhiyun 	else
245*4882a593Smuzhiyun 		atomic_dec(&adapter->tx_queued);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	if (!skb_queue_empty(&adapter->tx_data_q))
248*4882a593Smuzhiyun 		skb_next = skb_peek(&adapter->tx_data_q);
249*4882a593Smuzhiyun 	else
250*4882a593Smuzhiyun 		skb_next = NULL;
251*4882a593Smuzhiyun 	tx_param.next_pkt_len = ((skb_next) ? skb_next->len : 0);
252*4882a593Smuzhiyun 	if (!tx_param.next_pkt_len) {
253*4882a593Smuzhiyun 		if (!mwifiex_wmm_lists_empty(adapter))
254*4882a593Smuzhiyun 			tx_param.next_pkt_len = 1;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 	return mwifiex_host_to_card(adapter, skb, &tx_param);
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun void
mwifiex_process_tx_queue(struct mwifiex_adapter * adapter)260*4882a593Smuzhiyun mwifiex_process_tx_queue(struct mwifiex_adapter *adapter)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun 	do {
263*4882a593Smuzhiyun 		if (adapter->data_sent || adapter->tx_lock_flag)
264*4882a593Smuzhiyun 			break;
265*4882a593Smuzhiyun 		if (mwifiex_dequeue_tx_queue(adapter))
266*4882a593Smuzhiyun 			break;
267*4882a593Smuzhiyun 	} while (!skb_queue_empty(&adapter->tx_data_q));
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun /*
271*4882a593Smuzhiyun  * Packet send completion callback handler.
272*4882a593Smuzhiyun  *
273*4882a593Smuzhiyun  * It either frees the buffer directly or forwards it to another
274*4882a593Smuzhiyun  * completion callback which checks conditions, updates statistics,
275*4882a593Smuzhiyun  * wakes up stalled traffic queue if required, and then frees the buffer.
276*4882a593Smuzhiyun  */
mwifiex_write_data_complete(struct mwifiex_adapter * adapter,struct sk_buff * skb,int aggr,int status)277*4882a593Smuzhiyun int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
278*4882a593Smuzhiyun 				struct sk_buff *skb, int aggr, int status)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	struct mwifiex_private *priv;
281*4882a593Smuzhiyun 	struct mwifiex_txinfo *tx_info;
282*4882a593Smuzhiyun 	struct netdev_queue *txq;
283*4882a593Smuzhiyun 	int index;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	if (!skb)
286*4882a593Smuzhiyun 		return 0;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	tx_info = MWIFIEX_SKB_TXCB(skb);
289*4882a593Smuzhiyun 	priv = mwifiex_get_priv_by_id(adapter, tx_info->bss_num,
290*4882a593Smuzhiyun 				      tx_info->bss_type);
291*4882a593Smuzhiyun 	if (!priv)
292*4882a593Smuzhiyun 		goto done;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	mwifiex_set_trans_start(priv->netdev);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
297*4882a593Smuzhiyun 		atomic_dec_return(&adapter->pending_bridged_pkts);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
300*4882a593Smuzhiyun 		goto done;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	if (!status) {
303*4882a593Smuzhiyun 		priv->stats.tx_packets++;
304*4882a593Smuzhiyun 		priv->stats.tx_bytes += tx_info->pkt_len;
305*4882a593Smuzhiyun 		if (priv->tx_timeout_cnt)
306*4882a593Smuzhiyun 			priv->tx_timeout_cnt = 0;
307*4882a593Smuzhiyun 	} else {
308*4882a593Smuzhiyun 		priv->stats.tx_errors++;
309*4882a593Smuzhiyun 	}
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	if (aggr)
312*4882a593Smuzhiyun 		/* For skb_aggr, do not wake up tx queue */
313*4882a593Smuzhiyun 		goto done;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	atomic_dec(&adapter->tx_pending);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	index = mwifiex_1d_to_wmm_queue[skb->priority];
318*4882a593Smuzhiyun 	if (atomic_dec_return(&priv->wmm_tx_pending[index]) < LOW_TX_PENDING) {
319*4882a593Smuzhiyun 		txq = netdev_get_tx_queue(priv->netdev, index);
320*4882a593Smuzhiyun 		if (netif_tx_queue_stopped(txq)) {
321*4882a593Smuzhiyun 			netif_tx_wake_queue(txq);
322*4882a593Smuzhiyun 			mwifiex_dbg(adapter, DATA, "wake queue: %d\n", index);
323*4882a593Smuzhiyun 		}
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun done:
326*4882a593Smuzhiyun 	dev_kfree_skb_any(skb);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	return 0;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mwifiex_write_data_complete);
331*4882a593Smuzhiyun 
mwifiex_parse_tx_status_event(struct mwifiex_private * priv,void * event_body)332*4882a593Smuzhiyun void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
333*4882a593Smuzhiyun 				   void *event_body)
334*4882a593Smuzhiyun {
335*4882a593Smuzhiyun 	struct tx_status_event *tx_status = (void *)priv->adapter->event_body;
336*4882a593Smuzhiyun 	struct sk_buff *ack_skb;
337*4882a593Smuzhiyun 	struct mwifiex_txinfo *tx_info;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (!tx_status->tx_token_id)
340*4882a593Smuzhiyun 		return;
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	spin_lock_bh(&priv->ack_status_lock);
343*4882a593Smuzhiyun 	ack_skb = idr_remove(&priv->ack_status_frames, tx_status->tx_token_id);
344*4882a593Smuzhiyun 	spin_unlock_bh(&priv->ack_status_lock);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	if (ack_skb) {
347*4882a593Smuzhiyun 		tx_info = MWIFIEX_SKB_TXCB(ack_skb);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 		if (tx_info->flags & MWIFIEX_BUF_FLAG_EAPOL_TX_STATUS) {
350*4882a593Smuzhiyun 			/* consumes ack_skb */
351*4882a593Smuzhiyun 			skb_complete_wifi_ack(ack_skb, !tx_status->status);
352*4882a593Smuzhiyun 		} else {
353*4882a593Smuzhiyun 			/* Remove broadcast address which was added by driver */
354*4882a593Smuzhiyun 			memmove(ack_skb->data +
355*4882a593Smuzhiyun 				sizeof(struct ieee80211_hdr_3addr) +
356*4882a593Smuzhiyun 				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16),
357*4882a593Smuzhiyun 				ack_skb->data +
358*4882a593Smuzhiyun 				sizeof(struct ieee80211_hdr_3addr) +
359*4882a593Smuzhiyun 				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) +
360*4882a593Smuzhiyun 				ETH_ALEN, ack_skb->len -
361*4882a593Smuzhiyun 				(sizeof(struct ieee80211_hdr_3addr) +
362*4882a593Smuzhiyun 				MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) +
363*4882a593Smuzhiyun 				ETH_ALEN));
364*4882a593Smuzhiyun 			ack_skb->len = ack_skb->len - ETH_ALEN;
365*4882a593Smuzhiyun 			/* Remove driver's proprietary header including 2 bytes
366*4882a593Smuzhiyun 			 * of packet length and pass actual management frame buffer
367*4882a593Smuzhiyun 			 * to cfg80211.
368*4882a593Smuzhiyun 			 */
369*4882a593Smuzhiyun 			cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie,
370*4882a593Smuzhiyun 						ack_skb->data +
371*4882a593Smuzhiyun 						MWIFIEX_MGMT_FRAME_HEADER_SIZE +
372*4882a593Smuzhiyun 						sizeof(u16), ack_skb->len -
373*4882a593Smuzhiyun 						(MWIFIEX_MGMT_FRAME_HEADER_SIZE
374*4882a593Smuzhiyun 						 + sizeof(u16)),
375*4882a593Smuzhiyun 						!tx_status->status, GFP_ATOMIC);
376*4882a593Smuzhiyun 			dev_kfree_skb_any(ack_skb);
377*4882a593Smuzhiyun 		}
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun }
380