Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
8fc8598e JC |
2 | #include "ieee80211.h" |
3 | #include <linux/etherdevice.h> | |
5a0e3ad6 | 4 | #include <linux/slab.h> |
8fc8598e JC |
5 | #include "rtl819x_TS.h" |
6 | ||
d2e5af14 | 7 | static void TsSetupTimeOut(struct timer_list *unused) |
8fc8598e JC |
8 | { |
9 | // Not implement yet | |
10 | // This is used for WMMSA and ACM , that would send ADDTSReq frame. | |
11 | } | |
12 | ||
d2e5af14 | 13 | static void TsInactTimeout(struct timer_list *unused) |
8fc8598e JC |
14 | { |
15 | // Not implement yet | |
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. | |
18 | } | |
19 | ||
20 | /******************************************************************************************************************** | |
21 | *function: I still not understand this function, so wait for further implementation | |
80b6f0d4 | 22 | * input: unsigned long data //acturally we send struct tx_ts_record or struct rx_ts_record to these timer |
8fc8598e JC |
23 | * return: NULL |
24 | * notice: | |
239378b4 | 25 | ********************************************************************************************************************/ |
d2e5af14 | 26 | static void RxPktPendingTimeout(struct timer_list *t) |
8fc8598e | 27 | { |
5b76f8cb | 28 | struct rx_ts_record *pRxTs = from_timer(pRxTs, t, rx_pkt_pending_timer); |
8fc8598e JC |
29 | struct ieee80211_device *ieee = container_of(pRxTs, struct ieee80211_device, RxTsRecord[pRxTs->num]); |
30 | ||
3eb9aa00 | 31 | struct rx_reorder_entry *pReorderEntry = NULL; |
8fc8598e JC |
32 | |
33 | //u32 flags = 0; | |
34 | unsigned long flags = 0; | |
8fc8598e JC |
35 | u8 index = 0; |
36 | bool bPktInBuf = false; | |
37 | ||
8fc8598e | 38 | spin_lock_irqsave(&(ieee->reorder_spinlock), flags); |
dacdf6a6 | 39 | IEEE80211_DEBUG(IEEE80211_DL_REORDER, "==================>%s()\n", __func__); |
d5469036 | 40 | if (pRxTs->rx_timeout_indicate_seq != 0xffff) { |
8fc8598e | 41 | // Indicate the pending packets sequentially according to SeqNum until meet the gap. |
d5469036 | 42 | while (!list_empty(&pRxTs->rx_pending_pkt_list)) { |
a279fc9d | 43 | pReorderEntry = list_entry(pRxTs->rx_pending_pkt_list.prev, struct rx_reorder_entry, List); |
d5469036 | 44 | if (index == 0) |
dfbb36f7 | 45 | pRxTs->rx_indicate_seq = pReorderEntry->SeqNum; |
8fc8598e | 46 | |
d5469036 SY |
47 | if (SN_LESS(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq) || |
48 | SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq)) { | |
8fc8598e JC |
49 | list_del_init(&pReorderEntry->List); |
50 | ||
d5469036 | 51 | if (SN_EQUAL(pReorderEntry->SeqNum, pRxTs->rx_indicate_seq)) |
dfbb36f7 | 52 | pRxTs->rx_indicate_seq = (pRxTs->rx_indicate_seq + 1) % 4096; |
8fc8598e | 53 | |
3cc7037b | 54 | IEEE80211_DEBUG(IEEE80211_DL_REORDER, "%s: IndicateSeq: %d\n", __func__, pReorderEntry->SeqNum); |
26190d41 | 55 | ieee->stats_IndicateArray[index] = pReorderEntry->prxb; |
8fc8598e JC |
56 | index++; |
57 | ||
58 | list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List); | |
d05038cc | 59 | } else { |
8fc8598e JC |
60 | bPktInBuf = true; |
61 | break; | |
62 | } | |
63 | } | |
64 | } | |
65 | ||
0580db2c | 66 | if (index > 0) { |
902efe07 JW |
67 | // Set rx_timeout_indicate_seq to 0xffff to indicate no pending packets in buffer now. |
68 | pRxTs->rx_timeout_indicate_seq = 0xffff; | |
8fc8598e JC |
69 | |
70 | // Indicate packets | |
d5469036 | 71 | if (index > REORDER_WIN_SIZE) { |
58493d8e | 72 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "RxReorderIndicatePacket(): Rx Reorder buffer full!! \n"); |
8fc8598e JC |
73 | spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); |
74 | return; | |
75 | } | |
26190d41 | 76 | ieee80211_indicate_packets(ieee, ieee->stats_IndicateArray, index); |
8fc8598e JC |
77 | } |
78 | ||
d5469036 | 79 | if (bPktInBuf && (pRxTs->rx_timeout_indicate_seq == 0xffff)) { |
902efe07 | 80 | pRxTs->rx_timeout_indicate_seq = pRxTs->rx_indicate_seq; |
5b76f8cb | 81 | mod_timer(&pRxTs->rx_pkt_pending_timer, |
f3b8a53c | 82 | jiffies + msecs_to_jiffies(ieee->pHTInfo->RxReorderPendingTime)); |
8fc8598e JC |
83 | } |
84 | spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); | |
8fc8598e | 85 | } |
8fc8598e JC |
86 | |
87 | /******************************************************************************************************************** | |
88 | *function: Add BA timer function | |
80b6f0d4 | 89 | * input: unsigned long data //acturally we send struct tx_ts_record or struct rx_ts_record to these timer |
8fc8598e JC |
90 | * return: NULL |
91 | * notice: | |
239378b4 | 92 | ********************************************************************************************************************/ |
d2e5af14 | 93 | static void TsAddBaProcess(struct timer_list *t) |
8fc8598e | 94 | { |
1c194ce9 | 95 | struct tx_ts_record *pTxTs = from_timer(pTxTs, t, ts_add_ba_timer); |
8fc8598e JC |
96 | u8 num = pTxTs->num; |
97 | struct ieee80211_device *ieee = container_of(pTxTs, struct ieee80211_device, TxTsRecord[num]); | |
98 | ||
99 | TsInitAddBA(ieee, pTxTs, BA_POLICY_IMMEDIATE, false); | |
3cc7037b | 100 | IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: ADDBA Req is started!! \n", __func__); |
8fc8598e JC |
101 | } |
102 | ||
103 | ||
6ae62698 | 104 | static void ResetTsCommonInfo(struct ts_common_info *pTsCommonInfo) |
8fc8598e | 105 | { |
12a540c3 | 106 | eth_zero_addr(pTsCommonInfo->addr); |
9365607a | 107 | memset(&pTsCommonInfo->t_spec, 0, sizeof(struct tspec_body)); |
f401441d | 108 | memset(&pTsCommonInfo->t_class, 0, sizeof(union qos_tclas) * TCLAS_NUM); |
cb72b2f6 | 109 | pTsCommonInfo->t_clas_proc = 0; |
32cb4d73 | 110 | pTsCommonInfo->t_clas_num = 0; |
8fc8598e JC |
111 | } |
112 | ||
1538be28 | 113 | static void ResetTxTsEntry(struct tx_ts_record *pTS) |
8fc8598e | 114 | { |
c1fdc5de | 115 | ResetTsCommonInfo(&pTS->ts_common_info); |
4925d4b7 | 116 | pTS->tx_cur_seq = 0; |
e5afcc0f | 117 | pTS->add_ba_req_in_progress = false; |
df5d5bc8 | 118 | pTS->add_ba_req_delayed = false; |
5ef43de1 | 119 | pTS->using_ba = false; |
f57383bc | 120 | ResetBaEntry(&pTS->tx_admitted_ba_record); //For BA Originator |
43a420e3 | 121 | ResetBaEntry(&pTS->tx_pending_ba_record); |
8fc8598e JC |
122 | } |
123 | ||
80b6f0d4 | 124 | static void ResetRxTsEntry(struct rx_ts_record *pTS) |
8fc8598e | 125 | { |
c1fdc5de | 126 | ResetTsCommonInfo(&pTS->ts_common_info); |
dfbb36f7 | 127 | pTS->rx_indicate_seq = 0xffff; // This indicate the rx_indicate_seq is not used now!! |
902efe07 | 128 | pTS->rx_timeout_indicate_seq = 0xffff; // This indicate the rx_timeout_indicate_seq is not used now!! |
02f2560c | 129 | ResetBaEntry(&pTS->rx_admitted_ba_record); // For BA Recipient |
8fc8598e JC |
130 | } |
131 | ||
132 | void TSInitialize(struct ieee80211_device *ieee) | |
133 | { | |
1538be28 | 134 | struct tx_ts_record *pTxTS = ieee->TxTsRecord; |
80b6f0d4 | 135 | struct rx_ts_record *pRxTS = ieee->RxTsRecord; |
3eb9aa00 | 136 | struct rx_reorder_entry *pRxReorderEntry = ieee->RxReorderEntry; |
8fc8598e | 137 | u8 count = 0; |
f8628a47 | 138 | IEEE80211_DEBUG(IEEE80211_DL_TS, "==========>%s()\n", __func__); |
8fc8598e JC |
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); | |
143 | ||
d5469036 | 144 | for (count = 0; count < TOTAL_TS_NUM; count++) { |
8fc8598e JC |
145 | // |
146 | pTxTS->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!! | |
c1fdc5de | 149 | timer_setup(&pTxTS->ts_common_info.setup_timer, TsSetupTimeOut, |
d2e5af14 | 150 | 0); |
c1fdc5de | 151 | timer_setup(&pTxTS->ts_common_info.inact_timer, TsInactTimeout, |
d2e5af14 | 152 | 0); |
1c194ce9 | 153 | timer_setup(&pTxTS->ts_add_ba_timer, TsAddBaProcess, 0); |
6fcb0759 | 154 | timer_setup(&pTxTS->tx_pending_ba_record.timer, BaSetupTimeOut, |
d2e5af14 | 155 | 0); |
6fcb0759 | 156 | timer_setup(&pTxTS->tx_admitted_ba_record.timer, |
d2e5af14 | 157 | TxBaInactTimeout, 0); |
8fc8598e | 158 | ResetTxTsEntry(pTxTS); |
c1fdc5de | 159 | list_add_tail(&pTxTS->ts_common_info.list, &ieee->Tx_TS_Unused_List); |
8fc8598e JC |
160 | pTxTS++; |
161 | } | |
162 | ||
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); | |
d5469036 | 167 | for (count = 0; count < TOTAL_TS_NUM; count++) { |
8fc8598e | 168 | pRxTS->num = count; |
a1ac7d1c | 169 | INIT_LIST_HEAD(&pRxTS->rx_pending_pkt_list); |
c1fdc5de | 170 | timer_setup(&pRxTS->ts_common_info.setup_timer, TsSetupTimeOut, |
d2e5af14 | 171 | 0); |
c1fdc5de | 172 | timer_setup(&pRxTS->ts_common_info.inact_timer, TsInactTimeout, |
d2e5af14 | 173 | 0); |
6fcb0759 | 174 | timer_setup(&pRxTS->rx_admitted_ba_record.timer, |
d2e5af14 | 175 | RxBaInactTimeout, 0); |
5b76f8cb | 176 | timer_setup(&pRxTS->rx_pkt_pending_timer, RxPktPendingTimeout, 0); |
8fc8598e | 177 | ResetRxTsEntry(pRxTS); |
c1fdc5de | 178 | list_add_tail(&pRxTS->ts_common_info.list, &ieee->Rx_TS_Unused_List); |
8fc8598e JC |
179 | pRxTS++; |
180 | } | |
181 | // Initialize unused Rx Reorder List. | |
182 | INIT_LIST_HEAD(&ieee->RxReorder_Unused_List); | |
d5469036 | 183 | for (count = 0; count < REORDER_ENTRY_NUM; count++) { |
0580db2c | 184 | list_add_tail(&pRxReorderEntry->List, &ieee->RxReorder_Unused_List); |
f401441d | 185 | if (count == (REORDER_ENTRY_NUM - 1)) |
8fc8598e | 186 | break; |
f401441d | 187 | pRxReorderEntry = &ieee->RxReorderEntry[count + 1]; |
8fc8598e | 188 | } |
8fc8598e JC |
189 | } |
190 | ||
1d6fa895 | 191 | static void AdmitTS(struct ieee80211_device *ieee, |
6ae62698 | 192 | struct ts_common_info *pTsCommonInfo, u32 InactTime) |
8fc8598e | 193 | { |
36cf191f | 194 | del_timer_sync(&pTsCommonInfo->setup_timer); |
27c4a9bb | 195 | del_timer_sync(&pTsCommonInfo->inact_timer); |
8fc8598e | 196 | |
0580db2c | 197 | if (InactTime != 0) |
27c4a9bb | 198 | mod_timer(&pTsCommonInfo->inact_timer, |
f3b8a53c | 199 | jiffies + msecs_to_jiffies(InactTime)); |
8fc8598e JC |
200 | } |
201 | ||
202 | ||
6ae62698 JW |
203 | static struct ts_common_info *SearchAdmitTRStream(struct ieee80211_device *ieee, |
204 | u8 *Addr, u8 TID, | |
205 | enum tr_select TxRxSelect) | |
8fc8598e | 206 | { |
35997ff0 SH |
207 | //DIRECTION_VALUE dir; |
208 | u8 dir; | |
c6d87638 | 209 | bool search_dir[4] = {0}; |
3c19fbb6 | 210 | struct list_head *psearch_list; //FIXME |
6ae62698 | 211 | struct ts_common_info *pRet = NULL; |
d5469036 SY |
212 | if (ieee->iw_mode == IW_MODE_MASTER) { //ap mode |
213 | if (TxRxSelect == TX_DIR) { | |
8fc8598e | 214 | search_dir[DIR_DOWN] = true; |
0580db2c | 215 | search_dir[DIR_BI_DIR] = true; |
d05038cc | 216 | } else { |
35997ff0 | 217 | search_dir[DIR_UP] = true; |
0580db2c | 218 | search_dir[DIR_BI_DIR] = true; |
8fc8598e | 219 | } |
d5469036 | 220 | } else if (ieee->iw_mode == IW_MODE_ADHOC) { |
0580db2c | 221 | if (TxRxSelect == TX_DIR) |
35997ff0 | 222 | search_dir[DIR_UP] = true; |
8fc8598e JC |
223 | else |
224 | search_dir[DIR_DOWN] = true; | |
d05038cc | 225 | } else { |
d5469036 | 226 | if (TxRxSelect == TX_DIR) { |
35997ff0 | 227 | search_dir[DIR_UP] = true; |
0580db2c VB |
228 | search_dir[DIR_BI_DIR] = true; |
229 | search_dir[DIR_DIRECT] = true; | |
d05038cc | 230 | } else { |
8fc8598e | 231 | search_dir[DIR_DOWN] = true; |
0580db2c VB |
232 | search_dir[DIR_BI_DIR] = true; |
233 | search_dir[DIR_DIRECT] = true; | |
8fc8598e JC |
234 | } |
235 | } | |
236 | ||
d5469036 | 237 | if (TxRxSelect == TX_DIR) |
8fc8598e JC |
238 | psearch_list = &ieee->Tx_TS_Admit_List; |
239 | else | |
240 | psearch_list = &ieee->Rx_TS_Admit_List; | |
241 | ||
242 | //for(dir = DIR_UP; dir <= DIR_BI_DIR; dir++) | |
d5469036 | 243 | for (dir = 0; dir <= DIR_BI_DIR; dir++) { |
a0886f73 | 244 | if (!search_dir[dir]) |
8fc8598e | 245 | continue; |
d5469036 | 246 | list_for_each_entry(pRet, psearch_list, list) { |
73b068f5 | 247 | // IEEE80211_DEBUG(IEEE80211_DL_TS, "ADD:%pM, TID:%d, dir:%d\n", pRet->Addr, pRet->TSpec.ts_info.ucTSID, pRet->TSpec.ts_info.ucDirection); |
12a540c3 | 248 | if (memcmp(pRet->addr, Addr, 6) == 0) |
73b068f5 | 249 | if (pRet->t_spec.ts_info.uc_tsid == TID) |
d5469036 | 250 | if (pRet->t_spec.ts_info.uc_direction == dir) { |
8fc8598e JC |
251 | // printk("Bingo! got it\n"); |
252 | break; | |
253 | } | |
8fc8598e | 254 | } |
d5469036 | 255 | if (&pRet->list != psearch_list) |
8fc8598e JC |
256 | break; |
257 | } | |
258 | ||
d5469036 | 259 | if (&pRet->list != psearch_list) |
f401441d | 260 | return pRet; |
8fc8598e JC |
261 | else |
262 | return NULL; | |
263 | } | |
264 | ||
6ae62698 | 265 | static void MakeTSEntry(struct ts_common_info *pTsCommonInfo, u8 *Addr, |
f1c3b488 | 266 | struct tspec_body *pTSPEC, union qos_tclas *pTCLAS, u8 TCLAS_Num, |
1d6fa895 | 267 | u8 TCLAS_Proc) |
8fc8598e JC |
268 | { |
269 | u8 count; | |
270 | ||
d5469036 | 271 | if (pTsCommonInfo == NULL) |
8fc8598e JC |
272 | return; |
273 | ||
12a540c3 | 274 | memcpy(pTsCommonInfo->addr, Addr, 6); |
8fc8598e | 275 | |
d5469036 | 276 | if (pTSPEC != NULL) |
9365607a | 277 | memcpy((u8 *)(&(pTsCommonInfo->t_spec)), (u8 *)pTSPEC, sizeof(struct tspec_body)); |
8fc8598e | 278 | |
d5469036 | 279 | for (count = 0; count < TCLAS_Num; count++) |
f1c3b488 | 280 | memcpy((u8 *)(&(pTsCommonInfo->t_class[count])), (u8 *)pTCLAS, sizeof(union qos_tclas)); |
8fc8598e | 281 | |
cb72b2f6 | 282 | pTsCommonInfo->t_clas_proc = TCLAS_Proc; |
32cb4d73 | 283 | pTsCommonInfo->t_clas_num = TCLAS_Num; |
8fc8598e JC |
284 | } |
285 | ||
286 | ||
287 | bool GetTs( | |
3c19fbb6 | 288 | struct ieee80211_device *ieee, |
6ae62698 | 289 | struct ts_common_info **ppTS, |
3c19fbb6 | 290 | u8 *Addr, |
8fc8598e | 291 | u8 TID, |
336b2577 | 292 | enum tr_select TxRxSelect, //Rx:1, Tx:0 |
8fc8598e JC |
293 | bool bAddNewTs |
294 | ) | |
295 | { | |
296 | u8 UP = 0; | |
297 | // | |
298 | // We do not build any TS for Broadcast or Multicast stream. | |
299 | // So reject these kinds of search here. | |
300 | // | |
d05038cc | 301 | if (is_multicast_ether_addr(Addr)) { |
8fc8598e JC |
302 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "get TS for Broadcast or Multicast\n"); |
303 | return false; | |
304 | } | |
a09fcbd7 | 305 | |
d05038cc | 306 | if (ieee->current_network.qos_data.supported == 0) { |
8fc8598e | 307 | UP = 0; |
d05038cc | 308 | } else { |
8fc8598e | 309 | // In WMM case: we use 4 TID only |
0b0251ad | 310 | if (!is_ac_valid(TID)) { |
f8628a47 | 311 | IEEE80211_DEBUG(IEEE80211_DL_ERR, " in %s(), TID(%d) is not valid\n", __func__, TID); |
8fc8598e JC |
312 | return false; |
313 | } | |
314 | ||
d05038cc | 315 | switch (TID) { |
8fc8598e JC |
316 | case 0: |
317 | case 3: | |
318 | UP = 0; | |
319 | break; | |
320 | ||
321 | case 1: | |
322 | case 2: | |
323 | UP = 2; | |
324 | break; | |
325 | ||
326 | case 4: | |
327 | case 5: | |
328 | UP = 5; | |
329 | break; | |
330 | ||
331 | case 6: | |
332 | case 7: | |
333 | UP = 7; | |
334 | break; | |
335 | } | |
336 | } | |
337 | ||
338 | *ppTS = SearchAdmitTRStream( | |
339 | ieee, | |
340 | Addr, | |
341 | UP, | |
342 | TxRxSelect); | |
d5469036 | 343 | if (*ppTS != NULL) { |
8fc8598e | 344 | return true; |
d05038cc | 345 | } else { |
a0886f73 | 346 | if (!bAddNewTs) { |
8fc8598e JC |
347 | IEEE80211_DEBUG(IEEE80211_DL_TS, "add new TS failed(tid:%d)\n", UP); |
348 | return false; | |
d05038cc | 349 | } else { |
8fc8598e JC |
350 | // |
351 | // Create a new Traffic stream for current Tx/Rx | |
352 | // This is for EDCA and WMM to add a new TS. | |
353 | // For HCCA or WMMSA, TS cannot be addmit without negotiation. | |
354 | // | |
9365607a | 355 | struct tspec_body TSpec; |
73b068f5 | 356 | struct qos_tsinfo *pTSInfo = &TSpec.ts_info; |
3c19fbb6 | 357 | struct list_head *pUnusedList = |
0580db2c VB |
358 | (TxRxSelect == TX_DIR) ? |
359 | (&ieee->Tx_TS_Unused_List) : | |
8fc8598e JC |
360 | (&ieee->Rx_TS_Unused_List); |
361 | ||
3c19fbb6 | 362 | struct list_head *pAddmitList = |
0580db2c VB |
363 | (TxRxSelect == TX_DIR) ? |
364 | (&ieee->Tx_TS_Admit_List) : | |
8fc8598e JC |
365 | (&ieee->Rx_TS_Admit_List); |
366 | ||
0580db2c | 367 | enum direction_value Dir = (ieee->iw_mode == IW_MODE_MASTER) ? |
f401441d SB |
368 | ((TxRxSelect == TX_DIR) ? DIR_DOWN : DIR_UP) : |
369 | ((TxRxSelect == TX_DIR) ? DIR_UP : DIR_DOWN); | |
8fc8598e | 370 | IEEE80211_DEBUG(IEEE80211_DL_TS, "to add Ts\n"); |
0580db2c | 371 | if (!list_empty(pUnusedList)) { |
d48cc3c3 JW |
372 | (*ppTS) = list_entry(pUnusedList->next, struct ts_common_info, list); |
373 | list_del_init(&(*ppTS)->list); | |
cd62878c | 374 | if (TxRxSelect == TX_DIR) { |
c1fdc5de | 375 | struct tx_ts_record *tmp = container_of(*ppTS, struct tx_ts_record, ts_common_info); |
8fc8598e | 376 | ResetTxTsEntry(tmp); |
d05038cc | 377 | } else { |
80b6f0d4 | 378 | struct rx_ts_record *tmp = container_of(*ppTS, struct rx_ts_record, ts_common_info); |
8fc8598e JC |
379 | ResetRxTsEntry(tmp); |
380 | } | |
381 | ||
0ee9f67c | 382 | IEEE80211_DEBUG(IEEE80211_DL_TS, "to init current TS, UP:%d, Dir:%d, addr:%pM\n", UP, Dir, Addr); |
49863190 | 383 | // Prepare TS Info related field |
0a679b93 JW |
384 | pTSInfo->uc_traffic_type = 0; // Traffic type: WMM is reserved in this field |
385 | pTSInfo->uc_tsid = UP; // TSID | |
386 | pTSInfo->uc_direction = Dir; // Direction: if there is DirectLink, this need additional consideration. | |
387 | pTSInfo->uc_access_policy = 1; // Access policy | |
388 | pTSInfo->uc_aggregation = 0; // Aggregation | |
389 | pTSInfo->uc_psb = 0; // Aggregation | |
390 | pTSInfo->uc_up = UP; // User priority | |
391 | pTSInfo->uc_ts_info_ack_policy = 0; // Ack policy | |
392 | pTSInfo->uc_schedule = 0; // Schedule | |
8fc8598e JC |
393 | |
394 | MakeTSEntry(*ppTS, Addr, &TSpec, NULL, 0, 0); | |
395 | AdmitTS(ieee, *ppTS, 0); | |
d48cc3c3 | 396 | list_add_tail(&((*ppTS)->list), pAddmitList); |
8fc8598e JC |
397 | // if there is DirectLink, we need to do additional operation here!! |
398 | ||
399 | return true; | |
d05038cc | 400 | } else { |
f8628a47 | 401 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "in function %s() There is not enough TS record to be used!!", __func__); |
8fc8598e JC |
402 | return false; |
403 | } | |
404 | } | |
405 | } | |
406 | } | |
407 | ||
6ae62698 | 408 | static void RemoveTsEntry(struct ieee80211_device *ieee, struct ts_common_info *pTs, |
336b2577 | 409 | enum tr_select TxRxSelect) |
8fc8598e JC |
410 | { |
411 | //u32 flags = 0; | |
412 | unsigned long flags = 0; | |
36cf191f | 413 | del_timer_sync(&pTs->setup_timer); |
27c4a9bb | 414 | del_timer_sync(&pTs->inact_timer); |
8fc8598e JC |
415 | TsInitDelBA(ieee, pTs, TxRxSelect); |
416 | ||
d5469036 | 417 | if (TxRxSelect == RX_DIR) { |
3eb9aa00 | 418 | struct rx_reorder_entry *pRxReorderEntry; |
80b6f0d4 | 419 | struct rx_ts_record *pRxTS = (struct rx_ts_record *)pTs; |
d5469036 | 420 | if (timer_pending(&pRxTS->rx_pkt_pending_timer)) |
5b76f8cb | 421 | del_timer_sync(&pRxTS->rx_pkt_pending_timer); |
8fc8598e | 422 | |
d5469036 | 423 | while (!list_empty(&pRxTS->rx_pending_pkt_list)) { |
e406322b | 424 | spin_lock_irqsave(&(ieee->reorder_spinlock), flags); |
a1ac7d1c | 425 | //pRxReorderEntry = list_entry(&pRxTS->rx_pending_pkt_list.prev,RX_REORDER_ENTRY,List); |
a279fc9d | 426 | pRxReorderEntry = list_entry(pRxTS->rx_pending_pkt_list.prev, struct rx_reorder_entry, List); |
e406322b MCC |
427 | list_del_init(&pRxReorderEntry->List); |
428 | { | |
429 | int i = 0; | |
3c19fbb6 | 430 | struct ieee80211_rxb *prxb = pRxReorderEntry->prxb; |
d05038cc | 431 | if (unlikely(!prxb)) { |
8fc8598e JC |
432 | spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); |
433 | return; | |
434 | } | |
0580db2c | 435 | for (i = 0; i < prxb->nr_subframes; i++) |
e406322b | 436 | dev_kfree_skb(prxb->subframes[i]); |
d05038cc | 437 | |
e406322b MCC |
438 | kfree(prxb); |
439 | prxb = NULL; | |
440 | } | |
0580db2c | 441 | list_add_tail(&pRxReorderEntry->List, &ieee->RxReorder_Unused_List); |
e406322b MCC |
442 | spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags); |
443 | } | |
8fc8598e | 444 | |
d05038cc | 445 | } else { |
1538be28 | 446 | struct tx_ts_record *pTxTS = (struct tx_ts_record *)pTs; |
1c194ce9 | 447 | del_timer_sync(&pTxTS->ts_add_ba_timer); |
8fc8598e JC |
448 | } |
449 | } | |
450 | ||
3c19fbb6 | 451 | void RemovePeerTS(struct ieee80211_device *ieee, u8 *Addr) |
8fc8598e | 452 | { |
6ae62698 | 453 | struct ts_common_info *pTS, *pTmpTS; |
a09fcbd7 | 454 | |
3cc7037b | 455 | printk("===========>%s,%pM\n", __func__, Addr); |
d48cc3c3 | 456 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) { |
12a540c3 | 457 | if (memcmp(pTS->addr, Addr, 6) == 0) { |
8fc8598e | 458 | RemoveTsEntry(ieee, pTS, TX_DIR); |
d48cc3c3 JW |
459 | list_del_init(&pTS->list); |
460 | list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List); | |
8fc8598e JC |
461 | } |
462 | } | |
463 | ||
d48cc3c3 | 464 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, list) { |
12a540c3 | 465 | if (memcmp(pTS->addr, Addr, 6) == 0) { |
8fc8598e JC |
466 | printk("====>remove Tx_TS_admin_list\n"); |
467 | RemoveTsEntry(ieee, pTS, TX_DIR); | |
d48cc3c3 JW |
468 | list_del_init(&pTS->list); |
469 | list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List); | |
8fc8598e JC |
470 | } |
471 | } | |
472 | ||
d48cc3c3 | 473 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, list) { |
12a540c3 | 474 | if (memcmp(pTS->addr, Addr, 6) == 0) { |
8fc8598e | 475 | RemoveTsEntry(ieee, pTS, RX_DIR); |
d48cc3c3 JW |
476 | list_del_init(&pTS->list); |
477 | list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List); | |
8fc8598e JC |
478 | } |
479 | } | |
480 | ||
d48cc3c3 | 481 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, list) { |
12a540c3 | 482 | if (memcmp(pTS->addr, Addr, 6) == 0) { |
8fc8598e | 483 | RemoveTsEntry(ieee, pTS, RX_DIR); |
d48cc3c3 JW |
484 | list_del_init(&pTS->list); |
485 | list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List); | |
8fc8598e JC |
486 | } |
487 | } | |
8fc8598e JC |
488 | } |
489 | ||
3c19fbb6 | 490 | void RemoveAllTS(struct ieee80211_device *ieee) |
8fc8598e | 491 | { |
6ae62698 | 492 | struct ts_common_info *pTS, *pTmpTS; |
a09fcbd7 | 493 | |
d48cc3c3 | 494 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Pending_List, list) { |
8fc8598e | 495 | RemoveTsEntry(ieee, pTS, TX_DIR); |
d48cc3c3 JW |
496 | list_del_init(&pTS->list); |
497 | list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List); | |
8fc8598e JC |
498 | } |
499 | ||
d48cc3c3 | 500 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Tx_TS_Admit_List, list) { |
8fc8598e | 501 | RemoveTsEntry(ieee, pTS, TX_DIR); |
d48cc3c3 JW |
502 | list_del_init(&pTS->list); |
503 | list_add_tail(&pTS->list, &ieee->Tx_TS_Unused_List); | |
8fc8598e JC |
504 | } |
505 | ||
d48cc3c3 | 506 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Pending_List, list) { |
8fc8598e | 507 | RemoveTsEntry(ieee, pTS, RX_DIR); |
d48cc3c3 JW |
508 | list_del_init(&pTS->list); |
509 | list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List); | |
8fc8598e JC |
510 | } |
511 | ||
d48cc3c3 | 512 | list_for_each_entry_safe(pTS, pTmpTS, &ieee->Rx_TS_Admit_List, list) { |
8fc8598e | 513 | RemoveTsEntry(ieee, pTS, RX_DIR); |
d48cc3c3 JW |
514 | list_del_init(&pTS->list); |
515 | list_add_tail(&pTS->list, &ieee->Rx_TS_Unused_List); | |
8fc8598e | 516 | } |
8fc8598e JC |
517 | } |
518 | ||
1538be28 | 519 | void TsStartAddBaProcess(struct ieee80211_device *ieee, struct tx_ts_record *pTxTS) |
8fc8598e | 520 | { |
d5469036 | 521 | if (!pTxTS->add_ba_req_in_progress) { |
e5afcc0f | 522 | pTxTS->add_ba_req_in_progress = true; |
d5469036 | 523 | if (pTxTS->add_ba_req_delayed) { |
3cc7037b | 524 | IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Delayed Start ADDBA after 60 sec!!\n", __func__); |
1c194ce9 | 525 | mod_timer(&pTxTS->ts_add_ba_timer, |
f3b8a53c | 526 | jiffies + msecs_to_jiffies(TS_ADDBA_DELAY)); |
d05038cc | 527 | } else { |
3cc7037b | 528 | IEEE80211_DEBUG(IEEE80211_DL_BA, "%s: Immediately Start ADDBA now!!\n", __func__); |
f401441d | 529 | mod_timer(&pTxTS->ts_add_ba_timer, jiffies + 10); //set 10 ticks |
8fc8598e | 530 | } |
d05038cc | 531 | } else { |
f8628a47 | 532 | IEEE80211_DEBUG(IEEE80211_DL_ERR, "%s()==>BA timer is already added\n", __func__); |
d05038cc | 533 | } |
8fc8598e | 534 | } |