1 /** @file mlan_11n_rxreorder.c
2 *
3 * @brief This file contains the handling of RxReordering in wlan
4 * driver.
5 *
6 *
7 * Copyright 2008-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 11/10/2008: initial version
27 ********************************************************/
28
29 #include "mlan.h"
30 #include "mlan_join.h"
31 #include "mlan_util.h"
32 #include "mlan_fw.h"
33 #include "mlan_main.h"
34 #include "mlan_wmm.h"
35 #include "mlan_11n.h"
36 #include "mlan_11n_rxreorder.h"
37
38 /********************************************************
39 Local Variables
40 ********************************************************/
41
42 /********************************************************
43 Global Variables
44 ********************************************************/
45
46 /********************************************************
47 Local Functions
48 ********************************************************/
49 /**
50 * @brief This function will dispatch amsdu packet and
51 * forward it to kernel/upper layer
52 *
53 * @param priv A pointer to mlan_private
54 * @param pmbuf A pointer to the received buffer
55 *
56 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
57 */
wlan_11n_dispatch_amsdu_pkt(mlan_private * priv,pmlan_buffer pmbuf)58 static mlan_status wlan_11n_dispatch_amsdu_pkt(mlan_private *priv,
59 pmlan_buffer pmbuf)
60 {
61 RxPD *prx_pd;
62 prx_pd = (RxPD *)(pmbuf->pbuf + pmbuf->data_offset);
63
64 ENTER();
65 if (prx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
66 pmbuf->data_len = prx_pd->rx_pkt_length;
67 pmbuf->data_offset += prx_pd->rx_pkt_offset;
68 wlan_11n_deaggregate_pkt(priv, pmbuf);
69 LEAVE();
70 return MLAN_STATUS_SUCCESS;
71 }
72 LEAVE();
73 return MLAN_STATUS_FAILURE;
74 }
75
76 /**
77 * @brief This function will process the rx packet and
78 * forward it to kernel/upper layer
79 *
80 * @param priv A pointer to mlan_private
81 * @param payload A pointer to rx packet payload
82 * @param rx_reor_tbl_ptr pointer to RxReorderTbl
83 *
84 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
85 */
wlan_11n_dispatch_pkt(t_void * priv,t_void * payload,RxReorderTbl * rx_reor_tbl_ptr)86 static mlan_status wlan_11n_dispatch_pkt(t_void *priv, t_void *payload,
87 RxReorderTbl *rx_reor_tbl_ptr)
88 {
89 mlan_status ret = MLAN_STATUS_SUCCESS;
90 #ifdef STA_SUPPORT
91 pmlan_adapter pmadapter = ((pmlan_private)priv)->adapter;
92 #endif
93 ENTER();
94 if (payload == (t_void *)RX_PKT_DROPPED_IN_FW) {
95 LEAVE();
96 return ret;
97 }
98
99 #ifdef UAP_SUPPORT
100 if (GET_BSS_ROLE((mlan_private *)priv) == MLAN_BSS_ROLE_UAP) {
101 if (MLAN_STATUS_SUCCESS ==
102 wlan_11n_dispatch_amsdu_pkt((mlan_private *)priv,
103 (pmlan_buffer)payload)) {
104 LEAVE();
105 return ret;
106 }
107 ret = wlan_process_uap_rx_packet(priv, (pmlan_buffer)payload);
108 LEAVE();
109 return ret;
110 }
111 #endif /* UAP_SUPPORT */
112
113 #ifdef STA_SUPPORT
114 if (MLAN_STATUS_SUCCESS ==
115 wlan_11n_dispatch_amsdu_pkt((mlan_private *)priv,
116 (pmlan_buffer)payload)) {
117 LEAVE();
118 return ret;
119 }
120 ret = wlan_process_rx_packet(pmadapter, (pmlan_buffer)payload);
121 #endif /* STA_SUPPORT */
122 LEAVE();
123 return ret;
124 }
125
126 /**
127 * @brief This function restarts the reordering timeout timer
128 *
129 * @param pmadapter A pointer to mlan_adapter
130 * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
131 *
132 * @return N/A
133 */
mlan_11n_rxreorder_timer_restart(pmlan_adapter pmadapter,RxReorderTbl * rx_reor_tbl_ptr)134 static void mlan_11n_rxreorder_timer_restart(pmlan_adapter pmadapter,
135 RxReorderTbl *rx_reor_tbl_ptr)
136 {
137 t_u16 min_flush_time = 0;
138 ENTER();
139
140 if (rx_reor_tbl_ptr->win_size >= 32)
141 min_flush_time = MIN_FLUSH_TIMER_15_MS;
142 else
143 min_flush_time = MIN_FLUSH_TIMER_MS;
144
145 if (rx_reor_tbl_ptr->timer_context.timer_is_set)
146 pmadapter->callbacks.moal_stop_timer(
147 pmadapter->pmoal_handle,
148 rx_reor_tbl_ptr->timer_context.timer);
149
150 pmadapter->callbacks.moal_start_timer(
151 pmadapter->pmoal_handle, rx_reor_tbl_ptr->timer_context.timer,
152 MFALSE, (rx_reor_tbl_ptr->win_size * min_flush_time));
153
154 rx_reor_tbl_ptr->timer_context.timer_is_set = MTRUE;
155 LEAVE();
156 }
157
158 /**
159 * @brief This function dispatches all the packets in the buffer.
160 * There could be holes in the buffer.
161 *
162 * @param priv A pointer to mlan_private
163 * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
164 * @param start_win Start window
165 *
166 * @return MLAN_STATUS_SUCCESS
167 */
wlan_11n_dispatch_pkt_until_start_win(t_void * priv,RxReorderTbl * rx_reor_tbl_ptr,int start_win)168 static mlan_status wlan_11n_dispatch_pkt_until_start_win(
169 t_void *priv, RxReorderTbl *rx_reor_tbl_ptr, int start_win)
170 {
171 int no_pkt_to_send, i, xchg;
172 mlan_status ret = MLAN_STATUS_SUCCESS;
173 void *rx_tmp_ptr = MNULL;
174 mlan_private *pmpriv = (mlan_private *)priv;
175
176 ENTER();
177
178 no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
179 MIN((start_win - rx_reor_tbl_ptr->start_win),
180 rx_reor_tbl_ptr->win_size) :
181 rx_reor_tbl_ptr->win_size;
182
183 for (i = 0; i < no_pkt_to_send; ++i) {
184 pmpriv->adapter->callbacks.moal_spin_lock(
185 pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
186 rx_tmp_ptr = MNULL;
187 if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
188 rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
189 rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
190 }
191 pmpriv->adapter->callbacks.moal_spin_unlock(
192 pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
193 if (rx_tmp_ptr)
194 wlan_11n_dispatch_pkt(priv, rx_tmp_ptr,
195 rx_reor_tbl_ptr);
196 }
197
198 pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
199 pmpriv->rx_pkt_lock);
200 /*
201 * We don't have a circular buffer, hence use rotation to simulate
202 * circular buffer
203 */
204 xchg = rx_reor_tbl_ptr->win_size - no_pkt_to_send;
205 for (i = 0; i < xchg; ++i) {
206 rx_reor_tbl_ptr->rx_reorder_ptr[i] =
207 rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
208 rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = MNULL;
209 }
210
211 rx_reor_tbl_ptr->start_win = start_win;
212 pmpriv->adapter->callbacks.moal_spin_unlock(
213 pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
214
215 LEAVE();
216 return ret;
217 }
218
219 /**
220 * @brief This function will display the rxReorder table
221 *
222 * @param pmadapter A pointer to mlan_adapter structure
223 * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
224 *
225 * @return N/A
226 */
wlan_11n_display_tbl_ptr(pmlan_adapter pmadapter,RxReorderTbl * rx_reor_tbl_ptr)227 static t_void wlan_11n_display_tbl_ptr(pmlan_adapter pmadapter,
228 RxReorderTbl *rx_reor_tbl_ptr)
229 {
230 ENTER();
231
232 DBG_HEXDUMP(MDAT_D, "Reorder ptr", rx_reor_tbl_ptr->rx_reorder_ptr,
233 sizeof(t_void *) * rx_reor_tbl_ptr->win_size);
234
235 LEAVE();
236 }
237
238 /**
239 * @brief This function will dispatch all packets sequentially
240 * from start_win until a hole is found and adjust the
241 * start_win appropriately
242 *
243 * @param priv A pointer to mlan_private
244 * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
245 *
246 * @return MLAN_STATUS_SUCCESS
247 */
wlan_11n_scan_and_dispatch(t_void * priv,RxReorderTbl * rx_reor_tbl_ptr)248 static mlan_status wlan_11n_scan_and_dispatch(t_void *priv,
249 RxReorderTbl *rx_reor_tbl_ptr)
250 {
251 int i, j, xchg;
252 mlan_status ret = MLAN_STATUS_SUCCESS;
253 void *rx_tmp_ptr = MNULL;
254 mlan_private *pmpriv = (mlan_private *)priv;
255
256 ENTER();
257
258 for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
259 pmpriv->adapter->callbacks.moal_spin_lock(
260 pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
261 if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
262 pmpriv->adapter->callbacks.moal_spin_unlock(
263 pmpriv->adapter->pmoal_handle,
264 pmpriv->rx_pkt_lock);
265 break;
266 }
267 rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
268 rx_reor_tbl_ptr->rx_reorder_ptr[i] = MNULL;
269 pmpriv->adapter->callbacks.moal_spin_unlock(
270 pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
271 wlan_11n_dispatch_pkt(priv, rx_tmp_ptr, rx_reor_tbl_ptr);
272 }
273
274 pmpriv->adapter->callbacks.moal_spin_lock(pmpriv->adapter->pmoal_handle,
275 pmpriv->rx_pkt_lock);
276 /*
277 * We don't have a circular buffer, hence use rotation to simulate
278 * circular buffer
279 */
280 if (i > 0) {
281 xchg = rx_reor_tbl_ptr->win_size - i;
282 for (j = 0; j < xchg; ++j) {
283 rx_reor_tbl_ptr->rx_reorder_ptr[j] =
284 rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
285 rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = MNULL;
286 }
287 }
288
289 rx_reor_tbl_ptr->start_win =
290 (rx_reor_tbl_ptr->start_win + i) & (MAX_TID_VALUE - 1);
291
292 pmpriv->adapter->callbacks.moal_spin_unlock(
293 pmpriv->adapter->pmoal_handle, pmpriv->rx_pkt_lock);
294 LEAVE();
295 return ret;
296 }
297
298 /**
299 * @brief This function delete rxreorder table's entry
300 * and free the memory
301 *
302 * @param priv A pointer to mlan_private
303 * @param rx_reor_tbl_ptr A pointer to structure RxReorderTbl
304 *
305 * @return N/A
306 */
wlan_11n_delete_rxreorder_tbl_entry(mlan_private * priv,RxReorderTbl * rx_reor_tbl_ptr)307 static t_void wlan_11n_delete_rxreorder_tbl_entry(mlan_private *priv,
308 RxReorderTbl *rx_reor_tbl_ptr)
309 {
310 pmlan_adapter pmadapter = priv->adapter;
311
312 ENTER();
313
314 if (!rx_reor_tbl_ptr) {
315 LEAVE();
316 return;
317 }
318 mlan_block_rx_process(pmadapter, MTRUE);
319
320 wlan_11n_dispatch_pkt_until_start_win(
321 priv, rx_reor_tbl_ptr,
322 (rx_reor_tbl_ptr->start_win + rx_reor_tbl_ptr->win_size) &
323 (MAX_TID_VALUE - 1));
324
325 if (rx_reor_tbl_ptr->timer_context.timer) {
326 if (rx_reor_tbl_ptr->timer_context.timer_is_set) {
327 priv->adapter->callbacks.moal_stop_timer(
328 pmadapter->pmoal_handle,
329 rx_reor_tbl_ptr->timer_context.timer);
330 rx_reor_tbl_ptr->timer_context.timer_is_set = MFALSE;
331 }
332 priv->adapter->callbacks.moal_free_timer(
333 pmadapter->pmoal_handle,
334 rx_reor_tbl_ptr->timer_context.timer);
335 rx_reor_tbl_ptr->timer_context.timer = MNULL;
336 }
337
338 PRINTM(MDAT_D, "Delete rx_reor_tbl_ptr: %p\n", rx_reor_tbl_ptr);
339 util_unlink_list(pmadapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
340 (pmlan_linked_list)rx_reor_tbl_ptr,
341 pmadapter->callbacks.moal_spin_lock,
342 pmadapter->callbacks.moal_spin_unlock);
343
344 pmadapter->callbacks.moal_mfree(
345 pmadapter->pmoal_handle,
346 (t_u8 *)rx_reor_tbl_ptr->rx_reorder_ptr);
347 pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
348 (t_u8 *)rx_reor_tbl_ptr);
349 mlan_block_rx_process(pmadapter, MFALSE);
350
351 LEAVE();
352 }
353
354 /**
355 * @brief This function returns the last used sequence number
356 *
357 * @param rx_reorder_tbl_ptr A pointer to structure RxReorderTbl
358 *
359 * @return Last used sequence number
360 */
wlan_11n_find_last_seqnum(RxReorderTbl * rx_reorder_tbl_ptr)361 static int wlan_11n_find_last_seqnum(RxReorderTbl *rx_reorder_tbl_ptr)
362 {
363 int i;
364
365 ENTER();
366 for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i) {
367 if (rx_reorder_tbl_ptr->rx_reorder_ptr[i]) {
368 LEAVE();
369 return i;
370 }
371 }
372 LEAVE();
373 return -1;
374 }
375
376 /**
377 * @brief This function flushes all data
378 *
379 * @param priv A pointer to mlan_private structure
380 * @param rx_reor_tbl_ptr A pointer to RxReorderTbl
381 *
382 * @return N/A
383 */
wlan_start_flush_data(mlan_private * priv,RxReorderTbl * rx_reor_tbl_ptr)384 static t_void wlan_start_flush_data(mlan_private *priv,
385 RxReorderTbl *rx_reor_tbl_ptr)
386 {
387 int startWin;
388
389 ENTER();
390 wlan_11n_display_tbl_ptr(priv->adapter, rx_reor_tbl_ptr);
391
392 startWin = wlan_11n_find_last_seqnum(rx_reor_tbl_ptr);
393 if (startWin >= 0) {
394 PRINTM(MINFO, "Flush data %d\n", startWin);
395 wlan_11n_dispatch_pkt_until_start_win(
396 priv, rx_reor_tbl_ptr,
397 ((rx_reor_tbl_ptr->start_win + startWin + 1) &
398 (MAX_TID_VALUE - 1)));
399 }
400 wlan_11n_display_tbl_ptr(priv->adapter, rx_reor_tbl_ptr);
401 LEAVE();
402 }
403
404 /**
405 * @brief This function set the flag to flushes data
406 *
407 * @param context Reorder context pointer
408 *
409 * @return N/A
410 */
wlan_flush_data(t_void * context)411 static t_void wlan_flush_data(t_void *context)
412 {
413 reorder_tmr_cnxt_t *reorder_cnxt = (reorder_tmr_cnxt_t *)context;
414 ENTER();
415 /* Set the flag to flush data */
416 reorder_cnxt->priv->adapter->flush_data = MTRUE;
417 reorder_cnxt->ptr->flush_data = MTRUE;
418 reorder_cnxt->timer_is_set = MFALSE;
419 wlan_recv_event(reorder_cnxt->priv, MLAN_EVENT_ID_DRV_DEFER_RX_WORK,
420 MNULL);
421 LEAVE();
422 }
423
424 /**
425 * @brief This function will create a entry in rx reordering table for the
426 * given ta/tid and will initialize it with seq_num, win_size
427 *
428 * @param priv A pointer to mlan_private
429 * @param ta ta to find in reordering table
430 * @param tid tid to find in reordering table
431 * @param win_size win_size for the give ta/tid pair.
432 * @param seq_num Starting sequence number for current entry.
433 *
434 * @return N/A
435 */
wlan_11n_create_rxreorder_tbl(mlan_private * priv,t_u8 * ta,int tid,int win_size,int seq_num)436 static t_void wlan_11n_create_rxreorder_tbl(mlan_private *priv, t_u8 *ta,
437 int tid, int win_size, int seq_num)
438 {
439 int i;
440 pmlan_adapter pmadapter = priv->adapter;
441 RxReorderTbl *rx_reor_tbl_ptr, *new_node;
442 sta_node *sta_ptr = MNULL;
443 t_u16 last_seq = 0;
444
445 ENTER();
446
447 /*
448 * If we get a TID, ta pair which is already present dispatch all the
449 * the packets and move the window size until the ssn
450 */
451 rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, tid, ta);
452 if (rx_reor_tbl_ptr) {
453 PRINTM(MCMND, "%s: delete %p old_size=%d, win_size=%d\n",
454 __func__, rx_reor_tbl_ptr, rx_reor_tbl_ptr->win_size,
455 win_size);
456 wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
457 }
458 mlan_block_rx_process(pmadapter, MTRUE);
459 PRINTM(MCMND, "%s: seq_num %d, tid %d, ta " MACSTR ", win_size %d\n",
460 __func__, seq_num, tid, MAC2STR(ta), win_size);
461 if (pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
462 sizeof(RxReorderTbl), MLAN_MEM_DEF,
463 (t_u8 **)&new_node)) {
464 PRINTM(MERROR, "Rx reorder memory allocation failed\n");
465 mlan_block_rx_process(pmadapter, MFALSE);
466 LEAVE();
467 return;
468 }
469
470 util_init_list((pmlan_linked_list)new_node);
471 if (pmadapter->callbacks.moal_malloc(
472 pmadapter->pmoal_handle, sizeof(pmlan_buffer) * win_size,
473 MLAN_MEM_DEF, (t_u8 **)&new_node->rx_reorder_ptr)) {
474 PRINTM(MERROR, "Rx reorder table memory allocation"
475 "failed\n");
476 pmadapter->callbacks.moal_mfree(pmadapter->pmoal_handle,
477 (t_u8 *)new_node);
478 mlan_block_rx_process(pmadapter, MFALSE);
479 LEAVE();
480 return;
481 }
482 PRINTM(MDAT_D, "Create ReorderPtr: %p start_win=%d last_seq=%d\n",
483 new_node, new_node->start_win, last_seq);
484 new_node->timer_context.ptr = new_node;
485 new_node->timer_context.priv = priv;
486 new_node->timer_context.timer_is_set = MFALSE;
487 pmadapter->callbacks.moal_init_timer(pmadapter->pmoal_handle,
488 &new_node->timer_context.timer,
489 wlan_flush_data,
490 &new_node->timer_context);
491 util_enqueue_list_tail(pmadapter->pmoal_handle,
492 &priv->rx_reorder_tbl_ptr,
493 (pmlan_linked_list)new_node,
494 pmadapter->callbacks.moal_spin_lock,
495 pmadapter->callbacks.moal_spin_unlock);
496 new_node->tid = tid;
497 memcpy_ext(pmadapter, new_node->ta, ta, MLAN_MAC_ADDR_LENGTH,
498 MLAN_MAC_ADDR_LENGTH);
499 new_node->start_win = seq_num;
500 new_node->pkt_count = 0;
501 if (queuing_ra_based(priv)) {
502 if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) {
503 sta_ptr = wlan_get_station_entry(priv, ta);
504 if (sta_ptr)
505 last_seq = sta_ptr->rx_seq[tid];
506 }
507 PRINTM(MINFO, "UAP/ADHOC:last_seq=%d start_win=%d\n", last_seq,
508 new_node->start_win);
509 } else {
510 sta_ptr = wlan_get_station_entry(priv, ta);
511 if (sta_ptr)
512 last_seq = sta_ptr->rx_seq[tid];
513 else
514 last_seq = priv->rx_seq[tid];
515 }
516 new_node->last_seq = last_seq;
517 new_node->win_size = win_size;
518 new_node->force_no_drop = MFALSE;
519 new_node->check_start_win = MTRUE;
520 new_node->ba_status = BA_STREAM_SETUP_INPROGRESS;
521 for (i = 0; i < win_size; ++i)
522 new_node->rx_reorder_ptr[i] = MNULL;
523
524 mlan_block_rx_process(pmadapter, MFALSE);
525 LEAVE();
526 }
527
528 /********************************************************
529 Global Functions
530 ********************************************************/
531
532 /**
533 * @brief This function will return the pointer to a entry in rx reordering
534 * table which matches the give TA/TID pair
535 *
536 * @param priv A pointer to mlan_private
537 * @param ta ta to find in reordering table
538 * @param tid tid to find in reordering table
539 *
540 * @return A pointer to structure RxReorderTbl
541 */
wlan_11n_get_rxreorder_tbl(mlan_private * priv,int tid,t_u8 * ta)542 RxReorderTbl *wlan_11n_get_rxreorder_tbl(mlan_private *priv, int tid, t_u8 *ta)
543 {
544 RxReorderTbl *rx_reor_tbl_ptr;
545
546 ENTER();
547
548 rx_reor_tbl_ptr =
549 (RxReorderTbl *)util_peek_list(priv->adapter->pmoal_handle,
550 &priv->rx_reorder_tbl_ptr, MNULL,
551 MNULL);
552 if (!rx_reor_tbl_ptr) {
553 LEAVE();
554 return MNULL;
555 }
556
557 while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
558 if ((!memcmp(priv->adapter, rx_reor_tbl_ptr->ta, ta,
559 MLAN_MAC_ADDR_LENGTH)) &&
560 (rx_reor_tbl_ptr->tid == tid)) {
561 LEAVE();
562 return rx_reor_tbl_ptr;
563 }
564
565 rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
566 }
567
568 LEAVE();
569 return MNULL;
570 }
571
572 /**
573 * @brief This function prepares command for adding a block ack
574 * request.
575 *
576 * @param priv A pointer to mlan_private structure
577 * @param cmd A pointer to HostCmd_DS_COMMAND structure
578 * @param pdata_buf A pointer to data buffer
579 *
580 * @return MLAN_STATUS_SUCCESS
581 */
wlan_cmd_11n_addba_req(mlan_private * priv,HostCmd_DS_COMMAND * cmd,t_void * pdata_buf)582 mlan_status wlan_cmd_11n_addba_req(mlan_private *priv, HostCmd_DS_COMMAND *cmd,
583 t_void *pdata_buf)
584 {
585 HostCmd_DS_11N_ADDBA_REQ *padd_ba_req =
586 (HostCmd_DS_11N_ADDBA_REQ *)&cmd->params.add_ba_req;
587 ENTER();
588
589 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
590 cmd->size =
591 wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_REQ) + S_DS_GEN);
592
593 memcpy_ext(priv->adapter, padd_ba_req, pdata_buf,
594 sizeof(HostCmd_DS_11N_ADDBA_REQ),
595 sizeof(HostCmd_DS_11N_ADDBA_REQ));
596 padd_ba_req->block_ack_param_set =
597 wlan_cpu_to_le16(padd_ba_req->block_ack_param_set);
598 padd_ba_req->block_ack_tmo =
599 wlan_cpu_to_le16(padd_ba_req->block_ack_tmo);
600 padd_ba_req->ssn = wlan_cpu_to_le16(padd_ba_req->ssn);
601 padd_ba_req->add_req_result = 0;
602
603 LEAVE();
604 return MLAN_STATUS_SUCCESS;
605 }
606
607 /**
608 * @brief This function check if AMPDU Rx allowed
609 *
610 * @param priv A pointer to mlan_private structure
611 * @param tid TID
612 *
613 * @return MTRUE/MFALSE
614 */
wlan_is_addba_reject(mlan_private * priv,t_u8 tid)615 static t_u8 wlan_is_addba_reject(mlan_private *priv, t_u8 tid)
616 {
617 if (tid >= MAX_NUM_TID) {
618 PRINTM(MERROR, "Wrong TID =%d", tid);
619 return ADDBA_RSP_STATUS_REJECT;
620 }
621 #ifdef STA_SUPPORT
622 #endif
623 return priv->addba_reject[tid];
624 }
625 /**
626 * @brief This function prepares command for adding a block ack
627 * response.
628 *
629 * @param priv A pointer to mlan_private structure
630 * @param cmd A pointer to HostCmd_DS_COMMAND structure
631 * @param pdata_buf A pointer to data buffer
632 *
633 * @return MLAN_STATUS_SUCCESS
634 */
wlan_cmd_11n_addba_rspgen(mlan_private * priv,HostCmd_DS_COMMAND * cmd,void * pdata_buf)635 mlan_status wlan_cmd_11n_addba_rspgen(mlan_private *priv,
636 HostCmd_DS_COMMAND *cmd, void *pdata_buf)
637 {
638 HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
639 (HostCmd_DS_11N_ADDBA_RSP *)&cmd->params.add_ba_rsp;
640 HostCmd_DS_11N_ADDBA_REQ *pevt_addba_req =
641 (HostCmd_DS_11N_ADDBA_REQ *)pdata_buf;
642 t_u8 tid = 0;
643 int win_size = 0;
644
645 ENTER();
646
647 pevt_addba_req->block_ack_param_set =
648 wlan_le16_to_cpu(pevt_addba_req->block_ack_param_set);
649 pevt_addba_req->block_ack_tmo =
650 wlan_le16_to_cpu(pevt_addba_req->block_ack_tmo);
651 pevt_addba_req->ssn = wlan_le16_to_cpu(pevt_addba_req->ssn);
652
653 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
654 cmd->size =
655 wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_ADDBA_RSP) + S_DS_GEN);
656
657 memcpy_ext(priv->adapter, padd_ba_rsp->peer_mac_addr,
658 pevt_addba_req->peer_mac_addr, MLAN_MAC_ADDR_LENGTH,
659 MLAN_MAC_ADDR_LENGTH);
660 padd_ba_rsp->dialog_token = pevt_addba_req->dialog_token;
661 padd_ba_rsp->block_ack_tmo =
662 wlan_cpu_to_le16(pevt_addba_req->block_ack_tmo);
663 padd_ba_rsp->ssn = wlan_cpu_to_le16(pevt_addba_req->ssn);
664 padd_ba_rsp->add_rsp_result = 0;
665
666 padd_ba_rsp->block_ack_param_set = pevt_addba_req->block_ack_param_set;
667 tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK) >>
668 BLOCKACKPARAM_TID_POS;
669 if (wlan_is_addba_reject(priv, tid)
670 #ifdef STA_SUPPORT
671 || ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) &&
672 priv->wps.session_enable)
673 #endif
674 #ifdef UAP_SUPPORT
675 || ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) &&
676 (util_scalar_read(priv->adapter->pmoal_handle,
677 &priv->adapter->pending_bridge_pkts,
678 priv->adapter->callbacks.moal_spin_lock,
679 priv->adapter->callbacks.moal_spin_unlock) >
680 RX_LOW_THRESHOLD))
681 #endif
682 )
683 padd_ba_rsp->status_code =
684 wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
685 else
686 padd_ba_rsp->status_code =
687 wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
688 padd_ba_rsp->block_ack_param_set &= ~BLOCKACKPARAM_WINSIZE_MASK;
689 if (!priv->add_ba_param.rx_amsdu)
690 /* We do not support AMSDU inside AMPDU, hence reset the bit */
691 padd_ba_rsp->block_ack_param_set &=
692 ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
693
694 padd_ba_rsp->block_ack_param_set |=
695 (priv->add_ba_param.rx_win_size << BLOCKACKPARAM_WINSIZE_POS);
696 win_size = (padd_ba_rsp->block_ack_param_set &
697 BLOCKACKPARAM_WINSIZE_MASK) >>
698 BLOCKACKPARAM_WINSIZE_POS;
699
700 if (win_size == 0)
701 padd_ba_rsp->status_code =
702 wlan_cpu_to_le16(ADDBA_RSP_STATUS_DECLINED);
703
704 padd_ba_rsp->block_ack_param_set =
705 wlan_cpu_to_le16(padd_ba_rsp->block_ack_param_set);
706
707 if (padd_ba_rsp->status_code ==
708 wlan_cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT))
709 wlan_11n_create_rxreorder_tbl(priv,
710 pevt_addba_req->peer_mac_addr,
711 tid, win_size,
712 pevt_addba_req->ssn);
713 LEAVE();
714 return MLAN_STATUS_SUCCESS;
715 }
716
717 /**
718 * @brief This function prepares command for deleting a block ack
719 * request.
720 *
721 * @param priv A pointer to mlan_private structure
722 * @param cmd A pointer to HostCmd_DS_COMMAND structure
723 * @param pdata_buf A pointer to data buffer
724 *
725 * @return MLAN_STATUS_SUCCESS
726 */
wlan_cmd_11n_delba(mlan_private * priv,HostCmd_DS_COMMAND * cmd,void * pdata_buf)727 mlan_status wlan_cmd_11n_delba(mlan_private *priv, HostCmd_DS_COMMAND *cmd,
728 void *pdata_buf)
729 {
730 HostCmd_DS_11N_DELBA *pdel_ba =
731 (HostCmd_DS_11N_DELBA *)&cmd->params.del_ba;
732
733 ENTER();
734
735 cmd->command = wlan_cpu_to_le16(HostCmd_CMD_11N_DELBA);
736 cmd->size = wlan_cpu_to_le16(sizeof(HostCmd_DS_11N_DELBA) + S_DS_GEN);
737
738 memcpy_ext(priv->adapter, pdel_ba, pdata_buf,
739 sizeof(HostCmd_DS_11N_DELBA), sizeof(HostCmd_DS_11N_DELBA));
740 pdel_ba->del_ba_param_set = wlan_cpu_to_le16(pdel_ba->del_ba_param_set);
741 pdel_ba->reason_code = wlan_cpu_to_le16(pdel_ba->reason_code);
742 pdel_ba->del_result = 0;
743
744 LEAVE();
745 return MLAN_STATUS_SUCCESS;
746 }
747
748 /**
749 * @brief This function will identify if RxReodering is needed for the packet
750 * and will do the reordering if required before sending it to kernel
751 *
752 * @param priv A pointer to mlan_private
753 * @param seq_num Seqence number of the current packet
754 * @param tid Tid of the current packet
755 * @param ta Transmiter address of the current packet
756 * @param pkt_type Packetype for the current packet (to identify if its a BAR)
757 * @param payload Pointer to the payload
758 *
759 * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
760 */
mlan_11n_rxreorder_pkt(void * priv,t_u16 seq_num,t_u16 tid,t_u8 * ta,t_u8 pkt_type,void * payload)761 mlan_status mlan_11n_rxreorder_pkt(void *priv, t_u16 seq_num, t_u16 tid,
762 t_u8 *ta, t_u8 pkt_type, void *payload)
763 {
764 RxReorderTbl *rx_reor_tbl_ptr;
765 int prev_start_win, start_win, end_win, win_size;
766 mlan_status ret = MLAN_STATUS_SUCCESS;
767 pmlan_adapter pmadapter = ((mlan_private *)priv)->adapter;
768
769 ENTER();
770
771 rx_reor_tbl_ptr =
772 wlan_11n_get_rxreorder_tbl((mlan_private *)priv, tid, ta);
773 if (!rx_reor_tbl_ptr || rx_reor_tbl_ptr->win_size <= 1) {
774 if (pkt_type != PKT_TYPE_BAR)
775 wlan_11n_dispatch_pkt(priv, payload, rx_reor_tbl_ptr);
776
777 LEAVE();
778 return ret;
779
780 } else {
781 if (rx_reor_tbl_ptr->flush_data) {
782 rx_reor_tbl_ptr->flush_data = MFALSE;
783 wlan_start_flush_data(priv, rx_reor_tbl_ptr);
784 }
785 if ((pkt_type == PKT_TYPE_AMSDU) && !rx_reor_tbl_ptr->amsdu) {
786 wlan_11n_dispatch_pkt(priv, payload, rx_reor_tbl_ptr);
787 LEAVE();
788 return ret;
789 }
790 if (pkt_type == PKT_TYPE_BAR)
791 PRINTM(MDAT_D, "BAR ");
792 if (pkt_type == PKT_TYPE_AMSDU)
793 PRINTM(MDAT_D, "AMSDU ");
794
795 if (rx_reor_tbl_ptr->check_start_win) {
796 if (seq_num == rx_reor_tbl_ptr->start_win)
797 rx_reor_tbl_ptr->check_start_win = MFALSE;
798 else {
799 rx_reor_tbl_ptr->pkt_count++;
800 if (rx_reor_tbl_ptr->pkt_count <
801 (rx_reor_tbl_ptr->win_size / 2)) {
802 if (rx_reor_tbl_ptr->last_seq ==
803 seq_num) {
804 /** drop duplicate packet */
805 ret = MLAN_STATUS_FAILURE;
806 } else {
807 /** forward the packet to kernel
808 */
809 rx_reor_tbl_ptr->last_seq =
810 seq_num;
811 if (pkt_type != PKT_TYPE_BAR)
812 wlan_11n_dispatch_pkt(
813 priv, payload,
814 rx_reor_tbl_ptr);
815 }
816 LEAVE();
817 return ret;
818 }
819 rx_reor_tbl_ptr->check_start_win = MFALSE;
820 if ((seq_num != rx_reor_tbl_ptr->start_win) &&
821 (rx_reor_tbl_ptr->last_seq !=
822 DEFAULT_SEQ_NUM)) {
823 end_win = (rx_reor_tbl_ptr->start_win +
824 rx_reor_tbl_ptr->win_size -
825 1) &
826 (MAX_TID_VALUE - 1);
827 if (((end_win >
828 rx_reor_tbl_ptr->start_win) &&
829 (rx_reor_tbl_ptr->last_seq >=
830 rx_reor_tbl_ptr->start_win) &&
831 (rx_reor_tbl_ptr->last_seq <
832 end_win)) ||
833 ((end_win <
834 rx_reor_tbl_ptr->start_win) &&
835 ((rx_reor_tbl_ptr->last_seq >=
836 rx_reor_tbl_ptr->start_win) ||
837 (rx_reor_tbl_ptr->last_seq <
838 end_win)))) {
839 PRINTM(MDAT_D,
840 "Update start_win: last_seq=%d, start_win=%d seq_num=%d\n",
841 rx_reor_tbl_ptr->last_seq,
842 rx_reor_tbl_ptr
843 ->start_win,
844 seq_num);
845 rx_reor_tbl_ptr->start_win =
846 rx_reor_tbl_ptr
847 ->last_seq +
848 1;
849 } else if ((seq_num <
850 rx_reor_tbl_ptr->start_win) &&
851 (seq_num >
852 rx_reor_tbl_ptr->last_seq)) {
853 PRINTM(MDAT_D,
854 "Update start_win: last_seq=%d, start_win=%d seq_num=%d\n",
855 rx_reor_tbl_ptr->last_seq,
856 rx_reor_tbl_ptr
857 ->start_win,
858 seq_num);
859 rx_reor_tbl_ptr->start_win =
860 rx_reor_tbl_ptr
861 ->last_seq +
862 1;
863 }
864 }
865 }
866 }
867 if (rx_reor_tbl_ptr->force_no_drop) {
868 wlan_11n_dispatch_pkt_until_start_win(
869 priv, rx_reor_tbl_ptr,
870 (rx_reor_tbl_ptr->start_win +
871 rx_reor_tbl_ptr->win_size) &
872 (MAX_TID_VALUE - 1));
873 if (pkt_type != PKT_TYPE_BAR)
874 rx_reor_tbl_ptr->start_win = seq_num;
875 mlan_11n_rxreorder_timer_restart(pmadapter,
876 rx_reor_tbl_ptr);
877 }
878
879 prev_start_win = start_win = rx_reor_tbl_ptr->start_win;
880 win_size = rx_reor_tbl_ptr->win_size;
881 end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
882
883 PRINTM(MDAT_D, "TID %d, TA " MACSTR "\n", tid, MAC2STR(ta));
884 PRINTM(MDAT_D,
885 "1:seq_num %d start_win %d win_size %d end_win %d\n",
886 seq_num, start_win, win_size, end_win);
887 /*
888 * If seq_num is less then starting win then ignore and drop
889 * the packet
890 */
891 if (rx_reor_tbl_ptr->force_no_drop) {
892 PRINTM(MDAT_D, "No drop packet\n");
893 rx_reor_tbl_ptr->force_no_drop = MFALSE;
894 } else {
895 /* Wrap */
896 if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {
897 if (seq_num >= ((start_win + (TWOPOW11)) &
898 (MAX_TID_VALUE - 1)) &&
899 (seq_num < start_win)) {
900 if (pkt_type == PKT_TYPE_BAR)
901 PRINTM(MDAT_D,
902 "BAR: start_win=%d, end_win=%d, seq_num=%d\n",
903 start_win, end_win,
904 seq_num);
905 ret = MLAN_STATUS_FAILURE;
906 goto done;
907 }
908 } else if ((seq_num < start_win) ||
909 (seq_num >= (start_win + (TWOPOW11)))) {
910 if (pkt_type == PKT_TYPE_BAR)
911 PRINTM(MDAT_D,
912 "BAR: start_win=%d, end_win=%d, seq_num=%d\n",
913 start_win, end_win, seq_num);
914 ret = MLAN_STATUS_FAILURE;
915 goto done;
916 }
917 }
918
919 /*
920 * If this packet is a BAR we adjust seq_num as
921 * WinStart = seq_num
922 */
923 if (pkt_type == PKT_TYPE_BAR)
924 seq_num = ((seq_num + win_size) - 1) &
925 (MAX_TID_VALUE - 1);
926
927 PRINTM(MDAT_D,
928 "2:seq_num %d start_win %d win_size %d end_win %d\n",
929 seq_num, start_win, win_size, end_win);
930
931 if (((end_win < start_win) && (seq_num < start_win) &&
932 (seq_num > end_win)) ||
933 ((end_win > start_win) &&
934 ((seq_num > end_win) || (seq_num < start_win)))) {
935 end_win = seq_num;
936 if (((seq_num - win_size) + 1) >= 0)
937 start_win = (end_win - win_size) + 1;
938 else
939 start_win =
940 (MAX_TID_VALUE - (win_size - seq_num)) +
941 1;
942 ret = wlan_11n_dispatch_pkt_until_start_win(
943 priv, rx_reor_tbl_ptr, start_win);
944 if (ret)
945 goto done;
946 }
947
948 PRINTM(MDAT_D,
949 "3:seq_num %d start_win %d win_size %d"
950 " end_win %d\n",
951 seq_num, start_win, win_size, end_win);
952 if (pkt_type != PKT_TYPE_BAR) {
953 if (seq_num >= start_win) {
954 if (rx_reor_tbl_ptr->rx_reorder_ptr[seq_num -
955 start_win]) {
956 PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
957 ret = MLAN_STATUS_FAILURE;
958 goto done;
959 }
960 rx_reor_tbl_ptr
961 ->rx_reorder_ptr[seq_num - start_win] =
962 payload;
963 } else { /* Wrap condition */
964 if (rx_reor_tbl_ptr
965 ->rx_reorder_ptr[(seq_num +
966 (MAX_TID_VALUE)) -
967 start_win]) {
968 PRINTM(MDAT_D, "Drop Duplicate Pkt\n");
969 ret = MLAN_STATUS_FAILURE;
970 goto done;
971 }
972 rx_reor_tbl_ptr
973 ->rx_reorder_ptr[(seq_num +
974 (MAX_TID_VALUE)) -
975 start_win] = payload;
976 }
977 }
978
979 wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
980
981 /*
982 * Dispatch all packets sequentially from start_win until a
983 * hole is found and adjust the start_win appropriately
984 */
985 ret = wlan_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
986
987 wlan_11n_display_tbl_ptr(pmadapter, rx_reor_tbl_ptr);
988 }
989
990 done:
991 if (!rx_reor_tbl_ptr->timer_context.timer_is_set ||
992 (prev_start_win != rx_reor_tbl_ptr->start_win)) {
993 mlan_11n_rxreorder_timer_restart(pmadapter, rx_reor_tbl_ptr);
994 }
995
996 LEAVE();
997 return ret;
998 }
999
1000 /**
1001 * @brief This function will delete an entry for a given tid/ta pair. tid/ta
1002 * are taken from delba_event body
1003 *
1004 * @param priv A pointer to mlan_private
1005 * @param tid tid to send delba
1006 * @param peer_mac MAC address to send delba
1007 * @param type TYPE_DELBA_SENT or TYPE_DELBA_RECEIVE
1008 * @param initiator MTRUE if we are initiator of ADDBA, MFALSE otherwise
1009 * @param reason_code delete ba reason
1010 *
1011 * @return N/A
1012 */
mlan_11n_delete_bastream_tbl(mlan_private * priv,int tid,t_u8 * peer_mac,t_u8 type,int initiator,t_u16 reason_code)1013 void mlan_11n_delete_bastream_tbl(mlan_private *priv, int tid, t_u8 *peer_mac,
1014 t_u8 type, int initiator, t_u16 reason_code)
1015 {
1016 RxReorderTbl *rx_reor_tbl_ptr;
1017 TxBAStreamTbl *ptxtbl;
1018 t_u8 cleanup_rx_reorder_tbl;
1019 raListTbl *ra_list = MNULL;
1020 int tid_down;
1021
1022 ENTER();
1023
1024 if (type == TYPE_DELBA_RECEIVE)
1025 cleanup_rx_reorder_tbl = (initiator) ? MTRUE : MFALSE;
1026 else
1027 cleanup_rx_reorder_tbl = (initiator) ? MFALSE : MTRUE;
1028
1029 PRINTM(MEVENT,
1030 "delete_bastream_tbl: " MACSTR " tid=%d, type=%d"
1031 "initiator=%d reason=%d\n",
1032 MAC2STR(peer_mac), tid, type, initiator, reason_code);
1033
1034 if (cleanup_rx_reorder_tbl) {
1035 rx_reor_tbl_ptr =
1036 wlan_11n_get_rxreorder_tbl(priv, tid, peer_mac);
1037 if (!rx_reor_tbl_ptr) {
1038 PRINTM(MWARN, "TID, TA not found in table!\n");
1039 LEAVE();
1040 return;
1041 }
1042 wlan_11n_delete_rxreorder_tbl_entry(priv, rx_reor_tbl_ptr);
1043 } else {
1044 wlan_request_ralist_lock(priv);
1045 ptxtbl = wlan_11n_get_txbastream_tbl(priv, tid, peer_mac,
1046 MFALSE);
1047 if (!ptxtbl) {
1048 PRINTM(MWARN, "TID, RA not found in table!\n");
1049 wlan_release_ralist_lock(priv);
1050 LEAVE();
1051 return;
1052 }
1053 wlan_11n_delete_txbastream_tbl_entry(priv, ptxtbl);
1054 wlan_release_ralist_lock(priv);
1055 tid_down = wlan_get_wmm_tid_down(priv, tid);
1056 ra_list = wlan_wmm_get_ralist_node(priv, tid_down, peer_mac);
1057 if (ra_list) {
1058 ra_list->amsdu_in_ampdu = MFALSE;
1059 ra_list->ba_status = BA_STREAM_NOT_SETUP;
1060 if (type == TYPE_DELBA_RECEIVE) {
1061 if (reason_code == REASON_CODE_STA_TIMEOUT)
1062 ra_list->del_ba_count = 0;
1063 else
1064 ra_list->del_ba_count++;
1065 ra_list->packet_count = 0;
1066 /** after delba, we will try to set up BA again after sending 1k packets*/
1067 #define MIN_BA_SETUP_PACKET_REQIRED 1024
1068 ra_list->ba_packet_threshold =
1069 MIN_BA_SETUP_PACKET_REQIRED +
1070 wlan_get_random_ba_threshold(
1071 priv->adapter);
1072 }
1073 }
1074 }
1075
1076 LEAVE();
1077 }
1078
1079 /**
1080 * @brief This function handles the command response of
1081 * a block ack response
1082 *
1083 * @param priv A pointer to mlan_private structure
1084 * @param resp A pointer to HostCmd_DS_COMMAND
1085 *
1086 * @return MLAN_STATUS_SUCCESS
1087 */
wlan_ret_11n_addba_resp(mlan_private * priv,HostCmd_DS_COMMAND * resp)1088 mlan_status wlan_ret_11n_addba_resp(mlan_private *priv,
1089 HostCmd_DS_COMMAND *resp)
1090 {
1091 HostCmd_DS_11N_ADDBA_RSP *padd_ba_rsp =
1092 (HostCmd_DS_11N_ADDBA_RSP *)&resp->params.add_ba_rsp;
1093 int tid;
1094 RxReorderTbl *rx_reor_tbl_ptr = MNULL;
1095
1096 ENTER();
1097
1098 padd_ba_rsp->status_code = wlan_le16_to_cpu(padd_ba_rsp->status_code);
1099 padd_ba_rsp->block_ack_param_set =
1100 wlan_le16_to_cpu(padd_ba_rsp->block_ack_param_set);
1101 padd_ba_rsp->block_ack_tmo =
1102 wlan_le16_to_cpu(padd_ba_rsp->block_ack_tmo);
1103 padd_ba_rsp->ssn = wlan_le16_to_cpu(padd_ba_rsp->ssn);
1104
1105 tid = (padd_ba_rsp->block_ack_param_set & BLOCKACKPARAM_TID_MASK) >>
1106 BLOCKACKPARAM_TID_POS;
1107 /* Check if we had rejected the ADDBA, if yes then do not create the
1108 * stream
1109 */
1110 if (padd_ba_rsp->status_code == BA_RESULT_SUCCESS) {
1111 PRINTM(MCMND,
1112 "ADDBA RSP: " MACSTR
1113 " tid=%d ssn=%d win_size=%d,amsdu=%d\n",
1114 MAC2STR(padd_ba_rsp->peer_mac_addr), tid,
1115 padd_ba_rsp->ssn,
1116 ((padd_ba_rsp->block_ack_param_set &
1117 BLOCKACKPARAM_WINSIZE_MASK) >>
1118 BLOCKACKPARAM_WINSIZE_POS),
1119 padd_ba_rsp->block_ack_param_set &
1120 BLOCKACKPARAM_AMSDU_SUPP_MASK);
1121
1122 rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(
1123 priv, tid, padd_ba_rsp->peer_mac_addr);
1124 if (rx_reor_tbl_ptr) {
1125 rx_reor_tbl_ptr->ba_status = BA_STREAM_SETUP_COMPLETE;
1126 if ((padd_ba_rsp->block_ack_param_set &
1127 BLOCKACKPARAM_AMSDU_SUPP_MASK) &&
1128 priv->add_ba_param.rx_amsdu)
1129 rx_reor_tbl_ptr->amsdu = MTRUE;
1130 else
1131 rx_reor_tbl_ptr->amsdu = MFALSE;
1132 }
1133 } else {
1134 PRINTM(MCMND, "ADDBA RSP: Failed(" MACSTR " tid=%d)\n",
1135 MAC2STR(padd_ba_rsp->peer_mac_addr), tid);
1136 rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(
1137 priv, tid, padd_ba_rsp->peer_mac_addr);
1138 if (rx_reor_tbl_ptr)
1139 wlan_11n_delete_rxreorder_tbl_entry(priv,
1140 rx_reor_tbl_ptr);
1141 }
1142
1143 LEAVE();
1144 return MLAN_STATUS_SUCCESS;
1145 }
1146
1147 /**
1148 * @brief This function handles ba_stream_timeout event
1149 *
1150 * @param priv A pointer to mlan_private
1151 * @param event A pointer to structure HostCmd_DS_11N_BATIMEOUT
1152 *
1153 * @return N/A
1154 */
wlan_11n_ba_stream_timeout(mlan_private * priv,HostCmd_DS_11N_BATIMEOUT * event)1155 void wlan_11n_ba_stream_timeout(mlan_private *priv,
1156 HostCmd_DS_11N_BATIMEOUT *event)
1157 {
1158 HostCmd_DS_11N_DELBA delba;
1159
1160 ENTER();
1161
1162 DBG_HEXDUMP(MCMD_D, "Event:", (t_u8 *)event, 20);
1163
1164 memset(priv->adapter, &delba, 0, sizeof(HostCmd_DS_11N_DELBA));
1165 memcpy_ext(priv->adapter, delba.peer_mac_addr, event->peer_mac_addr,
1166 MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH);
1167
1168 delba.del_ba_param_set |= (t_u16)event->tid << DELBA_TID_POS;
1169 delba.del_ba_param_set |= (t_u16)event->origninator
1170 << DELBA_INITIATOR_POS;
1171 delba.reason_code = REASON_CODE_STA_TIMEOUT;
1172 wlan_prepare_cmd(priv, HostCmd_CMD_11N_DELBA, 0, 0, MNULL, &delba);
1173
1174 LEAVE();
1175 return;
1176 }
1177
1178 /**
1179 * @brief This function cleans up reorder tbl
1180 *
1181 * @param priv A pointer to mlan_private
1182 *
1183 * @return N/A
1184 */
wlan_11n_cleanup_reorder_tbl(mlan_private * priv)1185 void wlan_11n_cleanup_reorder_tbl(mlan_private *priv)
1186 {
1187 RxReorderTbl *del_tbl_ptr;
1188
1189 ENTER();
1190
1191 while ((del_tbl_ptr = (RxReorderTbl *)util_peek_list(
1192 priv->adapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
1193 priv->adapter->callbacks.moal_spin_lock,
1194 priv->adapter->callbacks.moal_spin_unlock))) {
1195 wlan_11n_delete_rxreorder_tbl_entry(priv, del_tbl_ptr);
1196 }
1197
1198 util_init_list((pmlan_linked_list)&priv->rx_reorder_tbl_ptr);
1199
1200 memset(priv->adapter, priv->rx_seq, 0xff, sizeof(priv->rx_seq));
1201 LEAVE();
1202 }
1203
1204 /**
1205 * @brief This function handle the rxba_sync event
1206 *
1207 * @param priv A pointer to mlan_private
1208 * @param event_buf A pointer to event buf
1209 * @param len event_buf length
1210 * @return N/A
1211 */
wlan_11n_rxba_sync_event(mlan_private * priv,t_u8 * event_buf,t_u16 len)1212 void wlan_11n_rxba_sync_event(mlan_private *priv, t_u8 *event_buf, t_u16 len)
1213 {
1214 MrvlIEtypes_RxBaSync_t *tlv_rxba = (MrvlIEtypes_RxBaSync_t *)event_buf;
1215 t_u16 tlv_type, tlv_len;
1216 RxReorderTbl *rx_reor_tbl_ptr = MNULL;
1217 t_u8 i, j;
1218 t_u16 seq_num = 0;
1219 int tlv_buf_left = len;
1220 ENTER();
1221
1222 DBG_HEXDUMP(MEVT_D, "RXBA_SYNC_EVT", event_buf, len);
1223 while (tlv_buf_left >= (int)sizeof(MrvlIEtypes_RxBaSync_t)) {
1224 tlv_type = wlan_le16_to_cpu(tlv_rxba->header.type);
1225 tlv_len = wlan_le16_to_cpu(tlv_rxba->header.len);
1226 if (tlv_type != TLV_TYPE_RXBA_SYNC) {
1227 PRINTM(MERROR, "Wrong TLV id=0x%x\n", tlv_type);
1228 goto done;
1229 }
1230 tlv_rxba->seq_num = wlan_le16_to_cpu(tlv_rxba->seq_num);
1231 tlv_rxba->bitmap_len = wlan_le16_to_cpu(tlv_rxba->bitmap_len);
1232 PRINTM(MEVENT, MACSTR " tid=%d seq_num=%d bitmap_len=%d\n",
1233 MAC2STR(tlv_rxba->mac), tlv_rxba->tid, tlv_rxba->seq_num,
1234 tlv_rxba->bitmap_len);
1235 rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(
1236 priv, tlv_rxba->tid, tlv_rxba->mac);
1237 if (!rx_reor_tbl_ptr) {
1238 PRINTM(MEVENT, "Can not find rx_reorder_tbl\n");
1239 goto done;
1240 }
1241 if (rx_reor_tbl_ptr->force_no_drop) {
1242 PRINTM(MEVENT, "Ignore RXBA_SYNC_EVT in resume\n");
1243 goto done;
1244 }
1245 for (i = 0; i < tlv_rxba->bitmap_len; i++) {
1246 for (j = 0; j < 8; j++) {
1247 if (tlv_rxba->bitmap[i] & (1 << j)) {
1248 seq_num = (tlv_rxba->seq_num + i * 8 +
1249 j) &
1250 (MAX_TID_VALUE - 1);
1251 PRINTM(MEVENT,
1252 "Fw dropped packet, seq=%d start_win=%d, win_size=%d\n",
1253 seq_num,
1254 rx_reor_tbl_ptr->start_win,
1255 rx_reor_tbl_ptr->win_size);
1256 if (MLAN_STATUS_SUCCESS !=
1257 mlan_11n_rxreorder_pkt(
1258 priv, seq_num,
1259 tlv_rxba->tid,
1260 tlv_rxba->mac, 0,
1261 (t_void *)
1262 RX_PKT_DROPPED_IN_FW)) {
1263 PRINTM(MERROR,
1264 "Fail to handle dropped packet, seq=%d\n",
1265 seq_num);
1266 }
1267 }
1268 }
1269 }
1270 tlv_buf_left -= (sizeof(MrvlIEtypesHeader_t) + tlv_len);
1271 tlv_rxba =
1272 (MrvlIEtypes_RxBaSync_t *)((t_u8 *)tlv_rxba + tlv_len +
1273 sizeof(MrvlIEtypesHeader_t));
1274 }
1275 done:
1276 LEAVE();
1277 return;
1278 }
1279
1280 /**
1281 * @brief This function cleans up reorder tbl for specific station
1282 *
1283 * @param priv A pointer to mlan_private
1284 * @param ta ta to find in reordering table
1285 * @return N/A
1286 */
wlan_cleanup_reorder_tbl(mlan_private * priv,t_u8 * ta)1287 void wlan_cleanup_reorder_tbl(mlan_private *priv, t_u8 *ta)
1288 {
1289 RxReorderTbl *rx_reor_tbl_ptr = MNULL;
1290 t_u8 i;
1291 ENTER();
1292 for (i = 0; i < MAX_NUM_TID; ++i) {
1293 rx_reor_tbl_ptr = wlan_11n_get_rxreorder_tbl(priv, i, ta);
1294 if (rx_reor_tbl_ptr)
1295 wlan_11n_delete_rxreorder_tbl_entry(priv,
1296 rx_reor_tbl_ptr);
1297 }
1298 LEAVE();
1299 return;
1300 }
1301
1302 /**
1303 * @brief This function will set force_no_drop flag in rxreorder_tbl.
1304 *
1305 * @param priv A pointer to mlan_private
1306 * @param flag MTRUE/MFALSE
1307 *
1308 * @return N/A
1309 */
wlan_set_rxreorder_tbl_no_drop_flag(mlan_private * priv,t_u8 flag)1310 static void wlan_set_rxreorder_tbl_no_drop_flag(mlan_private *priv, t_u8 flag)
1311 {
1312 RxReorderTbl *rx_reor_tbl_ptr;
1313
1314 ENTER();
1315
1316 rx_reor_tbl_ptr = (RxReorderTbl *)util_peek_list(
1317 priv->adapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
1318 priv->adapter->callbacks.moal_spin_lock,
1319 priv->adapter->callbacks.moal_spin_unlock);
1320 if (!rx_reor_tbl_ptr) {
1321 LEAVE();
1322 return;
1323 }
1324
1325 while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
1326 rx_reor_tbl_ptr->force_no_drop = flag;
1327 rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
1328 }
1329
1330 LEAVE();
1331 return;
1332 }
1333
1334 /**
1335 * @brief This function update all the rx_reorder_tbl's force_no_drop flag
1336 *
1337 * @param pmadapter A pointer to mlan_adapter
1338 * @param flag MTRUE/MFALSE
1339 * @return N/A
1340 */
wlan_update_rxreorder_tbl(pmlan_adapter pmadapter,t_u8 flag)1341 void wlan_update_rxreorder_tbl(pmlan_adapter pmadapter, t_u8 flag)
1342 {
1343 t_u8 i;
1344 pmlan_private priv = MNULL;
1345 for (i = 0; i < pmadapter->priv_num; i++) {
1346 if (pmadapter->priv[i]) {
1347 priv = pmadapter->priv[i];
1348 wlan_set_rxreorder_tbl_no_drop_flag(priv, flag);
1349 }
1350 }
1351 return;
1352 }
1353
1354 /**
1355 * @brief This function will flush the data in rxreorder_tbl.
1356 * which has flush_data flag on.
1357 *
1358 * @param priv A pointer to mlan_private
1359 *
1360 * @return N/A
1361 */
wlan_flush_priv_rxreorder_tbl(mlan_private * priv)1362 static void wlan_flush_priv_rxreorder_tbl(mlan_private *priv)
1363 {
1364 RxReorderTbl *rx_reor_tbl_ptr;
1365
1366 ENTER();
1367
1368 rx_reor_tbl_ptr = (RxReorderTbl *)util_peek_list(
1369 priv->adapter->pmoal_handle, &priv->rx_reorder_tbl_ptr,
1370 priv->adapter->callbacks.moal_spin_lock,
1371 priv->adapter->callbacks.moal_spin_unlock);
1372 if (!rx_reor_tbl_ptr) {
1373 LEAVE();
1374 return;
1375 }
1376
1377 while (rx_reor_tbl_ptr != (RxReorderTbl *)&priv->rx_reorder_tbl_ptr) {
1378 if (rx_reor_tbl_ptr->flush_data) {
1379 rx_reor_tbl_ptr->flush_data = MFALSE;
1380 wlan_start_flush_data(priv, rx_reor_tbl_ptr);
1381 }
1382 rx_reor_tbl_ptr = rx_reor_tbl_ptr->pnext;
1383 }
1384
1385 LEAVE();
1386 return;
1387 }
1388
1389 /**
1390 * @brief This function update all the rx_reorder_tbl's force_no_drop flag
1391 *
1392 * @param pmadapter A pointer to mlan_adapter
1393 * @return N/A
1394 */
wlan_flush_rxreorder_tbl(pmlan_adapter pmadapter)1395 void wlan_flush_rxreorder_tbl(pmlan_adapter pmadapter)
1396 {
1397 t_u8 i;
1398 pmlan_private priv = MNULL;
1399 for (i = 0; i < pmadapter->priv_num; i++) {
1400 if (pmadapter->priv[i]) {
1401 priv = pmadapter->priv[i];
1402 wlan_flush_priv_rxreorder_tbl(priv);
1403 }
1404 }
1405 return;
1406 }
1407
1408 /**
1409 * @brief This function update all the rx_win_size based on coex flag
1410 *
1411 * @param pmadapter A pointer to mlan_adapter
1412 * @param coex_flag coex flag
1413 *
1414 * @return N/A
1415 */
wlan_update_ampdu_rxwinsize(pmlan_adapter pmadapter,t_u8 coex_flag)1416 static void wlan_update_ampdu_rxwinsize(pmlan_adapter pmadapter, t_u8 coex_flag)
1417 {
1418 t_u8 i;
1419 t_u8 j;
1420 t_u32 rx_win_size = 0;
1421 pmlan_private priv = MNULL;
1422
1423 ENTER();
1424 if (!pmadapter->coex_rx_winsize) {
1425 LEAVE();
1426 return;
1427 }
1428 PRINTM(MEVENT, "Update rxwinsize %d\n", coex_flag);
1429 for (i = 0; i < pmadapter->priv_num; i++) {
1430 if (pmadapter->priv[i]) {
1431 priv = pmadapter->priv[i];
1432 rx_win_size = priv->add_ba_param.rx_win_size;
1433 if (coex_flag == MTRUE) {
1434 #ifdef STA_SUPPORT
1435 if (priv->bss_type == MLAN_BSS_TYPE_STA)
1436 priv->add_ba_param.rx_win_size =
1437 MLAN_STA_COEX_AMPDU_DEF_RXWINSIZE;
1438 #endif
1439 #ifdef WIFI_DIRECT_SUPPORT
1440 if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT)
1441 priv->add_ba_param.rx_win_size =
1442 MLAN_WFD_COEX_AMPDU_DEF_RXWINSIZE;
1443 #endif
1444 #ifdef UAP_SUPPORT
1445 if (priv->bss_type == MLAN_BSS_TYPE_UAP)
1446 priv->add_ba_param.rx_win_size =
1447 MLAN_UAP_COEX_AMPDU_DEF_RXWINSIZE;
1448 #endif
1449 priv->add_ba_param.rx_win_size =
1450 MIN(priv->add_ba_param.rx_win_size,
1451 priv->user_rxwinsize);
1452 } else {
1453 priv->add_ba_param.rx_win_size =
1454 priv->user_rxwinsize;
1455 }
1456 if (pmadapter->coex_win_size &&
1457 pmadapter->coex_rx_win_size)
1458 priv->add_ba_param.rx_win_size =
1459 pmadapter->coex_rx_win_size;
1460 if (rx_win_size != priv->add_ba_param.rx_win_size) {
1461 if (priv->media_connected == MTRUE) {
1462 for (j = 0; j < MAX_NUM_TID; j++)
1463 wlan_11n_delba(priv, j);
1464 wlan_recv_event(
1465 priv,
1466 MLAN_EVENT_ID_DRV_DEFER_HANDLING,
1467 MNULL);
1468 }
1469 }
1470 }
1471 }
1472 LEAVE();
1473 return;
1474 }
1475
1476 /**
1477 * @brief check coex for
1478 *
1479 * @param pmadapter A pointer to mlan_adapter
1480 *
1481 * @return N/A
1482 */
wlan_coex_ampdu_rxwinsize(pmlan_adapter pmadapter)1483 void wlan_coex_ampdu_rxwinsize(pmlan_adapter pmadapter)
1484 {
1485 t_u8 i;
1486 pmlan_private priv = MNULL;
1487 t_u8 count = 0;
1488 for (i = 0; i < pmadapter->priv_num; i++) {
1489 if (pmadapter->priv[i]) {
1490 priv = pmadapter->priv[i];
1491 #ifdef STA_SUPPORT
1492 if (GET_BSS_ROLE((mlan_private *)priv) ==
1493 MLAN_BSS_ROLE_STA) {
1494 if (priv->media_connected == MTRUE)
1495 count++;
1496 }
1497 #endif
1498 #ifdef UAP_SUPPORT
1499 if (GET_BSS_ROLE((mlan_private *)priv) ==
1500 MLAN_BSS_ROLE_UAP) {
1501 if (priv->uap_bss_started)
1502 count++;
1503 }
1504 #endif
1505 }
1506 if (count >= 2)
1507 break;
1508 }
1509 if (count >= 2)
1510 wlan_update_ampdu_rxwinsize(pmadapter, MTRUE);
1511 else
1512 wlan_update_ampdu_rxwinsize(pmadapter, MFALSE);
1513 return;
1514 }
1515