1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/etherdevice.h>
4 #include <linux/slab.h>
5 #include "rtl819x_TS.h"
7 static void TsSetupTimeOut(struct timer_list
*unused
)
10 // This is used for WMMSA and ACM , that would send ADDTSReq frame.
13 static void TsInactTimeout(struct timer_list
*unused
)
16 // This is used for WMMSA and ACM.
17 // This function would be call when TS is no Tx/Rx for some period of time.
20 /********************************************************************************************************************
21 *function: I still not understand this function, so wait for further implementation
22 * input: unsigned long data //acturally we send struct tx_ts_record or RX_TS_RECORD to these timer
25 ********************************************************************************************************************/
26 static void RxPktPendingTimeout(struct timer_list
*t
)
28 PRX_TS_RECORD pRxTs
= from_timer(pRxTs
, t
, RxPktPendingTimer
);
29 struct ieee80211_device
*ieee
= container_of(pRxTs
, struct ieee80211_device
, RxTsRecord
[pRxTs
->num
]);
31 PRX_REORDER_ENTRY pReorderEntry
= NULL
;
34 unsigned long flags
= 0;
36 bool bPktInBuf
= false;
38 spin_lock_irqsave(&(ieee
->reorder_spinlock
), flags
);
39 IEEE80211_DEBUG(IEEE80211_DL_REORDER
,"==================>%s()\n",__func__
);
40 if(pRxTs
->RxTimeoutIndicateSeq
!= 0xffff) {
41 // Indicate the pending packets sequentially according to SeqNum until meet the gap.
42 while(!list_empty(&pRxTs
->RxPendingPktList
)) {
43 pReorderEntry
= (PRX_REORDER_ENTRY
)list_entry(pRxTs
->RxPendingPktList
.prev
,RX_REORDER_ENTRY
,List
);
45 pRxTs
->RxIndicateSeq
= pReorderEntry
->SeqNum
;
47 if( SN_LESS(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
) ||
48 SN_EQUAL(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
) ) {
49 list_del_init(&pReorderEntry
->List
);
51 if(SN_EQUAL(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
))
52 pRxTs
->RxIndicateSeq
= (pRxTs
->RxIndicateSeq
+ 1) % 4096;
54 IEEE80211_DEBUG(IEEE80211_DL_REORDER
,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry
->SeqNum
);
55 ieee
->stats_IndicateArray
[index
] = pReorderEntry
->prxb
;
58 list_add_tail(&pReorderEntry
->List
, &ieee
->RxReorder_Unused_List
);
67 // Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now.
68 pRxTs
->RxTimeoutIndicateSeq
= 0xffff;
71 if(index
> REORDER_WIN_SIZE
) {
72 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "RxReorderIndicatePacket(): Rx Reorder buffer full!! \n");
73 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
76 ieee80211_indicate_packets(ieee
, ieee
->stats_IndicateArray
, index
);
79 if(bPktInBuf
&& (pRxTs
->RxTimeoutIndicateSeq
==0xffff)) {
80 pRxTs
->RxTimeoutIndicateSeq
= pRxTs
->RxIndicateSeq
;
81 mod_timer(&pRxTs
->RxPktPendingTimer
,
82 jiffies
+ msecs_to_jiffies(ieee
->pHTInfo
->RxReorderPendingTime
));
84 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
87 /********************************************************************************************************************
88 *function: Add BA timer function
89 * input: unsigned long data //acturally we send struct tx_ts_record or RX_TS_RECORD to these timer
92 ********************************************************************************************************************/
93 static void TsAddBaProcess(struct timer_list
*t
)
95 struct tx_ts_record
*pTxTs
= from_timer(pTxTs
, t
, TsAddBaTimer
);
97 struct ieee80211_device
*ieee
= container_of(pTxTs
, struct ieee80211_device
, TxTsRecord
[num
]);
99 TsInitAddBA(ieee
, pTxTs
, BA_POLICY_IMMEDIATE
, false);
100 IEEE80211_DEBUG(IEEE80211_DL_BA
, "TsAddBaProcess(): ADDBA Req is started!! \n");
104 static void ResetTsCommonInfo(struct ts_common_info
*pTsCommonInfo
)
106 eth_zero_addr(pTsCommonInfo
->addr
);
107 memset(&pTsCommonInfo
->t_spec
, 0, sizeof(TSPEC_BODY
));
108 memset(&pTsCommonInfo
->t_class
, 0, sizeof(QOS_TCLAS
)*TCLAS_NUM
);
109 pTsCommonInfo
->t_clas_proc
= 0;
110 pTsCommonInfo
->t_clas_num
= 0;
113 static void ResetTxTsEntry(struct tx_ts_record
*pTS
)
115 ResetTsCommonInfo(&pTS
->TsCommonInfo
);
117 pTS
->bAddBaReqInProgress
= false;
118 pTS
->bAddBaReqDelayed
= false;
119 pTS
->bUsingBa
= false;
120 ResetBaEntry(&pTS
->TxAdmittedBARecord
); //For BA Originator
121 ResetBaEntry(&pTS
->TxPendingBARecord
);
124 static void ResetRxTsEntry(PRX_TS_RECORD pTS
)
126 ResetTsCommonInfo(&pTS
->TsCommonInfo
);
127 pTS
->RxIndicateSeq
= 0xffff; // This indicate the RxIndicateSeq is not used now!!
128 pTS
->RxTimeoutIndicateSeq
= 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!!
129 ResetBaEntry(&pTS
->RxAdmittedBARecord
); // For BA Recipient
132 void TSInitialize(struct ieee80211_device
*ieee
)
134 struct tx_ts_record
*pTxTS
= ieee
->TxTsRecord
;
135 PRX_TS_RECORD pRxTS
= ieee
->RxTsRecord
;
136 PRX_REORDER_ENTRY pRxReorderEntry
= ieee
->RxReorderEntry
;
138 IEEE80211_DEBUG(IEEE80211_DL_TS
, "==========>%s()\n", __func__
);
139 // Initialize Tx TS related info.
140 INIT_LIST_HEAD(&ieee
->Tx_TS_Admit_List
);
141 INIT_LIST_HEAD(&ieee
->Tx_TS_Pending_List
);
142 INIT_LIST_HEAD(&ieee
->Tx_TS_Unused_List
);
144 for(count
= 0; count
< TOTAL_TS_NUM
; count
++) {
147 // The timers for the operation of Traffic Stream and Block Ack.
148 // DLS related timer will be add here in the future!!
149 timer_setup(&pTxTS
->TsCommonInfo
.setup_timer
, TsSetupTimeOut
,
151 timer_setup(&pTxTS
->TsCommonInfo
.inact_timer
, TsInactTimeout
,
153 timer_setup(&pTxTS
->TsAddBaTimer
, TsAddBaProcess
, 0);
154 timer_setup(&pTxTS
->TxPendingBARecord
.Timer
, BaSetupTimeOut
,
156 timer_setup(&pTxTS
->TxAdmittedBARecord
.Timer
,
157 TxBaInactTimeout
, 0);
158 ResetTxTsEntry(pTxTS
);
159 list_add_tail(&pTxTS
->TsCommonInfo
.list
, &ieee
->Tx_TS_Unused_List
);
163 // Initialize Rx TS related info.
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
++) {
169 INIT_LIST_HEAD(&pRxTS
->RxPendingPktList
);
170 timer_setup(&pRxTS
->TsCommonInfo
.setup_timer
, TsSetupTimeOut
,
172 timer_setup(&pRxTS
->TsCommonInfo
.inact_timer
, TsInactTimeout
,
174 timer_setup(&pRxTS
->RxAdmittedBARecord
.Timer
,
175 RxBaInactTimeout
, 0);
176 timer_setup(&pRxTS
->RxPktPendingTimer
, RxPktPendingTimeout
, 0);
177 ResetRxTsEntry(pRxTS
);
178 list_add_tail(&pRxTS
->TsCommonInfo
.list
, &ieee
->Rx_TS_Unused_List
);
181 // Initialize unused Rx Reorder List.
182 INIT_LIST_HEAD(&ieee
->RxReorder_Unused_List
);
184 for(count
= 0; count
< REORDER_ENTRY_NUM
; count
++) {
185 list_add_tail( &pRxReorderEntry
->List
,&ieee
->RxReorder_Unused_List
);
186 if(count
== (REORDER_ENTRY_NUM
-1))
188 pRxReorderEntry
= &ieee
->RxReorderEntry
[count
+1];
193 static void AdmitTS(struct ieee80211_device
*ieee
,
194 struct ts_common_info
*pTsCommonInfo
, u32 InactTime
)
196 del_timer_sync(&pTsCommonInfo
->setup_timer
);
197 del_timer_sync(&pTsCommonInfo
->inact_timer
);
200 mod_timer(&pTsCommonInfo
->inact_timer
,
201 jiffies
+ msecs_to_jiffies(InactTime
));
205 static struct ts_common_info
*SearchAdmitTRStream(struct ieee80211_device
*ieee
,
207 enum tr_select TxRxSelect
)
209 //DIRECTION_VALUE dir;
211 bool search_dir
[4] = {0};
212 struct list_head
*psearch_list
; //FIXME
213 struct ts_common_info
*pRet
= NULL
;
214 if(ieee
->iw_mode
== IW_MODE_MASTER
) { //ap mode
215 if(TxRxSelect
== TX_DIR
) {
216 search_dir
[DIR_DOWN
] = true;
217 search_dir
[DIR_BI_DIR
]= true;
219 search_dir
[DIR_UP
] = true;
220 search_dir
[DIR_BI_DIR
]= true;
222 } else if(ieee
->iw_mode
== IW_MODE_ADHOC
) {
223 if(TxRxSelect
== TX_DIR
)
224 search_dir
[DIR_UP
] = true;
226 search_dir
[DIR_DOWN
] = true;
228 if(TxRxSelect
== TX_DIR
) {
229 search_dir
[DIR_UP
] = true;
230 search_dir
[DIR_BI_DIR
]= true;
231 search_dir
[DIR_DIRECT
]= true;
233 search_dir
[DIR_DOWN
] = true;
234 search_dir
[DIR_BI_DIR
]= true;
235 search_dir
[DIR_DIRECT
]= true;
239 if(TxRxSelect
== TX_DIR
)
240 psearch_list
= &ieee
->Tx_TS_Admit_List
;
242 psearch_list
= &ieee
->Rx_TS_Admit_List
;
244 //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
245 for(dir
= 0; dir
<= DIR_BI_DIR
; dir
++) {
246 if (!search_dir
[dir
])
248 list_for_each_entry(pRet
, psearch_list
, list
){
249 // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.f.TSInfo.field.ucTSID, pRet->TSpec.f.TSInfo.field.ucDirection);
250 if (memcmp(pRet
->addr
, Addr
, 6) == 0)
251 if (pRet
->t_spec
.f
.TSInfo
.field
.ucTSID
== TID
)
252 if(pRet
->t_spec
.f
.TSInfo
.field
.ucDirection
== dir
) {
253 // printk("Bingo! got it\n");
257 if(&pRet
->list
!= psearch_list
)
261 if(&pRet
->list
!= psearch_list
)
267 static void MakeTSEntry(struct ts_common_info
*pTsCommonInfo
, u8
*Addr
,
268 PTSPEC_BODY pTSPEC
, PQOS_TCLAS pTCLAS
, u8 TCLAS_Num
,
273 if(pTsCommonInfo
== NULL
)
276 memcpy(pTsCommonInfo
->addr
, Addr
, 6);
279 memcpy((u8
*)(&(pTsCommonInfo
->t_spec
)), (u8
*)pTSPEC
, sizeof(TSPEC_BODY
));
281 for(count
= 0; count
< TCLAS_Num
; count
++)
282 memcpy((u8
*)(&(pTsCommonInfo
->t_class
[count
])), (u8
*)pTCLAS
, sizeof(QOS_TCLAS
));
284 pTsCommonInfo
->t_clas_proc
= TCLAS_Proc
;
285 pTsCommonInfo
->t_clas_num
= TCLAS_Num
;
290 struct ieee80211_device
*ieee
,
291 struct ts_common_info
**ppTS
,
294 enum tr_select TxRxSelect
, //Rx:1, Tx:0
300 // We do not build any TS for Broadcast or Multicast stream.
301 // So reject these kinds of search here.
303 if (is_multicast_ether_addr(Addr
)) {
304 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "get TS for Broadcast or Multicast\n");
308 if (ieee
->current_network
.qos_data
.supported
== 0) {
311 // In WMM case: we use 4 TID only
312 if (!IsACValid(TID
)) {
313 IEEE80211_DEBUG(IEEE80211_DL_ERR
, " in %s(), TID(%d) is not valid\n", __func__
, TID
);
340 *ppTS
= SearchAdmitTRStream(
349 IEEE80211_DEBUG(IEEE80211_DL_TS
, "add new TS failed(tid:%d)\n", UP
);
353 // Create a new Traffic stream for current Tx/Rx
354 // This is for EDCA and WMM to add a new TS.
355 // For HCCA or WMMSA, TS cannot be addmit without negotiation.
358 PQOS_TSINFO pTSInfo
= &TSpec
.f
.TSInfo
;
359 struct list_head
*pUnusedList
=
360 (TxRxSelect
== TX_DIR
)?
361 (&ieee
->Tx_TS_Unused_List
):
362 (&ieee
->Rx_TS_Unused_List
);
364 struct list_head
*pAddmitList
=
365 (TxRxSelect
== TX_DIR
)?
366 (&ieee
->Tx_TS_Admit_List
):
367 (&ieee
->Rx_TS_Admit_List
);
369 DIRECTION_VALUE Dir
= (ieee
->iw_mode
== IW_MODE_MASTER
)?
370 ((TxRxSelect
==TX_DIR
)?DIR_DOWN
:DIR_UP
):
371 ((TxRxSelect
==TX_DIR
)?DIR_UP
:DIR_DOWN
);
372 IEEE80211_DEBUG(IEEE80211_DL_TS
, "to add Ts\n");
373 if(!list_empty(pUnusedList
)) {
374 (*ppTS
) = list_entry(pUnusedList
->next
, struct ts_common_info
, list
);
375 list_del_init(&(*ppTS
)->list
);
376 if(TxRxSelect
==TX_DIR
) {
377 struct tx_ts_record
*tmp
= container_of(*ppTS
, struct tx_ts_record
, TsCommonInfo
);
380 PRX_TS_RECORD tmp
= container_of(*ppTS
, RX_TS_RECORD
, TsCommonInfo
);
384 IEEE80211_DEBUG(IEEE80211_DL_TS
, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP
, Dir
, Addr
);
385 // Prepare TS Info releated field
386 pTSInfo
->field
.ucTrafficType
= 0; // Traffic type: WMM is reserved in this field
387 pTSInfo
->field
.ucTSID
= UP
; // TSID
388 pTSInfo
->field
.ucDirection
= Dir
; // Direction: if there is DirectLink, this need additional consideration.
389 pTSInfo
->field
.ucAccessPolicy
= 1; // Access policy
390 pTSInfo
->field
.ucAggregation
= 0; // Aggregation
391 pTSInfo
->field
.ucPSB
= 0; // Aggregation
392 pTSInfo
->field
.ucUP
= UP
; // User priority
393 pTSInfo
->field
.ucTSInfoAckPolicy
= 0; // Ack policy
394 pTSInfo
->field
.ucSchedule
= 0; // Schedule
396 MakeTSEntry(*ppTS
, Addr
, &TSpec
, NULL
, 0, 0);
397 AdmitTS(ieee
, *ppTS
, 0);
398 list_add_tail(&((*ppTS
)->list
), pAddmitList
);
399 // if there is DirectLink, we need to do additional operation here!!
403 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "in function %s() There is not enough TS record to be used!!", __func__
);
410 static void RemoveTsEntry(struct ieee80211_device
*ieee
, struct ts_common_info
*pTs
,
411 enum tr_select TxRxSelect
)
414 unsigned long flags
= 0;
415 del_timer_sync(&pTs
->setup_timer
);
416 del_timer_sync(&pTs
->inact_timer
);
417 TsInitDelBA(ieee
, pTs
, TxRxSelect
);
419 if(TxRxSelect
== RX_DIR
) {
421 PRX_REORDER_ENTRY pRxReorderEntry
;
422 PRX_TS_RECORD pRxTS
= (PRX_TS_RECORD
)pTs
;
423 if(timer_pending(&pRxTS
->RxPktPendingTimer
))
424 del_timer_sync(&pRxTS
->RxPktPendingTimer
);
426 while(!list_empty(&pRxTS
->RxPendingPktList
)) {
427 spin_lock_irqsave(&(ieee
->reorder_spinlock
), flags
);
428 //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
429 pRxReorderEntry
= (PRX_REORDER_ENTRY
)list_entry(pRxTS
->RxPendingPktList
.prev
,RX_REORDER_ENTRY
,List
);
430 list_del_init(&pRxReorderEntry
->List
);
433 struct ieee80211_rxb
*prxb
= pRxReorderEntry
->prxb
;
434 if (unlikely(!prxb
)) {
435 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
438 for(i
=0; i
< prxb
->nr_subframes
; i
++)
439 dev_kfree_skb(prxb
->subframes
[i
]);
444 list_add_tail(&pRxReorderEntry
->List
,&ieee
->RxReorder_Unused_List
);
445 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
450 struct tx_ts_record
*pTxTS
= (struct tx_ts_record
*)pTs
;
451 del_timer_sync(&pTxTS
->TsAddBaTimer
);
455 void RemovePeerTS(struct ieee80211_device
*ieee
, u8
*Addr
)
457 struct ts_common_info
*pTS
, *pTmpTS
;
459 printk("===========>RemovePeerTS,%pM\n", Addr
);
460 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Pending_List
, list
) {
461 if (memcmp(pTS
->addr
, Addr
, 6) == 0) {
462 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
463 list_del_init(&pTS
->list
);
464 list_add_tail(&pTS
->list
, &ieee
->Tx_TS_Unused_List
);
468 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Admit_List
, list
) {
469 if (memcmp(pTS
->addr
, Addr
, 6) == 0) {
470 printk("====>remove Tx_TS_admin_list\n");
471 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
472 list_del_init(&pTS
->list
);
473 list_add_tail(&pTS
->list
, &ieee
->Tx_TS_Unused_List
);
477 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Pending_List
, list
) {
478 if (memcmp(pTS
->addr
, Addr
, 6) == 0) {
479 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
480 list_del_init(&pTS
->list
);
481 list_add_tail(&pTS
->list
, &ieee
->Rx_TS_Unused_List
);
485 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Admit_List
, list
) {
486 if (memcmp(pTS
->addr
, Addr
, 6) == 0) {
487 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
488 list_del_init(&pTS
->list
);
489 list_add_tail(&pTS
->list
, &ieee
->Rx_TS_Unused_List
);
494 void RemoveAllTS(struct ieee80211_device
*ieee
)
496 struct ts_common_info
*pTS
, *pTmpTS
;
498 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Pending_List
, list
) {
499 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
500 list_del_init(&pTS
->list
);
501 list_add_tail(&pTS
->list
, &ieee
->Tx_TS_Unused_List
);
504 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Admit_List
, list
) {
505 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
506 list_del_init(&pTS
->list
);
507 list_add_tail(&pTS
->list
, &ieee
->Tx_TS_Unused_List
);
510 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Pending_List
, list
) {
511 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
512 list_del_init(&pTS
->list
);
513 list_add_tail(&pTS
->list
, &ieee
->Rx_TS_Unused_List
);
516 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Admit_List
, list
) {
517 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
518 list_del_init(&pTS
->list
);
519 list_add_tail(&pTS
->list
, &ieee
->Rx_TS_Unused_List
);
523 void TsStartAddBaProcess(struct ieee80211_device
*ieee
, struct tx_ts_record
*pTxTS
)
525 if(!pTxTS
->bAddBaReqInProgress
) {
526 pTxTS
->bAddBaReqInProgress
= true;
527 if(pTxTS
->bAddBaReqDelayed
) {
528 IEEE80211_DEBUG(IEEE80211_DL_BA
, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
529 mod_timer(&pTxTS
->TsAddBaTimer
,
530 jiffies
+ msecs_to_jiffies(TS_ADDBA_DELAY
));
532 IEEE80211_DEBUG(IEEE80211_DL_BA
,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
533 mod_timer(&pTxTS
->TsAddBaTimer
, jiffies
+10); //set 10 ticks
536 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "%s()==>BA timer is already added\n", __func__
);