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