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;
34 struct ieee80211_rxb
*stats_IndicateArray
[REORDER_WIN_SIZE
];
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)
42 // Indicate the pending packets sequentially according to SeqNum until meet the gap.
43 while(!list_empty(&pRxTs
->RxPendingPktList
))
45 pReorderEntry
= (PRX_REORDER_ENTRY
)list_entry(pRxTs
->RxPendingPktList
.prev
,RX_REORDER_ENTRY
,List
);
47 pRxTs
->RxIndicateSeq
= pReorderEntry
->SeqNum
;
49 if( SN_LESS(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
) ||
50 SN_EQUAL(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
) )
52 list_del_init(&pReorderEntry
->List
);
54 if(SN_EQUAL(pReorderEntry
->SeqNum
, pRxTs
->RxIndicateSeq
))
55 pRxTs
->RxIndicateSeq
= (pRxTs
->RxIndicateSeq
+ 1) % 4096;
57 IEEE80211_DEBUG(IEEE80211_DL_REORDER
,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry
->SeqNum
);
58 stats_IndicateArray
[index
] = pReorderEntry
->prxb
;
61 list_add_tail(&pReorderEntry
->List
, &ieee
->RxReorder_Unused_List
);
73 // Set RxTimeoutIndicateSeq to 0xffff to indicate no pending packets in buffer now.
74 pRxTs
->RxTimeoutIndicateSeq
= 0xffff;
77 if(index
> REORDER_WIN_SIZE
){
78 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "RxReorderIndicatePacket(): Rx Reorder buffer full!! \n");
79 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
82 ieee80211_indicate_packets(ieee
, stats_IndicateArray
, index
);
85 if(bPktInBuf
&& (pRxTs
->RxTimeoutIndicateSeq
==0xffff))
87 pRxTs
->RxTimeoutIndicateSeq
= pRxTs
->RxIndicateSeq
;
88 mod_timer(&pRxTs
->RxPktPendingTimer
,
89 jiffies
+ msecs_to_jiffies(ieee
->pHTInfo
->RxReorderPendingTime
));
91 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
94 /********************************************************************************************************************
95 *function: Add BA timer function
96 * input: unsigned long data //acturally we send TX_TS_RECORD or RX_TS_RECORD to these timer
99 ********************************************************************************************************************/
100 static void TsAddBaProcess(unsigned long data
)
102 PTX_TS_RECORD pTxTs
= (PTX_TS_RECORD
)data
;
104 struct ieee80211_device
*ieee
= container_of(pTxTs
, struct ieee80211_device
, TxTsRecord
[num
]);
106 TsInitAddBA(ieee
, pTxTs
, BA_POLICY_IMMEDIATE
, false);
107 IEEE80211_DEBUG(IEEE80211_DL_BA
, "TsAddBaProcess(): ADDBA Req is started!! \n");
111 static void ResetTsCommonInfo(PTS_COMMON_INFO pTsCommonInfo
)
113 eth_zero_addr(pTsCommonInfo
->Addr
);
114 memset(&pTsCommonInfo
->TSpec
, 0, sizeof(TSPEC_BODY
));
115 memset(&pTsCommonInfo
->TClass
, 0, sizeof(QOS_TCLAS
)*TCLAS_NUM
);
116 pTsCommonInfo
->TClasProc
= 0;
117 pTsCommonInfo
->TClasNum
= 0;
120 static void ResetTxTsEntry(PTX_TS_RECORD pTS
)
122 ResetTsCommonInfo(&pTS
->TsCommonInfo
);
124 pTS
->bAddBaReqInProgress
= false;
125 pTS
->bAddBaReqDelayed
= false;
126 pTS
->bUsingBa
= false;
127 ResetBaEntry(&pTS
->TxAdmittedBARecord
); //For BA Originator
128 ResetBaEntry(&pTS
->TxPendingBARecord
);
131 static void ResetRxTsEntry(PRX_TS_RECORD pTS
)
133 ResetTsCommonInfo(&pTS
->TsCommonInfo
);
134 pTS
->RxIndicateSeq
= 0xffff; // This indicate the RxIndicateSeq is not used now!!
135 pTS
->RxTimeoutIndicateSeq
= 0xffff; // This indicate the RxTimeoutIndicateSeq is not used now!!
136 ResetBaEntry(&pTS
->RxAdmittedBARecord
); // For BA Recipient
139 void TSInitialize(struct ieee80211_device
*ieee
)
141 PTX_TS_RECORD pTxTS
= ieee
->TxTsRecord
;
142 PRX_TS_RECORD pRxTS
= ieee
->RxTsRecord
;
143 PRX_REORDER_ENTRY pRxReorderEntry
= ieee
->RxReorderEntry
;
145 IEEE80211_DEBUG(IEEE80211_DL_TS
, "==========>%s()\n", __func__
);
146 // Initialize Tx TS related info.
147 INIT_LIST_HEAD(&ieee
->Tx_TS_Admit_List
);
148 INIT_LIST_HEAD(&ieee
->Tx_TS_Pending_List
);
149 INIT_LIST_HEAD(&ieee
->Tx_TS_Unused_List
);
151 for(count
= 0; count
< TOTAL_TS_NUM
; count
++)
155 // The timers for the operation of Traffic Stream and Block Ack.
156 // DLS related timer will be add here in the future!!
157 setup_timer(&pTxTS
->TsCommonInfo
.SetupTimer
, TsSetupTimeOut
,
158 (unsigned long)pTxTS
);
159 setup_timer(&pTxTS
->TsCommonInfo
.InactTimer
, TsInactTimeout
,
160 (unsigned long)pTxTS
);
161 setup_timer(&pTxTS
->TsAddBaTimer
, TsAddBaProcess
,
162 (unsigned long)pTxTS
);
163 setup_timer(&pTxTS
->TxPendingBARecord
.Timer
, BaSetupTimeOut
,
164 (unsigned long)pTxTS
);
165 setup_timer(&pTxTS
->TxAdmittedBARecord
.Timer
,
166 TxBaInactTimeout
, (unsigned long)pTxTS
);
167 ResetTxTsEntry(pTxTS
);
168 list_add_tail(&pTxTS
->TsCommonInfo
.List
, &ieee
->Tx_TS_Unused_List
);
172 // Initialize Rx TS related info.
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
++)
179 INIT_LIST_HEAD(&pRxTS
->RxPendingPktList
);
180 setup_timer(&pRxTS
->TsCommonInfo
.SetupTimer
, TsSetupTimeOut
,
181 (unsigned long)pRxTS
);
182 setup_timer(&pRxTS
->TsCommonInfo
.InactTimer
, TsInactTimeout
,
183 (unsigned long)pRxTS
);
184 setup_timer(&pRxTS
->RxAdmittedBARecord
.Timer
,
185 RxBaInactTimeout
, (unsigned long)pRxTS
);
186 setup_timer(&pRxTS
->RxPktPendingTimer
, RxPktPendingTimeout
,
187 (unsigned long)pRxTS
);
188 ResetRxTsEntry(pRxTS
);
189 list_add_tail(&pRxTS
->TsCommonInfo
.List
, &ieee
->Rx_TS_Unused_List
);
192 // Initialize unused Rx Reorder List.
193 INIT_LIST_HEAD(&ieee
->RxReorder_Unused_List
);
195 for(count
= 0; count
< REORDER_ENTRY_NUM
; count
++)
197 list_add_tail( &pRxReorderEntry
->List
,&ieee
->RxReorder_Unused_List
);
198 if(count
== (REORDER_ENTRY_NUM
-1))
200 pRxReorderEntry
= &ieee
->RxReorderEntry
[count
+1];
206 static void AdmitTS(struct ieee80211_device
*ieee
,
207 PTS_COMMON_INFO pTsCommonInfo
, u32 InactTime
)
209 del_timer_sync(&pTsCommonInfo
->SetupTimer
);
210 del_timer_sync(&pTsCommonInfo
->InactTimer
);
213 mod_timer(&pTsCommonInfo
->InactTimer
,
214 jiffies
+ msecs_to_jiffies(InactTime
));
218 static PTS_COMMON_INFO
SearchAdmitTRStream(struct ieee80211_device
*ieee
,
220 TR_SELECT TxRxSelect
)
222 //DIRECTION_VALUE dir;
224 bool search_dir
[4] = {0};
225 struct list_head
*psearch_list
; //FIXME
226 PTS_COMMON_INFO pRet
= NULL
;
227 if(ieee
->iw_mode
== IW_MODE_MASTER
) //ap mode
229 if(TxRxSelect
== TX_DIR
)
231 search_dir
[DIR_DOWN
] = true;
232 search_dir
[DIR_BI_DIR
]= true;
236 search_dir
[DIR_UP
] = true;
237 search_dir
[DIR_BI_DIR
]= true;
240 else if(ieee
->iw_mode
== IW_MODE_ADHOC
)
242 if(TxRxSelect
== TX_DIR
)
243 search_dir
[DIR_UP
] = true;
245 search_dir
[DIR_DOWN
] = true;
249 if(TxRxSelect
== TX_DIR
)
251 search_dir
[DIR_UP
] = true;
252 search_dir
[DIR_BI_DIR
]= true;
253 search_dir
[DIR_DIRECT
]= true;
257 search_dir
[DIR_DOWN
] = true;
258 search_dir
[DIR_BI_DIR
]= true;
259 search_dir
[DIR_DIRECT
]= true;
263 if(TxRxSelect
== TX_DIR
)
264 psearch_list
= &ieee
->Tx_TS_Admit_List
;
266 psearch_list
= &ieee
->Rx_TS_Admit_List
;
268 //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++)
269 for(dir
= 0; dir
<= DIR_BI_DIR
; dir
++)
271 if (!search_dir
[dir
])
273 list_for_each_entry(pRet
, psearch_list
, List
){
274 // 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);
275 if (memcmp(pRet
->Addr
, Addr
, 6) == 0)
276 if (pRet
->TSpec
.f
.TSInfo
.field
.ucTSID
== TID
)
277 if(pRet
->TSpec
.f
.TSInfo
.field
.ucDirection
== dir
)
279 // printk("Bingo! got it\n");
284 if(&pRet
->List
!= psearch_list
)
288 if(&pRet
->List
!= psearch_list
){
295 static void MakeTSEntry(PTS_COMMON_INFO pTsCommonInfo
, u8
*Addr
,
296 PTSPEC_BODY pTSPEC
, PQOS_TCLAS pTCLAS
, u8 TCLAS_Num
,
301 if(pTsCommonInfo
== NULL
)
304 memcpy(pTsCommonInfo
->Addr
, Addr
, 6);
307 memcpy((u8
*)(&(pTsCommonInfo
->TSpec
)), (u8
*)pTSPEC
, sizeof(TSPEC_BODY
));
309 for(count
= 0; count
< TCLAS_Num
; count
++)
310 memcpy((u8
*)(&(pTsCommonInfo
->TClass
[count
])), (u8
*)pTCLAS
, sizeof(QOS_TCLAS
));
312 pTsCommonInfo
->TClasProc
= TCLAS_Proc
;
313 pTsCommonInfo
->TClasNum
= TCLAS_Num
;
318 struct ieee80211_device
*ieee
,
319 PTS_COMMON_INFO
*ppTS
,
322 TR_SELECT TxRxSelect
, //Rx:1, Tx:0
328 // We do not build any TS for Broadcast or Multicast stream.
329 // So reject these kinds of search here.
331 if (is_multicast_ether_addr(Addr
))
333 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "get TS for Broadcast or Multicast\n");
337 if (ieee
->current_network
.qos_data
.supported
== 0)
341 // In WMM case: we use 4 TID only
344 IEEE80211_DEBUG(IEEE80211_DL_ERR
, " in %s(), TID(%d) is not valid\n", __func__
, TID
);
372 *ppTS
= SearchAdmitTRStream(
384 IEEE80211_DEBUG(IEEE80211_DL_TS
, "add new TS failed(tid:%d)\n", UP
);
390 // Create a new Traffic stream for current Tx/Rx
391 // This is for EDCA and WMM to add a new TS.
392 // For HCCA or WMMSA, TS cannot be addmit without negotiation.
395 PQOS_TSINFO pTSInfo
= &TSpec
.f
.TSInfo
;
396 struct list_head
*pUnusedList
=
397 (TxRxSelect
== TX_DIR
)?
398 (&ieee
->Tx_TS_Unused_List
):
399 (&ieee
->Rx_TS_Unused_List
);
401 struct list_head
*pAddmitList
=
402 (TxRxSelect
== TX_DIR
)?
403 (&ieee
->Tx_TS_Admit_List
):
404 (&ieee
->Rx_TS_Admit_List
);
406 DIRECTION_VALUE Dir
= (ieee
->iw_mode
== IW_MODE_MASTER
)?
407 ((TxRxSelect
==TX_DIR
)?DIR_DOWN
:DIR_UP
):
408 ((TxRxSelect
==TX_DIR
)?DIR_UP
:DIR_DOWN
);
409 IEEE80211_DEBUG(IEEE80211_DL_TS
, "to add Ts\n");
410 if(!list_empty(pUnusedList
))
412 (*ppTS
) = list_entry(pUnusedList
->next
, TS_COMMON_INFO
, List
);
413 list_del_init(&(*ppTS
)->List
);
414 if(TxRxSelect
==TX_DIR
)
416 PTX_TS_RECORD tmp
= container_of(*ppTS
, TX_TS_RECORD
, TsCommonInfo
);
420 PRX_TS_RECORD tmp
= container_of(*ppTS
, RX_TS_RECORD
, TsCommonInfo
);
424 IEEE80211_DEBUG(IEEE80211_DL_TS
, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP
, Dir
, Addr
);
425 // Prepare TS Info releated field
426 pTSInfo
->field
.ucTrafficType
= 0; // Traffic type: WMM is reserved in this field
427 pTSInfo
->field
.ucTSID
= UP
; // TSID
428 pTSInfo
->field
.ucDirection
= Dir
; // Direction: if there is DirectLink, this need additional consideration.
429 pTSInfo
->field
.ucAccessPolicy
= 1; // Access policy
430 pTSInfo
->field
.ucAggregation
= 0; // Aggregation
431 pTSInfo
->field
.ucPSB
= 0; // Aggregation
432 pTSInfo
->field
.ucUP
= UP
; // User priority
433 pTSInfo
->field
.ucTSInfoAckPolicy
= 0; // Ack policy
434 pTSInfo
->field
.ucSchedule
= 0; // Schedule
436 MakeTSEntry(*ppTS
, Addr
, &TSpec
, NULL
, 0, 0);
437 AdmitTS(ieee
, *ppTS
, 0);
438 list_add_tail(&((*ppTS
)->List
), pAddmitList
);
439 // if there is DirectLink, we need to do additional operation here!!
445 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "in function %s() There is not enough TS record to be used!!", __func__
);
452 static void RemoveTsEntry(struct ieee80211_device
*ieee
, PTS_COMMON_INFO pTs
,
453 TR_SELECT TxRxSelect
)
456 unsigned long flags
= 0;
457 del_timer_sync(&pTs
->SetupTimer
);
458 del_timer_sync(&pTs
->InactTimer
);
459 TsInitDelBA(ieee
, pTs
, TxRxSelect
);
461 if(TxRxSelect
== RX_DIR
)
464 PRX_REORDER_ENTRY pRxReorderEntry
;
465 PRX_TS_RECORD pRxTS
= (PRX_TS_RECORD
)pTs
;
466 if(timer_pending(&pRxTS
->RxPktPendingTimer
))
467 del_timer_sync(&pRxTS
->RxPktPendingTimer
);
469 while(!list_empty(&pRxTS
->RxPendingPktList
))
471 spin_lock_irqsave(&(ieee
->reorder_spinlock
), flags
);
472 //pRxReorderEntry = list_entry(&pRxTS->RxPendingPktList.prev,RX_REORDER_ENTRY,List);
473 pRxReorderEntry
= (PRX_REORDER_ENTRY
)list_entry(pRxTS
->RxPendingPktList
.prev
,RX_REORDER_ENTRY
,List
);
474 list_del_init(&pRxReorderEntry
->List
);
477 struct ieee80211_rxb
*prxb
= pRxReorderEntry
->prxb
;
480 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
483 for(i
=0; i
< prxb
->nr_subframes
; i
++) {
484 dev_kfree_skb(prxb
->subframes
[i
]);
489 list_add_tail(&pRxReorderEntry
->List
,&ieee
->RxReorder_Unused_List
);
490 spin_unlock_irqrestore(&(ieee
->reorder_spinlock
), flags
);
497 PTX_TS_RECORD pTxTS
= (PTX_TS_RECORD
)pTs
;
498 del_timer_sync(&pTxTS
->TsAddBaTimer
);
502 void RemovePeerTS(struct ieee80211_device
*ieee
, u8
*Addr
)
504 PTS_COMMON_INFO pTS
, pTmpTS
;
506 printk("===========>RemovePeerTS,%pM\n", Addr
);
507 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Pending_List
, List
)
509 if (memcmp(pTS
->Addr
, Addr
, 6) == 0)
511 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
512 list_del_init(&pTS
->List
);
513 list_add_tail(&pTS
->List
, &ieee
->Tx_TS_Unused_List
);
517 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Admit_List
, List
)
519 if (memcmp(pTS
->Addr
, Addr
, 6) == 0)
521 printk("====>remove Tx_TS_admin_list\n");
522 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
523 list_del_init(&pTS
->List
);
524 list_add_tail(&pTS
->List
, &ieee
->Tx_TS_Unused_List
);
528 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Pending_List
, List
)
530 if (memcmp(pTS
->Addr
, Addr
, 6) == 0)
532 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
533 list_del_init(&pTS
->List
);
534 list_add_tail(&pTS
->List
, &ieee
->Rx_TS_Unused_List
);
538 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Admit_List
, List
)
540 if (memcmp(pTS
->Addr
, Addr
, 6) == 0)
542 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
543 list_del_init(&pTS
->List
);
544 list_add_tail(&pTS
->List
, &ieee
->Rx_TS_Unused_List
);
549 void RemoveAllTS(struct ieee80211_device
*ieee
)
551 PTS_COMMON_INFO pTS
, pTmpTS
;
553 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Pending_List
, List
)
555 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
556 list_del_init(&pTS
->List
);
557 list_add_tail(&pTS
->List
, &ieee
->Tx_TS_Unused_List
);
560 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Tx_TS_Admit_List
, List
)
562 RemoveTsEntry(ieee
, pTS
, TX_DIR
);
563 list_del_init(&pTS
->List
);
564 list_add_tail(&pTS
->List
, &ieee
->Tx_TS_Unused_List
);
567 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Pending_List
, List
)
569 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
570 list_del_init(&pTS
->List
);
571 list_add_tail(&pTS
->List
, &ieee
->Rx_TS_Unused_List
);
574 list_for_each_entry_safe(pTS
, pTmpTS
, &ieee
->Rx_TS_Admit_List
, List
)
576 RemoveTsEntry(ieee
, pTS
, RX_DIR
);
577 list_del_init(&pTS
->List
);
578 list_add_tail(&pTS
->List
, &ieee
->Rx_TS_Unused_List
);
582 void TsStartAddBaProcess(struct ieee80211_device
*ieee
, PTX_TS_RECORD pTxTS
)
584 if(!pTxTS
->bAddBaReqInProgress
)
586 pTxTS
->bAddBaReqInProgress
= true;
587 if(pTxTS
->bAddBaReqDelayed
)
589 IEEE80211_DEBUG(IEEE80211_DL_BA
, "TsStartAddBaProcess(): Delayed Start ADDBA after 60 sec!!\n");
590 mod_timer(&pTxTS
->TsAddBaTimer
,
591 jiffies
+ msecs_to_jiffies(TS_ADDBA_DELAY
));
595 IEEE80211_DEBUG(IEEE80211_DL_BA
,"TsStartAddBaProcess(): Immediately Start ADDBA now!!\n");
596 mod_timer(&pTxTS
->TsAddBaTimer
, jiffies
+10); //set 10 ticks
600 IEEE80211_DEBUG(IEEE80211_DL_ERR
, "%s()==>BA timer is already added\n", __func__
);