1 /******************************************************************************
2  * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
3  *
4  * This program is distributed in the hope that it will be useful, but WITHOUT
5  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
6  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
7  * more details.
8  *
9  * The full GNU General Public License is included in this distribution in the
10  * file called LICENSE.
11  *
12  * Contact Information:
13  * wlanfae <wlanfae@realtek.com>
14  ******************************************************************************/
15 #include "rtllib.h"
16 #include <linux/etherdevice.h>
17 #include "rtl819x_TS.h"
18 
TsSetupTimeOut(struct timer_list * unused)19 static void TsSetupTimeOut(struct timer_list *unused)
20 {
21 }
22 
TsInactTimeout(struct timer_list * unused)23 static void TsInactTimeout(struct timer_list *unused)
24 {
25 }
26 
RxPktPendingTimeout(struct timer_list * t)27 static void RxPktPendingTimeout(struct timer_list *t)
28 {
29 	struct rx_ts_record *pRxTs = from_timer(pRxTs, t,
30 						     RxPktPendingTimer);
31 	struct rtllib_device *ieee = container_of(pRxTs, struct rtllib_device,
32 						  RxTsRecord[pRxTs->num]);
33 
34 	struct rx_reorder_entry *pReorderEntry = NULL;
35 
36 	unsigned long flags = 0;
37 	u8 index = 0;
38 	bool bPktInBuf = false;
39 
40 	spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
41 	if (pRxTs->RxTimeoutIndicateSeq != 0xffff) {
42 		while (!list_empty(&pRxTs->RxPendingPktList)) {
43 			pReorderEntry = (struct rx_reorder_entry *)
44 					list_entry(pRxTs->RxPendingPktList.prev,
45 					struct rx_reorder_entry, List);
46 			if (index == 0)
47 				pRxTs->RxIndicateSeq = pReorderEntry->SeqNum;
48 
49 			if (SN_LESS(pReorderEntry->SeqNum,
50 				    pRxTs->RxIndicateSeq) ||
51 			    SN_EQUAL(pReorderEntry->SeqNum,
52 				     pRxTs->RxIndicateSeq)) {
53 				list_del_init(&pReorderEntry->List);
54 
55 				if (SN_EQUAL(pReorderEntry->SeqNum,
56 				    pRxTs->RxIndicateSeq))
57 					pRxTs->RxIndicateSeq =
58 					      (pRxTs->RxIndicateSeq + 1) % 4096;
59 
60 				netdev_dbg(ieee->dev,
61 					   "%s(): Indicate SeqNum: %d\n",
62 					   __func__, pReorderEntry->SeqNum);
63 				ieee->stats_IndicateArray[index] =
64 							 pReorderEntry->prxb;
65 				index++;
66 
67 				list_add_tail(&pReorderEntry->List,
68 					      &ieee->RxReorder_Unused_List);
69 			} else {
70 				bPktInBuf = true;
71 				break;
72 			}
73 		}
74 	}
75 
76 	if (index > 0) {
77 		pRxTs->RxTimeoutIndicateSeq = 0xffff;
78 
79 		if (index > REORDER_WIN_SIZE) {
80 			netdev_warn(ieee->dev,
81 				    "%s(): Rx Reorder struct buffer full\n",
82 				    __func__);
83 			spin_unlock_irqrestore(&(ieee->reorder_spinlock),
84 					       flags);
85 			return;
86 		}
87 		rtllib_indicate_packets(ieee, ieee->stats_IndicateArray, index);
88 		bPktInBuf = false;
89 	}
90 
91 	if (bPktInBuf && (pRxTs->RxTimeoutIndicateSeq == 0xffff)) {
92 		pRxTs->RxTimeoutIndicateSeq = pRxTs->RxIndicateSeq;
93 		mod_timer(&pRxTs->RxPktPendingTimer,  jiffies +
94 			  msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime)
95 			  );
96 	}
97 	spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
98 }
99 
TsAddBaProcess(struct timer_list * t)100 static void TsAddBaProcess(struct timer_list *t)
101 {
102 	struct tx_ts_record *pTxTs = from_timer(pTxTs, t, TsAddBaTimer);
103 	u8 num = pTxTs->num;
104 	struct rtllib_device *ieee = container_of(pTxTs, struct rtllib_device,
105 				     TxTsRecord[num]);
106 
107 	TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false);
108 	netdev_dbg(ieee->dev, "%s(): ADDBA Req is started\n", __func__);
109 }
110 
ResetTsCommonInfo(struct ts_common_info * pTsCommonInfo)111 static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo)
112 {
113 	eth_zero_addr(pTsCommonInfo->Addr);
114 	memset(&pTsCommonInfo->TSpec, 0, sizeof(union tspec_body));
115 	memset(&pTsCommonInfo->TClass, 0, sizeof(union qos_tclas)*TCLAS_NUM);
116 	pTsCommonInfo->TClasProc = 0;
117 	pTsCommonInfo->TClasNum = 0;
118 }
119 
ResetTxTsEntry(struct tx_ts_record * pTS)120 static void ResetTxTsEntry(struct tx_ts_record *pTS)
121 {
122 	ResetTsCommonInfo(&pTS->TsCommonInfo);
123 	pTS->TxCurSeq = 0;
124 	pTS->bAddBaReqInProgress = false;
125 	pTS->bAddBaReqDelayed = false;
126 	pTS->bUsingBa = false;
127 	pTS->bDisable_AddBa = false;
128 	ResetBaEntry(&pTS->TxAdmittedBARecord);
129 	ResetBaEntry(&pTS->TxPendingBARecord);
130 }
131 
ResetRxTsEntry(struct rx_ts_record * pTS)132 static void ResetRxTsEntry(struct rx_ts_record *pTS)
133 {
134 	ResetTsCommonInfo(&pTS->TsCommonInfo);
135 	pTS->RxIndicateSeq = 0xffff;
136 	pTS->RxTimeoutIndicateSeq = 0xffff;
137 	ResetBaEntry(&pTS->RxAdmittedBARecord);
138 }
139 
TSInitialize(struct rtllib_device * ieee)140 void TSInitialize(struct rtllib_device *ieee)
141 {
142 	struct tx_ts_record *pTxTS  = ieee->TxTsRecord;
143 	struct rx_ts_record *pRxTS  = ieee->RxTsRecord;
144 	struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry;
145 	u8				count = 0;
146 
147 	netdev_vdbg(ieee->dev, "%s()\n", __func__);
148 	INIT_LIST_HEAD(&ieee->Tx_TS_Admit_List);
149 	INIT_LIST_HEAD(&ieee->Tx_TS_Pending_List);
150 	INIT_LIST_HEAD(&ieee->Tx_TS_Unused_List);
151 
152 	for (count = 0; count < TOTAL_TS_NUM; count++) {
153 		pTxTS->num = count;
154 		timer_setup(&pTxTS->TsCommonInfo.SetupTimer, TsSetupTimeOut,
155 			    0);
156 
157 		timer_setup(&pTxTS->TsCommonInfo.InactTimer, TsInactTimeout,
158 			    0);
159 
160 		timer_setup(&pTxTS->TsAddBaTimer, TsAddBaProcess, 0);
161 
162 		timer_setup(&pTxTS->TxPendingBARecord.Timer, BaSetupTimeOut,
163 			    0);
164 		timer_setup(&pTxTS->TxAdmittedBARecord.Timer,
165 			    TxBaInactTimeout, 0);
166 
167 		ResetTxTsEntry(pTxTS);
168 		list_add_tail(&pTxTS->TsCommonInfo.List,
169 				&ieee->Tx_TS_Unused_List);
170 		pTxTS++;
171 	}
172 
173 	INIT_LIST_HEAD(&ieee->Rx_TS_Admit_List);
174 	INIT_LIST_HEAD(&ieee->Rx_TS_Pending_List);
175 	INIT_LIST_HEAD(&ieee->Rx_TS_Unused_List);
176 	for (count = 0; count < TOTAL_TS_NUM; count++) {
177 		pRxTS->num = count;
178 		INIT_LIST_HEAD(&pRxTS->RxPendingPktList);
179 
180 		timer_setup(&pRxTS->TsCommonInfo.SetupTimer, TsSetupTimeOut,
181 			    0);
182 
183 		timer_setup(&pRxTS->TsCommonInfo.InactTimer, TsInactTimeout,
184 			    0);
185 
186 		timer_setup(&pRxTS->RxAdmittedBARecord.Timer,
187 			    RxBaInactTimeout, 0);
188 
189 		timer_setup(&pRxTS->RxPktPendingTimer, RxPktPendingTimeout, 0);
190 
191 		ResetRxTsEntry(pRxTS);
192 		list_add_tail(&pRxTS->TsCommonInfo.List,
193 			      &ieee->Rx_TS_Unused_List);
194 		pRxTS++;
195 	}
196 	INIT_LIST_HEAD(&ieee->RxReorder_Unused_List);
197 	for (count = 0; count < REORDER_ENTRY_NUM; count++) {
198 		list_add_tail(&pRxReorderEntry->List,
199 			      &ieee->RxReorder_Unused_List);
200 		if (count == (REORDER_ENTRY_NUM-1))
201 			break;
202 		pRxReorderEntry = &ieee->RxReorderEntry[count+1];
203 	}
204 
205 }
206 
AdmitTS(struct rtllib_device * ieee,struct ts_common_info * pTsCommonInfo,u32 InactTime)207 static void AdmitTS(struct rtllib_device *ieee,
208 		    struct ts_common_info *pTsCommonInfo, u32 InactTime)
209 {
210 	del_timer_sync(&pTsCommonInfo->SetupTimer);
211 	del_timer_sync(&pTsCommonInfo->InactTimer);
212 
213 	if (InactTime != 0)
214 		mod_timer(&pTsCommonInfo->InactTimer, jiffies +
215 			  msecs_to_jiffies(InactTime));
216 }
217 
SearchAdmitTRStream(struct rtllib_device * ieee,u8 * Addr,u8 TID,enum tr_select TxRxSelect)218 static struct ts_common_info *SearchAdmitTRStream(struct rtllib_device *ieee,
219 						  u8 *Addr, u8 TID,
220 						  enum tr_select TxRxSelect)
221 {
222 	u8	dir;
223 	bool	search_dir[4] = {0};
224 	struct list_head *psearch_list;
225 	struct ts_common_info *pRet = NULL;
226 
227 	if (ieee->iw_mode == IW_MODE_MASTER) {
228 		if (TxRxSelect == TX_DIR) {
229 			search_dir[DIR_DOWN] = true;
230 			search_dir[DIR_BI_DIR] = true;
231 		} else {
232 			search_dir[DIR_UP] = true;
233 			search_dir[DIR_BI_DIR] = true;
234 		}
235 	} else if (ieee->iw_mode == IW_MODE_ADHOC) {
236 		if (TxRxSelect == TX_DIR)
237 			search_dir[DIR_UP] = true;
238 		else
239 			search_dir[DIR_DOWN] = true;
240 	} else {
241 		if (TxRxSelect == TX_DIR) {
242 			search_dir[DIR_UP] = true;
243 			search_dir[DIR_BI_DIR] = true;
244 			search_dir[DIR_DIRECT] = true;
245 		} else {
246 			search_dir[DIR_DOWN] = true;
247 			search_dir[DIR_BI_DIR] = true;
248 			search_dir[DIR_DIRECT] = true;
249 		}
250 	}
251 
252 	if (TxRxSelect == TX_DIR)
253 		psearch_list = &ieee->Tx_TS_Admit_List;
254 	else
255 		psearch_list = &ieee->Rx_TS_Admit_List;
256 
257 	for (dir = 0; dir <= DIR_BI_DIR; dir++) {
258 		if (!search_dir[dir])
259 			continue;
260 		list_for_each_entry(pRet, psearch_list, List) {
261 			if (memcmp(pRet->Addr, Addr, 6) == 0 &&
262 			    pRet->TSpec.f.TSInfo.field.ucTSID == TID &&
263 			    pRet->TSpec.f.TSInfo.field.ucDirection == dir)
264 				break;
265 
266 		}
267 		if (&pRet->List  != psearch_list)
268 			break;
269 	}
270 
271 	if (pRet && &pRet->List  != psearch_list)
272 		return pRet;
273 	return NULL;
274 }
275 
MakeTSEntry(struct ts_common_info * pTsCommonInfo,u8 * Addr,union tspec_body * pTSPEC,union qos_tclas * pTCLAS,u8 TCLAS_Num,u8 TCLAS_Proc)276 static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr,
277 			union tspec_body *pTSPEC, union qos_tclas *pTCLAS,
278 			u8 TCLAS_Num, u8 TCLAS_Proc)
279 {
280 	u8	count;
281 
282 	if (pTsCommonInfo == NULL)
283 		return;
284 
285 	memcpy(pTsCommonInfo->Addr, Addr, 6);
286 
287 	if (pTSPEC != NULL)
288 		memcpy((u8 *)(&(pTsCommonInfo->TSpec)), (u8 *)pTSPEC,
289 			sizeof(union tspec_body));
290 
291 	for (count = 0; count < TCLAS_Num; count++)
292 		memcpy((u8 *)(&(pTsCommonInfo->TClass[count])),
293 		       (u8 *)pTCLAS, sizeof(union qos_tclas));
294 
295 	pTsCommonInfo->TClasProc = TCLAS_Proc;
296 	pTsCommonInfo->TClasNum = TCLAS_Num;
297 }
298 
GetTs(struct rtllib_device * ieee,struct ts_common_info ** ppTS,u8 * Addr,u8 TID,enum tr_select TxRxSelect,bool bAddNewTs)299 bool GetTs(struct rtllib_device *ieee, struct ts_common_info **ppTS,
300 	   u8 *Addr, u8 TID, enum tr_select TxRxSelect, bool bAddNewTs)
301 {
302 	u8	UP = 0;
303 	union tspec_body TSpec;
304 	union qos_tsinfo *pTSInfo = &TSpec.f.TSInfo;
305 	struct list_head *pUnusedList;
306 	struct list_head *pAddmitList;
307 	enum direction_value Dir;
308 
309 	if (is_multicast_ether_addr(Addr)) {
310 		netdev_warn(ieee->dev, "Get TS for Broadcast or Multicast\n");
311 		return false;
312 	}
313 	if (ieee->current_network.qos_data.supported == 0) {
314 		UP = 0;
315 	} else {
316 		switch (TID) {
317 		case 0:
318 		case 3:
319 			UP = 0;
320 			break;
321 		case 1:
322 		case 2:
323 			UP = 2;
324 			break;
325 		case 4:
326 		case 5:
327 			UP = 5;
328 			break;
329 		case 6:
330 		case 7:
331 			UP = 7;
332 			break;
333 		default:
334 			netdev_warn(ieee->dev, "%s(): TID(%d) is not valid\n",
335 				    __func__, TID);
336 			return false;
337 		}
338 	}
339 
340 	*ppTS = SearchAdmitTRStream(ieee, Addr, UP, TxRxSelect);
341 	if (*ppTS != NULL)
342 		return true;
343 
344 	if (!bAddNewTs) {
345 		netdev_dbg(ieee->dev, "add new TS failed(tid:%d)\n", UP);
346 		return false;
347 	}
348 
349 	pUnusedList = (TxRxSelect == TX_DIR) ?
350 				(&ieee->Tx_TS_Unused_List) :
351 				(&ieee->Rx_TS_Unused_List);
352 
353 	pAddmitList = (TxRxSelect == TX_DIR) ?
354 				(&ieee->Tx_TS_Admit_List) :
355 				(&ieee->Rx_TS_Admit_List);
356 
357 	Dir = (ieee->iw_mode == IW_MODE_MASTER) ?
358 				((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) :
359 				((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN);
360 
361 	if (!list_empty(pUnusedList)) {
362 		(*ppTS) = list_entry(pUnusedList->next,
363 			  struct ts_common_info, List);
364 		list_del_init(&(*ppTS)->List);
365 		if (TxRxSelect == TX_DIR) {
366 			struct tx_ts_record *tmp =
367 				container_of(*ppTS,
368 				struct tx_ts_record,
369 				TsCommonInfo);
370 			ResetTxTsEntry(tmp);
371 		} else {
372 			struct rx_ts_record *tmp =
373 				 container_of(*ppTS,
374 				 struct rx_ts_record,
375 				 TsCommonInfo);
376 			ResetRxTsEntry(tmp);
377 		}
378 
379 		netdev_dbg(ieee->dev,
380 			   "to init current TS, UP:%d, Dir:%d, addr: %pM ppTs=%p\n",
381 			   UP, Dir, Addr, *ppTS);
382 		pTSInfo->field.ucTrafficType = 0;
383 		pTSInfo->field.ucTSID = UP;
384 		pTSInfo->field.ucDirection = Dir;
385 		pTSInfo->field.ucAccessPolicy = 1;
386 		pTSInfo->field.ucAggregation = 0;
387 		pTSInfo->field.ucPSB = 0;
388 		pTSInfo->field.ucUP = UP;
389 		pTSInfo->field.ucTSInfoAckPolicy = 0;
390 		pTSInfo->field.ucSchedule = 0;
391 
392 		MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0);
393 		AdmitTS(ieee, *ppTS, 0);
394 		list_add_tail(&((*ppTS)->List), pAddmitList);
395 
396 		return true;
397 	}
398 
399 	netdev_warn(ieee->dev,
400 		    "There is not enough dir=%d(0=up down=1) TS record to be used!",
401 		    Dir);
402 	return false;
403 }
404 
RemoveTsEntry(struct rtllib_device * ieee,struct ts_common_info * pTs,enum tr_select TxRxSelect)405 static void RemoveTsEntry(struct rtllib_device *ieee,
406 			  struct ts_common_info *pTs, enum tr_select TxRxSelect)
407 {
408 	del_timer_sync(&pTs->SetupTimer);
409 	del_timer_sync(&pTs->InactTimer);
410 	TsInitDelBA(ieee, pTs, TxRxSelect);
411 
412 	if (TxRxSelect == RX_DIR) {
413 		struct rx_reorder_entry *pRxReorderEntry;
414 		struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs;
415 
416 		if (timer_pending(&pRxTS->RxPktPendingTimer))
417 			del_timer_sync(&pRxTS->RxPktPendingTimer);
418 
419 		while (!list_empty(&pRxTS->RxPendingPktList)) {
420 			pRxReorderEntry = (struct rx_reorder_entry *)
421 					list_entry(pRxTS->RxPendingPktList.prev,
422 					struct rx_reorder_entry, List);
423 			netdev_dbg(ieee->dev,  "%s(): Delete SeqNum %d!\n",
424 				   __func__, pRxReorderEntry->SeqNum);
425 			list_del_init(&pRxReorderEntry->List);
426 			{
427 				int i = 0;
428 				struct rtllib_rxb *prxb = pRxReorderEntry->prxb;
429 
430 				if (unlikely(!prxb))
431 					return;
432 				for (i = 0; i < prxb->nr_subframes; i++)
433 					dev_kfree_skb(prxb->subframes[i]);
434 				kfree(prxb);
435 				prxb = NULL;
436 			}
437 			list_add_tail(&pRxReorderEntry->List,
438 				      &ieee->RxReorder_Unused_List);
439 		}
440 	} else {
441 		struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs;
442 
443 		del_timer_sync(&pTxTS->TsAddBaTimer);
444 	}
445 }
446 
RemovePeerTS(struct rtllib_device * ieee,u8 * Addr)447 void RemovePeerTS(struct rtllib_device *ieee, u8 *Addr)
448 {
449 	struct ts_common_info *pTS, *pTmpTS;
450 
451 	netdev_info(ieee->dev, "===========>RemovePeerTS, %pM\n", Addr);
452 
453 	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) {
454 		if (memcmp(pTS->Addr, Addr, 6) == 0) {
455 			RemoveTsEntry(ieee, pTS, TX_DIR);
456 			list_del_init(&pTS->List);
457 			list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
458 		}
459 	}
460 
461 	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) {
462 		if (memcmp(pTS->Addr, Addr, 6) == 0) {
463 			netdev_info(ieee->dev,
464 				    "====>remove Tx_TS_admin_list\n");
465 			RemoveTsEntry(ieee, pTS, TX_DIR);
466 			list_del_init(&pTS->List);
467 			list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
468 		}
469 	}
470 
471 	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) {
472 		if (memcmp(pTS->Addr, Addr, 6) == 0) {
473 			RemoveTsEntry(ieee, pTS, RX_DIR);
474 			list_del_init(&pTS->List);
475 			list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
476 		}
477 	}
478 
479 	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) {
480 		if (memcmp(pTS->Addr, Addr, 6) == 0) {
481 			RemoveTsEntry(ieee, pTS, RX_DIR);
482 			list_del_init(&pTS->List);
483 			list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
484 		}
485 	}
486 }
487 EXPORT_SYMBOL(RemovePeerTS);
488 
RemoveAllTS(struct rtllib_device * ieee)489 void RemoveAllTS(struct rtllib_device *ieee)
490 {
491 	struct ts_common_info *pTS, *pTmpTS;
492 
493 	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, List) {
494 		RemoveTsEntry(ieee, pTS, TX_DIR);
495 		list_del_init(&pTS->List);
496 		list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
497 	}
498 
499 	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, List) {
500 		RemoveTsEntry(ieee, pTS, TX_DIR);
501 		list_del_init(&pTS->List);
502 		list_add_tail(&pTS->List, &ieee->Tx_TS_Unused_List);
503 	}
504 
505 	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, List) {
506 		RemoveTsEntry(ieee, pTS, RX_DIR);
507 		list_del_init(&pTS->List);
508 		list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
509 	}
510 
511 	list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, List) {
512 		RemoveTsEntry(ieee, pTS, RX_DIR);
513 		list_del_init(&pTS->List);
514 		list_add_tail(&pTS->List, &ieee->Rx_TS_Unused_List);
515 	}
516 }
517 
TsStartAddBaProcess(struct rtllib_device * ieee,struct tx_ts_record * pTxTS)518 void TsStartAddBaProcess(struct rtllib_device *ieee, struct tx_ts_record *pTxTS)
519 {
520 	if (pTxTS->bAddBaReqInProgress == false) {
521 		pTxTS->bAddBaReqInProgress = true;
522 
523 		if (pTxTS->bAddBaReqDelayed) {
524 			netdev_dbg(ieee->dev, "Start ADDBA after 60 sec!!\n");
525 			mod_timer(&pTxTS->TsAddBaTimer, jiffies +
526 				  msecs_to_jiffies(TS_ADDBA_DELAY));
527 		} else {
528 			netdev_dbg(ieee->dev, "Immediately Start ADDBA\n");
529 			mod_timer(&pTxTS->TsAddBaTimer, jiffies+10);
530 		}
531 	} else
532 		netdev_dbg(ieee->dev, "BA timer is already added\n");
533 }
534