2 #include <linux/etherdevice.h>
3 #include <linux/slab.h>
4 #include "rtl819x_TS.h"
6 static void TsSetupTimeOut(unsigned long data
)
9 // This is used for WMMSA and ACM , that would send ADDTSReq frame.
12 static void TsInactTimeout(unsigned long data
)
15 // This is used for WMMSA and ACM.
16 // This function would be call when TS is no Tx/Rx for some period of time.
19 /********************************************************************************************************************
20 *function: I still not understand this function, so wait for further implementation
21 * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer
24 ********************************************************************************************************************/
25 static void RxPktPendingTimeout(unsigned long data
)
27 PRX_TS_RECORD pRxTs
= (PRX_TS_RECORD
)data
;
28 struct ieee80211_device
*ieee
= container_of(pRxTs
, struct ieee80211_device
, RxTsRecord
[pRxTs
->num
]);
30 PRX_REORDER_ENTRY pReorderEntry
= NULL
;
33 unsigned long flags
= 0;
35 bool bPktInBuf
= false;
37 spin_lock_irqsave(&(ieee
->reorder_spinlock
), flags
);
38 IEEE80211_DEBUG(IEEE80211_DL_REORDER
,"==================>%s()\n",__func__
);
39 if(pRxTs
->RxTimeoutIndicateSeq
!= 0xffff) {
40 // Indicate the pending packets sequentially according to SeqNum until meet the gap.
41 while(!list_empty(&pRxTs
->RxPendingPktList
)) {
42 pReorderEntry
= (PRX_REORDER_ENTRY
)list_entry(pRxTs
->RxPendingPktList
.prev
,RX_REORDER_ENTRY
,List
);
44 pRxTs
->RxIndicateSeq
= pReorderEntry
->SeqNum
;
46 if( SN_LESS(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
) ||
47 SN_EQUAL(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
) ) {
48 list_del_init(&pReorderEntry
->List
);
50 if(SN_EQUAL(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
))
51 pRxTs
->RxIndicateSeq
= (pRxTs
->RxIndicateSeq
+ 1) % 4096;
53 IEEE80211_DEBUG(IEEE80211_DL_REORDER
,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry
->SeqNum
);
54 ieee
->stats_IndicateArray
[index
] = pReorderEntry
->prxb
;
57 list_add_tail(&pReorderEntry
->List
, &ieee
->RxReorder_Unused_List
);
66 // Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now.
67 pRxTs
->RxTimeoutIndicateSeq
= 0xffff;
70 if(index
> REORDER_WIN_SIZE
) {
71 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "RxReorderIndicatePacket(): Rx Reorder buffer full!! \n");
72 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
75 ieee80211_indicate_packets(ieee
, ieee
->stats_IndicateArray
, index
);
78 if(bPktInBuf
&& (pRxTs
->RxTimeoutIndicateSeq
==0xffff)) {
79 pRxTs
->RxTimeoutIndicateSeq
= pRxTs
->RxIndicateSeq
;
80 mod_timer(&pRxTs
->RxPktPendingTimer
,
81 jiffies
+ msecs_to_jiffies(ieee
->pHTInfo
->RxReorderPendingTime
));
83 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
86 /********************************************************************************************************************
87 *function: Add BA timer function
88 * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer
91 ********************************************************************************************************************/
92 static void TsAddBaProcess(unsigned long data
)
94 PTX_TS_RECORD pTxTs
= (PTX_TS_RECORD
)data
;
96 struct ieee80211_device
*ieee
= container_of(pTxTs
, struct ieee80211_device
, TxTsRecord
[num
]);
98 TsInitAddBA(ieee
, pTxTs
, BA_POLICY_IMMEDIATE
, false);
99 IEEE80211_DEBUG(IEEE80211_DL_BA
, "TsAddBaProcess(): ADDBA Req is started!! \n");
103 static void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo
)
105 eth_zero_addr(pTsCommonInfo
->Addr
);
106 memset(&pTsCommonInfo
->TSpec
, 0, sizeof(TSPEC_BODY
));
107 memset(&pTsCommonInfo
->TClass
, 0, sizeof(QOS_TCLAS
)*TCLAS_NUM
);
108 pTsCommonInfo
->TClasProc
= 0;
109 pTsCommonInfo
->TClasNum
= 0;
112 static void ResetTxTsEntry(PTX_TS_RECORD pTS
)
114 ResetTsCommonInfo(&pTS
->TsCommonInfo
);
116 pTS
->bAddBaReqInProgress
= false;
117 pTS
->bAddBaReqDelayed
= false;
118 pTS
->bUsingBa
= false;
119 ResetBaEntry(&pTS
->TxAdmittedBARecord
); //For BA Originator
120 ResetBaEntry(&pTS
->TxPendingBARecord
);
123 static void ResetRxTsEntry(PRX_TS_RECORD pTS
)
125 ResetTsCommonInfo(&pTS
->TsCommonInfo
);
126 pTS
->RxIndicateSeq
= 0xffff; // This indicate the RxIndicateSeq is not used now!!
127 pTS
->RxTimeoutIndicateSeq
= 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!!
128 ResetBaEntry(&pTS
->RxAdmittedBARecord
); // For BA Recipient
131 void TSInitialize(struct ieee80211_device
*ieee
)
133 PTX_TS_RECORD pTxTS
= ieee
->TxTsRecord
;
134 PRX_TS_RECORD pRxTS
= ieee
->RxTsRecord
;
135 PRX_REORDER_ENTRY pRxReorderEntry
= ieee
->RxReorderEntry
;
137 IEEE80211_DEBUG(IEEE80211_DL_TS
, "==========>%s()\n", __func__
);
138 // Initialize Tx TS related info.
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
);
143 for(count
= 0; count
< TOTAL_TS_NUM
; count
++) {
146 // The timers for the operation of Traffic Stream and Block Ack.
147 // DLS related timer will be add here in the future!!
148 setup_timer(&pTxTS
->TsCommonInfo
.SetupTimer
, TsSetupTimeOut
,
149 (unsigned long)pTxTS
);
150 setup_timer(&pTxTS
->TsCommonInfo
.InactTimer
, TsInactTimeout
,
151 (unsigned long)pTxTS
);
152 setup_timer(&pTxTS
->TsAddBaTimer
, TsAddBaProcess
,
153 (unsigned long)pTxTS
);
154 setup_timer(&pTxTS
->TxPendingBARecord
.Timer
, BaSetupTimeOut
,
155 (unsigned long)pTxTS
);
156 setup_timer(&pTxTS
->TxAdmittedBARecord
.Timer
,
157 TxBaInactTimeout
, (unsigned long)pTxTS
);
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 setup_timer(&pRxTS
->TsCommonInfo
.SetupTimer
, TsSetupTimeOut
,
171 (unsigned long)pRxTS
);
172 setup_timer(&pRxTS
->TsCommonInfo
.InactTimer
, TsInactTimeout
,
173 (unsigned long)pRxTS
);
174 setup_timer(&pRxTS
->RxAdmittedBARecord
.Timer
,
175 RxBaInactTimeout
, (unsigned long)pRxTS
);
176 setup_timer(&pRxTS
->RxPktPendingTimer
, RxPktPendingTimeout
,
177 (unsigned long)pRxTS
);
178 ResetRxTsEntry(pRxTS
);
179 list_add_tail(&pRxTS
->TsCommonInfo
.List
, &ieee
->Rx_TS_Unused_List
);
182 // Initialize unused Rx Reorder List.
183 INIT_LIST_HEAD(&ieee
->RxReorder_Unused_List
);
185 for(count
= 0; count
< REORDER_ENTRY_NUM
; count
++) {
186 list_add_tail( &pRxReorderEntry
->List
,&ieee
->RxReorder_Unused_List
);
187 if(count
== (REORDER_ENTRY_NUM
-1))
189 pRxReorderEntry
= &ieee
->RxReorderEntry
[count
+1];
194 static void AdmitTS(struct ieee80211_device
*ieee
,
195 PTS_COMMON_INFO pTsCommonInfo
, u32 InactTime
)
197 del_timer_sync(&pTsCommonInfo
->SetupTimer
);
198 del_timer_sync(&pTsCommonInfo
->InactTimer
);
201 mod_timer(&pTsCommonInfo
->InactTimer
,
202 jiffies
+ msecs_to_jiffies(InactTime
));
206 static PTS_COMMON_INFO
SearchAdmitTRStream(struct ieee80211_device
*ieee
,
208 TR_SELECT TxRxSelect
)
210 //DIRECTION_VALUE dir;
212 bool search_dir
[4] = {0};
213 struct list_head
*psearch_list
; //FIXME
214 PTS_COMMON_INFO pRet
= NULL
;
215 if(ieee
->iw_mode
== IW_MODE_MASTER
) { //ap mode
216 if(TxRxSelect
== TX_DIR
) {
217 search_dir
[DIR_DOWN
] = true;
218 search_dir
[DIR_BI_DIR
]= true;
220 search_dir
[DIR_UP
] = true;
221 search_dir
[DIR_BI_DIR
]= true;
223 } else if(ieee
->iw_mode
== IW_MODE_ADHOC
) {
224 if(TxRxSelect
== TX_DIR
)
225 search_dir
[DIR_UP
] = true;
227 search_dir
[DIR_DOWN
] = true;
229 if(TxRxSelect
== TX_DIR
) {
230 search_dir
[DIR_UP
] = true;
231 search_dir
[DIR_BI_DIR
]= true;
232 search_dir
[DIR_DIRECT
]= true;
234 search_dir
[DIR_DOWN
] = true;
235 search_dir
[DIR_BI_DIR
]= true;
236 search_dir
[DIR_DIRECT
]= true;
240 if(TxRxSelect
== TX_DIR
)
241 psearch_list
= &ieee
->Tx_TS_Admit_List
;
243 psearch_list
= &ieee
->Rx_TS_Admit_List
;
245 //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
246 for(dir
= 0; dir
<= DIR_BI_DIR
; dir
++) {
247 if (!search_dir
[dir
])
249 list_for_each_entry(pRet
, psearch_list
, List
){
250 // 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);
251 if (memcmp(pRet
->Addr
, Addr
, 6) == 0)
252 if (pRet
->TSpec
.f
.TSInfo
.field
.ucTSID
== TID
)
253 if(pRet
->TSpec
.f
.TSInfo
.field
.ucDirection
== dir
) {
254 // printk("Bingo! got it\n");
258 if(&pRet
->List
!= psearch_list
)
262 if(&pRet
->List
!= psearch_list
)
268 static void MakeTSEntry(PTS_COMMON_INFO pTsCommonInfo
, u8
*Addr
,
269 PTSPEC_BODY pTSPEC
, PQOS_TCLAS pTCLAS
, u8 TCLAS_Num
,
274 if(pTsCommonInfo
== NULL
)
277 memcpy(pTsCommonInfo
->Addr
, Addr
, 6);
280 memcpy((u8
*)(&(pTsCommonInfo
->TSpec
)), (u8
*)pTSPEC
, sizeof(TSPEC_BODY
));
282 for(count
= 0; count
< TCLAS_Num
; count
++)
283 memcpy((u8
*)(&(pTsCommonInfo
->TClass
[count
])), (u8
*)pTCLAS
, sizeof(QOS_TCLAS
));
285 pTsCommonInfo
->TClasProc
= TCLAS_Proc
;
286 pTsCommonInfo
->TClasNum
= TCLAS_Num
;
291 struct ieee80211_device
*ieee
,
292 PTS_COMMON_INFO
*ppTS
,
295 TR_SELECT TxRxSelect
, //Rx:1, Tx:0
301 // We do not build any TS for Broadcast or Multicast stream.
302 // So reject these kinds of search here.
304 if (is_multicast_ether_addr(Addr
)) {
305 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "get TS for Broadcast or Multicast\n");
309 if (ieee
->current_network
.qos_data
.supported
== 0) {
312 // In WMM case: we use 4 TID only
313 if (!IsACValid(TID
)) {
314 IEEE80211_DEBUG(IEEE80211_DL_ERR
, " in %s(), TID(%d) is not valid\n", __func__
, TID
);
341 *ppTS
= SearchAdmitTRStream(
350 IEEE80211_DEBUG(IEEE80211_DL_TS
, "add new TS failed(tid:%d)\n", UP
);
354 // Create a new Traffic stream for current Tx/Rx
355 // This is for EDCA and WMM to add a new TS.
356 // For HCCA or WMMSA, TS cannot be addmit without negotiation.
359 PQOS_TSINFO pTSInfo
= &TSpec
.f
.TSInfo
;
360 struct list_head
*pUnusedList
=
361 (TxRxSelect
== TX_DIR
)?
362 (&ieee
->Tx_TS_Unused_List
):
363 (&ieee
->Rx_TS_Unused_List
);
365 struct list_head
*pAddmitList
=
366 (TxRxSelect
== TX_DIR
)?
367 (&ieee
->Tx_TS_Admit_List
):
368 (&ieee
->Rx_TS_Admit_List
);
370 DIRECTION_VALUE Dir
= (ieee
->iw_mode
== IW_MODE_MASTER
)?
371 ((TxRxSelect
==TX_DIR
)?DIR_DOWN
:DIR_UP
):
372 ((TxRxSelect
==TX_DIR
)?DIR_UP
:DIR_DOWN
);
373 IEEE80211_DEBUG(IEEE80211_DL_TS
, "to add Ts\n");
374 if(!list_empty(pUnusedList
)) {
375 (*ppTS
) = list_entry(pUnusedList
->next
, TS_COMMON_INFO
, List
);
376 list_del_init(&(*ppTS
)->List
);
377 if(TxRxSelect
==TX_DIR
) {
378 PTX_TS_RECORD tmp
= container_of(*ppTS
, TX_TS_RECORD
, TsCommonInfo
);
381 PRX_TS_RECORD tmp
= container_of(*ppTS
, RX_TS_RECORD
, TsCommonInfo
);
385 IEEE80211_DEBUG(IEEE80211_DL_TS
, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP
, Dir
, Addr
);
386 // Prepare TS Info releated field
387 pTSInfo
->field
.ucTrafficType
= 0; // Traffic type: WMM is reserved in this field
388 pTSInfo
->field
.ucTSID
= UP
; // TSID
389 pTSInfo
->field
.ucDirection
= Dir
; // Direction: if there is DirectLink, this need additional consideration.
390 pTSInfo
->field
.ucAccessPolicy
= 1; // Access policy
391 pTSInfo
->field
.ucAggregation
= 0; // Aggregation
392 pTSInfo
->field
.ucPSB
= 0; // Aggregation
393 pTSInfo
->field
.ucUP
= UP
; // User priority
394 pTSInfo
->field
.ucTSInfoAckPolicy
= 0; // Ack policy
395 pTSInfo
->field
.ucSchedule
= 0; // Schedule
397 MakeTSEntry(*ppTS
, Addr
, &TSpec
, NULL
, 0, 0);
398 AdmitTS(ieee
, *ppTS
, 0);
399 list_add_tail(&((*ppTS
)->List
), pAddmitList
);
400 // if there is DirectLink, we need to do additional operation here!!
404 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "in function %s() There is not enough TS record to be used!!", __func__
);
411 static void RemoveTsEntry(struct ieee80211_device
*ieee
, PTS_COMMON_INFO pTs
,
412 TR_SELECT TxRxSelect
)
415 unsigned long flags
= 0;
416 del_timer_sync(&pTs
->SetupTimer
);
417 del_timer_sync(&pTs
->InactTimer
);
418 TsInitDelBA(ieee
, pTs
, TxRxSelect
);
420 if(TxRxSelect
== RX_DIR
) {
422 PRX_REORDER_ENTRY pRxReorderEntry
;
423 PRX_TS_RECORD pRxTS
= (PRX_TS_RECORD
)pTs
;
424 if(timer_pending(&pRxTS
->RxPktPendingTimer
))
425 del_timer_sync(&pRxTS
->RxPktPendingTimer
);
427 while(!list_empty(&pRxTS
->RxPendingPktList
)) {
428 spin_lock_irqsave(&(ieee
->reorder_spinlock
), flags
);
429 //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
430 pRxReorderEntry
= (PRX_REORDER_ENTRY
)list_entry(pRxTS
->RxPendingPktList
.prev
,RX_REORDER_ENTRY
,List
);
431 list_del_init(&pRxReorderEntry
->List
);
434 struct ieee80211_rxb
*prxb
= pRxReorderEntry
->prxb
;
435 if (unlikely(!prxb
)) {
436 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
439 for(i
=0; i
< prxb
->nr_subframes
; i
++)
440 dev_kfree_skb(prxb
->subframes
[i
]);
445 list_add_tail(&pRxReorderEntry
->List
,&ieee
->RxReorder_Unused_List
);
446 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
451 PTX_TS_RECORD pTxTS
= (PTX_TS_RECORD
)pTs
;
452 del_timer_sync(&pTxTS
->TsAddBaTimer
);
456 void RemovePeerTS(struct ieee80211_device
*ieee
, u8
*Addr
)
458 PTS_COMMON_INFO pTS
, pTmpTS
;
460 printk("===========>RemovePeerTS,%pM\n", Addr
);
461 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Pending_List
, List
) {
462 if (memcmp(pTS
->Addr
, Addr
, 6) == 0) {
463 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
464 list_del_init(&pTS
->List
);
465 list_add_tail(&pTS
->List
, &ieee
->Tx_TS_Unused_List
);
469 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Admit_List
, List
) {
470 if (memcmp(pTS
->Addr
, Addr
, 6) == 0) {
471 printk("====>remove Tx_TS_admin_list\n");
472 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
473 list_del_init(&pTS
->List
);
474 list_add_tail(&pTS
->List
, &ieee
->Tx_TS_Unused_List
);
478 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Pending_List
, List
) {
479 if (memcmp(pTS
->Addr
, Addr
, 6) == 0) {
480 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
481 list_del_init(&pTS
->List
);
482 list_add_tail(&pTS
->List
, &ieee
->Rx_TS_Unused_List
);
486 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Admit_List
, List
) {
487 if (memcmp(pTS
->Addr
, Addr
, 6) == 0) {
488 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
489 list_del_init(&pTS
->List
);
490 list_add_tail(&pTS
->List
, &ieee
->Rx_TS_Unused_List
);
495 void RemoveAllTS(struct ieee80211_device
*ieee
)
497 PTS_COMMON_INFO pTS
, pTmpTS
;
499 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Pending_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
);
505 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Admit_List
, List
) {
506 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
507 list_del_init(&pTS
->List
);
508 list_add_tail(&pTS
->List
, &ieee
->Tx_TS_Unused_List
);
511 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Pending_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
);
517 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Admit_List
, List
) {
518 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
519 list_del_init(&pTS
->List
);
520 list_add_tail(&pTS
->List
, &ieee
->Rx_TS_Unused_List
);
524 void TsStartAddBaProcess(struct ieee80211_device
*ieee
, PTX_TS_RECORD pTxTS
)
526 if(!pTxTS
->bAddBaReqInProgress
) {
527 pTxTS
->bAddBaReqInProgress
= true;
528 if(pTxTS
->bAddBaReqDelayed
) {
529 IEEE80211_DEBUG(IEEE80211_DL_BA
, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
530 mod_timer(&pTxTS
->TsAddBaTimer
,
531 jiffies
+ msecs_to_jiffies(TS_ADDBA_DELAY
));
533 IEEE80211_DEBUG(IEEE80211_DL_BA
,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
534 mod_timer(&pTxTS
->TsAddBaTimer
, jiffies
+10); //set 10 ticks
537 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "%s()==>BA timer is already added\n", __func__
);