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