1 /**
2 * @file mlan_txrx.c
3 *
4 * @brief This file contains the handling of TX/RX in MLAN
5 *
6 *
7 * Copyright 2009-2021 NXP
8 *
9 * This software file (the File) is distributed by NXP
10 * under the terms of the GNU General Public License Version 2, June 1991
11 * (the License). You may use, redistribute and/or modify the File in
12 * accordance with the terms and conditions of the License, a copy of which
13 * is available by writing to the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
15 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
16 *
17 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
19 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
20 * this warranty disclaimer.
21 *
22 */
23
24 /*************************************************************
25 Change Log:
26 05/11/2009: initial version
27 ************************************************************/
28
29 #include "mlan.h"
30 #ifdef STA_SUPPORT
31 #include "mlan_join.h"
32 #endif
33 #include "mlan_util.h"
34 #include "mlan_fw.h"
35 #include "mlan_main.h"
36 #include "mlan_wmm.h"
37
38 /********************************************************
39 Local Variables
40 ********************************************************/
41
42 /********************************************************
43 Global Variables
44 ********************************************************/
45
46 /********************************************************
47 Local Functions
48 ********************************************************/
49
50 /********************************************************
51 Global Functions
52 ********************************************************/
53 /**
54 * @brief This function processes the received buffer
55 *
56 * @param pmadapter A pointer to mlan_adapter
57 * @param pmbuf A pointer to the received buffer
58 *
59 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
60 */
wlan_handle_rx_packet(pmlan_adapter pmadapter,pmlan_buffer pmbuf)61 mlan_status wlan_handle_rx_packet(pmlan_adapter pmadapter, pmlan_buffer pmbuf)
62 {
63 mlan_status ret = MLAN_STATUS_SUCCESS;
64 pmlan_private priv = MNULL;
65 RxPD *prx_pd;
66 #ifdef DEBUG_LEVEL1
67 t_u32 sec = 0, usec = 0;
68 #endif
69
70 ENTER();
71
72 prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
73 /* Get the BSS number from RxPD, get corresponding priv */
74 priv = wlan_get_priv_by_id(pmadapter, prx_pd->bss_num & BSS_NUM_MASK,
75 prx_pd->bss_type);
76 if (!priv)
77 priv = wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY);
78 if (!priv) {
79 ret = MLAN_STATUS_FAILURE;
80 goto done;
81 }
82 pmbuf->bss_index = priv->bss_index;
83 PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
84 PRINTM_NETINTF(MDATA, priv);
85 PRINTM(MDATA, "%lu.%06lu : Data <= FW\n", sec, usec);
86 ret = priv->ops.process_rx_packet(pmadapter, pmbuf);
87
88 done:
89 LEAVE();
90 return ret;
91 }
92
93 /**
94 * @brief This function checks the conditions and sends packet to device
95 *
96 * @param priv A pointer to mlan_private structure
97 * @param pmbuf A pointer to the mlan_buffer for process
98 * @param tx_param A pointer to mlan_tx_param structure
99 *
100 * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise
101 * failure
102 */
wlan_process_tx(pmlan_private priv,pmlan_buffer pmbuf,mlan_tx_param * tx_param)103 mlan_status wlan_process_tx(pmlan_private priv, pmlan_buffer pmbuf,
104 mlan_tx_param *tx_param)
105 {
106 mlan_status ret = MLAN_STATUS_SUCCESS;
107 pmlan_adapter pmadapter = priv->adapter;
108 t_u8 *head_ptr = MNULL;
109 #ifdef DEBUG_LEVEL1
110 t_u32 sec = 0, usec = 0;
111 #endif
112 #ifdef STA_SUPPORT
113 PTxPD plocal_tx_pd = MNULL;
114 #endif
115
116 ENTER();
117 head_ptr = (t_u8 *)priv->ops.process_txpd(priv, pmbuf);
118 if (!head_ptr) {
119 pmbuf->status_code = MLAN_ERROR_PKT_INVALID;
120 ret = MLAN_STATUS_FAILURE;
121 goto done;
122 }
123 #ifdef STA_SUPPORT
124 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA)
125 plocal_tx_pd = (TxPD *)(head_ptr + priv->intf_hr_len);
126 #endif
127 if (pmadapter->tp_state_on)
128 pmadapter->callbacks.moal_tp_accounting(pmadapter->pmoal_handle,
129 pmbuf, 4);
130 if (pmadapter->tp_state_drop_point == 4)
131 goto done;
132 else {
133 ret = pmadapter->ops.host_to_card(priv, MLAN_TYPE_DATA, pmbuf,
134 tx_param);
135 }
136 done:
137 switch (ret) {
138 #ifdef USB
139 case MLAN_STATUS_PRESOURCE:
140 PRINTM(MINFO, "MLAN_STATUS_PRESOURCE is returned\n");
141 DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
142 MIN(pmbuf->data_len + sizeof(TxPD),
143 MAX_DATA_DUMP_LEN));
144 break;
145 #endif
146 case MLAN_STATUS_RESOURCE:
147 #ifdef STA_SUPPORT
148 if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
149 pmadapter->pps_uapsd_mode &&
150 (pmadapter->tx_lock_flag == MTRUE)) {
151 pmadapter->tx_lock_flag = MFALSE;
152 if (plocal_tx_pd != MNULL)
153 plocal_tx_pd->flags = 0;
154 }
155 #endif
156 PRINTM(MINFO, "MLAN_STATUS_RESOURCE is returned\n");
157 break;
158 case MLAN_STATUS_FAILURE:
159 pmadapter->dbg.num_tx_host_to_card_failure++;
160 pmbuf->status_code = MLAN_ERROR_DATA_TX_FAIL;
161 wlan_write_data_complete(pmadapter, pmbuf, ret);
162 break;
163 case MLAN_STATUS_PENDING:
164 DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
165 MIN(pmbuf->data_len + sizeof(TxPD),
166 MAX_DATA_DUMP_LEN));
167 break;
168 case MLAN_STATUS_SUCCESS:
169 DBG_HEXDUMP(MDAT_D, "Tx", head_ptr + priv->intf_hr_len,
170 MIN(pmbuf->data_len + sizeof(TxPD),
171 MAX_DATA_DUMP_LEN));
172 wlan_write_data_complete(pmadapter, pmbuf, ret);
173 break;
174 default:
175 break;
176 }
177
178 if ((ret == MLAN_STATUS_SUCCESS) || (ret == MLAN_STATUS_PENDING)) {
179 PRINTM_GET_SYS_TIME(MDATA, &sec, &usec);
180 PRINTM_NETINTF(MDATA, priv);
181 PRINTM(MDATA, "%lu.%06lu : Data => FW\n", sec, usec);
182 }
183 LEAVE();
184 return ret;
185 }
186
187 /**
188 * @brief Packet send completion handling
189 *
190 * @param pmadapter A pointer to mlan_adapter structure
191 * @param pmbuf A pointer to mlan_buffer structure
192 * @param status Callback status
193 *
194 * @return MLAN_STATUS_SUCCESS
195 */
wlan_write_data_complete(pmlan_adapter pmadapter,pmlan_buffer pmbuf,mlan_status status)196 mlan_status wlan_write_data_complete(pmlan_adapter pmadapter,
197 pmlan_buffer pmbuf, mlan_status status)
198 {
199 mlan_status ret = MLAN_STATUS_SUCCESS;
200 pmlan_callbacks pcb;
201
202 ENTER();
203
204 MASSERT(pmadapter && pmbuf);
205 if (!pmadapter || !pmbuf) {
206 LEAVE();
207 return MLAN_STATUS_FAILURE;
208 }
209
210 pcb = &pmadapter->callbacks;
211
212 if ((pmbuf->buf_type == MLAN_BUF_TYPE_DATA) ||
213 (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)) {
214 PRINTM(MINFO, "wlan_write_data_complete: DATA %p\n", pmbuf);
215 #if defined(USB)
216 if ((pmbuf->flags & MLAN_BUF_FLAG_USB_TX_AGGR) &&
217 pmbuf->use_count) {
218 pmlan_buffer pmbuf_next;
219 t_u32 i, use_count = pmbuf->use_count;
220 for (i = 0; i <= use_count; i++) {
221 pmbuf_next = pmbuf->pnext;
222 if (pmbuf->flags & MLAN_BUF_FLAG_MOAL_TX_BUF)
223 pcb->moal_send_packet_complete(
224 pmadapter->pmoal_handle, pmbuf,
225 status);
226 else
227 wlan_free_mlan_buffer(pmadapter, pmbuf);
228 pmbuf = pmbuf_next;
229 }
230 } else {
231 #endif
232 if (pmbuf->flags & MLAN_BUF_FLAG_MOAL_TX_BUF) {
233 /* pmbuf was allocated by MOAL */
234 pcb->moal_send_packet_complete(
235 pmadapter->pmoal_handle, pmbuf, status);
236 } else {
237 /* pmbuf was allocated by MLAN */
238 wlan_free_mlan_buffer(pmadapter, pmbuf);
239 }
240 #if defined(USB)
241 }
242 #endif
243 }
244
245 LEAVE();
246 return ret;
247 }
248
249 /**
250 * @brief Packet receive completion callback handler
251 *
252 * @param pmadapter A pointer to mlan_adapter structure
253 * @param pmbuf A pointer to mlan_buffer structure
254 * @param status Callback status
255 *
256 * @return MLAN_STATUS_SUCCESS
257 */
wlan_recv_packet_complete(pmlan_adapter pmadapter,pmlan_buffer pmbuf,mlan_status status)258 mlan_status wlan_recv_packet_complete(pmlan_adapter pmadapter,
259 pmlan_buffer pmbuf, mlan_status status)
260 {
261 mlan_status ret = MLAN_STATUS_SUCCESS;
262
263 ENTER();
264
265 MASSERT(pmadapter && pmbuf);
266 if (!pmadapter || !pmbuf) {
267 LEAVE();
268 return MLAN_STATUS_FAILURE;
269 }
270
271 MASSERT(pmbuf->bss_index < pmadapter->priv_num);
272
273 if (pmbuf->pparent) {
274 /** we will free the pparaent at the end of deaggr */
275 wlan_free_mlan_buffer(pmadapter, pmbuf);
276 } else {
277 pmadapter->ops.data_complete(pmadapter, pmbuf, status);
278 }
279
280 LEAVE();
281 return ret;
282 }
283
284 /**
285 * @brief Add packet to Bypass TX queue
286 *
287 * @param pmadapter Pointer to the mlan_adapter driver data struct
288 * @param pmbuf Pointer to the mlan_buffer data struct
289 *
290 * @return N/A
291 */
wlan_add_buf_bypass_txqueue(mlan_adapter * pmadapter,pmlan_buffer pmbuf)292 t_void wlan_add_buf_bypass_txqueue(mlan_adapter *pmadapter, pmlan_buffer pmbuf)
293 {
294 pmlan_private priv = pmadapter->priv[pmbuf->bss_index];
295 ENTER();
296
297 if (pmbuf->buf_type != MLAN_BUF_TYPE_RAW_DATA)
298 pmbuf->buf_type = MLAN_BUF_TYPE_DATA;
299 pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
300 priv->bypass_txq.plock);
301 pmadapter->bypass_pkt_count++;
302 util_enqueue_list_tail(pmadapter->pmoal_handle, &priv->bypass_txq,
303 (pmlan_linked_list)pmbuf, MNULL, MNULL);
304 pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
305 priv->bypass_txq.plock);
306 LEAVE();
307 }
308
309 /**
310 * @brief Check if packets are available in Bypass TX queue
311 *
312 * @param pmadapter Pointer to the mlan_adapter driver data struct
313 *
314 * @return MFALSE if not empty; MTRUE if empty
315 */
wlan_bypass_tx_list_empty(mlan_adapter * pmadapter)316 INLINE t_u8 wlan_bypass_tx_list_empty(mlan_adapter *pmadapter)
317 {
318 return (pmadapter->bypass_pkt_count) ? MFALSE : MTRUE;
319 }
320
321 /**
322 * @brief Clean up the By-pass TX queue
323 *
324 * @param priv Pointer to the mlan_private data struct
325 *
326 * @return N/A
327 */
wlan_cleanup_bypass_txq(mlan_private * priv)328 t_void wlan_cleanup_bypass_txq(mlan_private *priv)
329 {
330 pmlan_buffer pmbuf;
331 mlan_adapter *pmadapter = priv->adapter;
332 ENTER();
333 pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
334 priv->bypass_txq.plock);
335 while ((pmbuf = (pmlan_buffer)util_peek_list(pmadapter->pmoal_handle,
336 &priv->bypass_txq, MNULL,
337 MNULL))) {
338 util_unlink_list(pmadapter->pmoal_handle, &priv->bypass_txq,
339 (pmlan_linked_list)pmbuf, MNULL, MNULL);
340 wlan_write_data_complete(pmadapter, pmbuf, MLAN_STATUS_FAILURE);
341 pmadapter->bypass_pkt_count--;
342 }
343 pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
344 priv->bypass_txq.plock);
345 LEAVE();
346 }
347
348 /**
349 * @brief Transmit the By-passed packet awaiting in by-pass queue
350 *
351 * @param pmadapter Pointer to the mlan_adapter driver data struct
352 *
353 * @return N/A
354 */
wlan_process_bypass_tx(pmlan_adapter pmadapter)355 t_void wlan_process_bypass_tx(pmlan_adapter pmadapter)
356 {
357 pmlan_buffer pmbuf;
358 mlan_tx_param tx_param;
359 mlan_status status = MLAN_STATUS_SUCCESS;
360 pmlan_private priv;
361 int j = 0;
362 ENTER();
363 do {
364 for (j = 0; j < pmadapter->priv_num; ++j) {
365 priv = pmadapter->priv[j];
366 if (priv) {
367 pmbuf = (pmlan_buffer)util_dequeue_list(
368 pmadapter->pmoal_handle,
369 &priv->bypass_txq,
370 pmadapter->callbacks.moal_spin_lock,
371 pmadapter->callbacks.moal_spin_unlock);
372 if (pmbuf) {
373 pmadapter->callbacks.moal_spin_lock(
374 pmadapter->pmoal_handle,
375 priv->bypass_txq.plock);
376 pmadapter->bypass_pkt_count--;
377 pmadapter->callbacks.moal_spin_unlock(
378 pmadapter->pmoal_handle,
379 priv->bypass_txq.plock);
380 PRINTM(MINFO,
381 "Dequeuing bypassed packet %p\n",
382 pmbuf);
383 if (wlan_bypass_tx_list_empty(
384 pmadapter))
385 tx_param.next_pkt_len = 0;
386 else
387 tx_param.next_pkt_len =
388 pmbuf->data_len;
389 status = wlan_process_tx(
390 pmadapter->priv[pmbuf->bss_index],
391 pmbuf, &tx_param);
392
393 if (status == MLAN_STATUS_RESOURCE) {
394 /* Queue the packet again so
395 * that it will be TX'ed later
396 */
397 pmadapter->callbacks.moal_spin_lock(
398 pmadapter->pmoal_handle,
399 priv->bypass_txq.plock);
400 pmadapter->bypass_pkt_count++;
401 util_enqueue_list_head(
402 pmadapter->pmoal_handle,
403 &priv->bypass_txq,
404 (pmlan_linked_list)pmbuf,
405 pmadapter->callbacks
406 .moal_spin_lock,
407 pmadapter->callbacks
408 .moal_spin_unlock);
409 pmadapter->callbacks.moal_spin_unlock(
410 pmadapter->pmoal_handle,
411 priv->bypass_txq.plock);
412 }
413 break;
414 } else {
415 PRINTM(MINFO, "Nothing to send\n");
416 }
417 }
418 }
419 } while (!pmadapter->data_sent && !pmadapter->tx_lock_flag &&
420 !wlan_bypass_tx_list_empty(pmadapter));
421 LEAVE();
422 }
423