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