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