1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved. |
5 | * |
6 | ******************************************************************************/ |
7 | #include <drv_types.h> |
8 | #include <rtw_debug.h> |
9 | |
10 | void _rtw_init_stainfo(struct sta_info *psta); |
11 | void _rtw_init_stainfo(struct sta_info *psta) |
12 | { |
13 | memset((u8 *)psta, 0, sizeof(struct sta_info)); |
14 | |
15 | spin_lock_init(&psta->lock); |
16 | INIT_LIST_HEAD(list: &psta->list); |
17 | INIT_LIST_HEAD(list: &psta->hash_list); |
18 | /* INIT_LIST_HEAD(&psta->asoc_list); */ |
19 | /* INIT_LIST_HEAD(&psta->sleep_list); */ |
20 | /* INIT_LIST_HEAD(&psta->wakeup_list); */ |
21 | |
22 | INIT_LIST_HEAD(list: &psta->sleep_q.queue); |
23 | spin_lock_init(&psta->sleep_q.lock); |
24 | psta->sleepq_len = 0; |
25 | |
26 | _rtw_init_sta_xmit_priv(psta_xmitpriv: &psta->sta_xmitpriv); |
27 | _rtw_init_sta_recv_priv(psta_recvpriv: &psta->sta_recvpriv); |
28 | |
29 | INIT_LIST_HEAD(list: &psta->asoc_list); |
30 | |
31 | INIT_LIST_HEAD(list: &psta->auth_list); |
32 | |
33 | psta->expire_to = 0; |
34 | |
35 | psta->flags = 0; |
36 | |
37 | psta->capability = 0; |
38 | |
39 | psta->bpairwise_key_installed = false; |
40 | |
41 | psta->nonerp_set = 0; |
42 | psta->no_short_slot_time_set = 0; |
43 | psta->no_short_preamble_set = 0; |
44 | psta->no_ht_gf_set = 0; |
45 | psta->no_ht_set = 0; |
46 | psta->ht_20mhz_set = 0; |
47 | |
48 | psta->under_exist_checking = 0; |
49 | |
50 | psta->keep_alive_trycnt = 0; |
51 | } |
52 | |
53 | u32 _rtw_init_sta_priv(struct sta_priv *pstapriv) |
54 | { |
55 | struct sta_info *psta; |
56 | s32 i; |
57 | |
58 | pstapriv->pallocated_stainfo_buf = vzalloc(size: sizeof(struct sta_info) * NUM_STA+4); |
59 | |
60 | if (!pstapriv->pallocated_stainfo_buf) |
61 | return _FAIL; |
62 | |
63 | pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - |
64 | ((SIZE_PTR)(pstapriv->pallocated_stainfo_buf) & 3); |
65 | |
66 | INIT_LIST_HEAD(list: &pstapriv->free_sta_queue.queue); |
67 | spin_lock_init(&pstapriv->free_sta_queue.lock); |
68 | |
69 | spin_lock_init(&pstapriv->sta_hash_lock); |
70 | |
71 | /* _rtw_init_queue(&pstapriv->asoc_q); */ |
72 | pstapriv->asoc_sta_count = 0; |
73 | INIT_LIST_HEAD(list: &pstapriv->sleep_q.queue); |
74 | spin_lock_init(&pstapriv->sleep_q.lock); |
75 | INIT_LIST_HEAD(list: &pstapriv->wakeup_q.queue); |
76 | spin_lock_init(&pstapriv->wakeup_q.lock); |
77 | |
78 | psta = (struct sta_info *)(pstapriv->pstainfo_buf); |
79 | |
80 | for (i = 0; i < NUM_STA; i++) { |
81 | _rtw_init_stainfo(psta); |
82 | |
83 | INIT_LIST_HEAD(list: &(pstapriv->sta_hash[i])); |
84 | |
85 | list_add_tail(new: &psta->list, head: get_list_head(queue: &pstapriv->free_sta_queue)); |
86 | |
87 | psta++; |
88 | } |
89 | |
90 | pstapriv->sta_dz_bitmap = 0; |
91 | pstapriv->tim_bitmap = 0; |
92 | |
93 | INIT_LIST_HEAD(list: &pstapriv->asoc_list); |
94 | INIT_LIST_HEAD(list: &pstapriv->auth_list); |
95 | spin_lock_init(&pstapriv->asoc_list_lock); |
96 | spin_lock_init(&pstapriv->auth_list_lock); |
97 | pstapriv->asoc_list_cnt = 0; |
98 | pstapriv->auth_list_cnt = 0; |
99 | |
100 | pstapriv->auth_to = 3; /* 3*2 = 6 sec */ |
101 | pstapriv->assoc_to = 3; |
102 | pstapriv->expire_to = 3; /* 3*2 = 6 sec */ |
103 | pstapriv->max_num_sta = NUM_STA; |
104 | return _SUCCESS; |
105 | } |
106 | |
107 | inline int rtw_stainfo_offset(struct sta_priv *stapriv, struct sta_info *sta) |
108 | { |
109 | int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info); |
110 | |
111 | return offset; |
112 | } |
113 | |
114 | inline struct sta_info *rtw_get_stainfo_by_offset(struct sta_priv *stapriv, int offset) |
115 | { |
116 | return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info)); |
117 | } |
118 | |
119 | /* this function is used to free the memory of lock || sema for all stainfos */ |
120 | void kfree_all_stainfo(struct sta_priv *pstapriv); |
121 | void kfree_all_stainfo(struct sta_priv *pstapriv) |
122 | { |
123 | struct list_head *plist, *phead; |
124 | |
125 | spin_lock_bh(lock: &pstapriv->sta_hash_lock); |
126 | |
127 | phead = get_list_head(queue: &pstapriv->free_sta_queue); |
128 | plist = get_next(list: phead); |
129 | |
130 | while (phead != plist) |
131 | plist = get_next(list: plist); |
132 | |
133 | spin_unlock_bh(lock: &pstapriv->sta_hash_lock); |
134 | } |
135 | |
136 | void kfree_sta_priv_lock(struct sta_priv *pstapriv); |
137 | void kfree_sta_priv_lock(struct sta_priv *pstapriv) |
138 | { |
139 | kfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */ |
140 | } |
141 | |
142 | u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) |
143 | { |
144 | struct list_head *phead, *plist; |
145 | struct sta_info *psta = NULL; |
146 | struct recv_reorder_ctrl *preorder_ctrl; |
147 | int index; |
148 | |
149 | if (pstapriv) { |
150 | /*delete all reordering_ctrl_timer */ |
151 | spin_lock_bh(lock: &pstapriv->sta_hash_lock); |
152 | for (index = 0; index < NUM_STA; index++) { |
153 | phead = &(pstapriv->sta_hash[index]); |
154 | list_for_each(plist, phead) { |
155 | int i; |
156 | |
157 | psta = list_entry(plist, struct sta_info, |
158 | hash_list); |
159 | |
160 | for (i = 0; i < 16 ; i++) { |
161 | preorder_ctrl = &psta->recvreorder_ctrl[i]; |
162 | del_timer_sync(timer: &preorder_ctrl->reordering_ctrl_timer); |
163 | } |
164 | } |
165 | } |
166 | spin_unlock_bh(lock: &pstapriv->sta_hash_lock); |
167 | /*===============================*/ |
168 | |
169 | kfree_sta_priv_lock(pstapriv); |
170 | |
171 | vfree(addr: pstapriv->pallocated_stainfo_buf); |
172 | } |
173 | return _SUCCESS; |
174 | } |
175 | |
176 | /* struct sta_info *rtw_alloc_stainfo(_queue *pfree_sta_queue, unsigned char *hwaddr) */ |
177 | struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) |
178 | { |
179 | s32 index; |
180 | struct list_head *phash_list; |
181 | struct sta_info *psta; |
182 | struct __queue *pfree_sta_queue; |
183 | struct recv_reorder_ctrl *preorder_ctrl; |
184 | int i = 0; |
185 | u16 wRxSeqInitialValue = 0xffff; |
186 | |
187 | pfree_sta_queue = &pstapriv->free_sta_queue; |
188 | |
189 | /* spin_lock_bh(&(pfree_sta_queue->lock)); */ |
190 | spin_lock_bh(lock: &(pstapriv->sta_hash_lock)); |
191 | if (list_empty(head: &pfree_sta_queue->queue)) { |
192 | /* spin_unlock_bh(&(pfree_sta_queue->lock)); */ |
193 | spin_unlock_bh(lock: &(pstapriv->sta_hash_lock)); |
194 | return NULL; |
195 | } else { |
196 | psta = container_of(get_next(&pfree_sta_queue->queue), struct sta_info, list); |
197 | |
198 | list_del_init(entry: &(psta->list)); |
199 | |
200 | /* spin_unlock_bh(&(pfree_sta_queue->lock)); */ |
201 | |
202 | _rtw_init_stainfo(psta); |
203 | |
204 | psta->padapter = pstapriv->padapter; |
205 | |
206 | memcpy(psta->hwaddr, hwaddr, ETH_ALEN); |
207 | |
208 | index = wifi_mac_hash(mac: hwaddr); |
209 | |
210 | if (index >= NUM_STA) { |
211 | spin_unlock_bh(lock: &(pstapriv->sta_hash_lock)); |
212 | psta = NULL; |
213 | goto exit; |
214 | } |
215 | phash_list = &(pstapriv->sta_hash[index]); |
216 | |
217 | /* spin_lock_bh(&(pstapriv->sta_hash_lock)); */ |
218 | |
219 | list_add_tail(new: &psta->hash_list, head: phash_list); |
220 | |
221 | pstapriv->asoc_sta_count++; |
222 | |
223 | /* spin_unlock_bh(&(pstapriv->sta_hash_lock)); */ |
224 | |
225 | /* Commented by Albert 2009/08/13 */ |
226 | /* For the SMC router, the sequence number of first packet of WPS handshake will be 0. */ |
227 | /* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */ |
228 | /* So, we initialize the tid_rxseq variable as the 0xffff. */ |
229 | |
230 | for (i = 0; i < 16; i++) |
231 | memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); |
232 | |
233 | init_addba_retry_timer(padapter: pstapriv->padapter, psta); |
234 | |
235 | /* for A-MPDU Rx reordering buffer control */ |
236 | for (i = 0; i < 16 ; i++) { |
237 | preorder_ctrl = &psta->recvreorder_ctrl[i]; |
238 | |
239 | preorder_ctrl->padapter = pstapriv->padapter; |
240 | |
241 | preorder_ctrl->enable = false; |
242 | |
243 | preorder_ctrl->indicate_seq = 0xffff; |
244 | preorder_ctrl->wend_b = 0xffff; |
245 | /* preorder_ctrl->wsize_b = (NR_RECVBUFF-2); */ |
246 | preorder_ctrl->wsize_b = 64;/* 64; */ |
247 | |
248 | INIT_LIST_HEAD(list: &preorder_ctrl->pending_recvframe_queue.queue); |
249 | spin_lock_init(&preorder_ctrl->pending_recvframe_queue.lock); |
250 | |
251 | rtw_init_recv_timer(preorder_ctrl); |
252 | } |
253 | |
254 | /* init for DM */ |
255 | psta->rssi_stat.UndecoratedSmoothedPWDB = (-1); |
256 | psta->rssi_stat.UndecoratedSmoothedCCK = (-1); |
257 | |
258 | /* init for the sequence number of received management frame */ |
259 | psta->RxMgmtFrameSeqNum = 0xffff; |
260 | spin_unlock_bh(lock: &(pstapriv->sta_hash_lock)); |
261 | /* alloc mac id for non-bc/mc station, */ |
262 | rtw_alloc_macid(padapter: pstapriv->padapter, psta); |
263 | } |
264 | |
265 | exit: |
266 | |
267 | return psta; |
268 | } |
269 | |
270 | u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) |
271 | { |
272 | int i; |
273 | struct __queue *pfree_sta_queue; |
274 | struct recv_reorder_ctrl *preorder_ctrl; |
275 | struct sta_xmit_priv *pstaxmitpriv; |
276 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; |
277 | struct sta_priv *pstapriv = &padapter->stapriv; |
278 | struct hw_xmit *phwxmit; |
279 | |
280 | if (!psta) |
281 | goto exit; |
282 | |
283 | spin_lock_bh(lock: &psta->lock); |
284 | psta->state &= ~_FW_LINKED; |
285 | spin_unlock_bh(lock: &psta->lock); |
286 | |
287 | pfree_sta_queue = &pstapriv->free_sta_queue; |
288 | |
289 | pstaxmitpriv = &psta->sta_xmitpriv; |
290 | |
291 | /* list_del_init(&psta->sleep_list); */ |
292 | |
293 | /* list_del_init(&psta->wakeup_list); */ |
294 | |
295 | spin_lock_bh(lock: &pxmitpriv->lock); |
296 | |
297 | rtw_free_xmitframe_queue(pxmitpriv, pframequeue: &psta->sleep_q); |
298 | psta->sleepq_len = 0; |
299 | |
300 | /* vo */ |
301 | /* spin_lock_bh(&(pxmitpriv->vo_pending.lock)); */ |
302 | rtw_free_xmitframe_queue(pxmitpriv, pframequeue: &pstaxmitpriv->vo_q.sta_pending); |
303 | list_del_init(entry: &(pstaxmitpriv->vo_q.tx_pending)); |
304 | phwxmit = pxmitpriv->hwxmits; |
305 | phwxmit->accnt -= pstaxmitpriv->vo_q.qcnt; |
306 | pstaxmitpriv->vo_q.qcnt = 0; |
307 | /* spin_unlock_bh(&(pxmitpriv->vo_pending.lock)); */ |
308 | |
309 | /* vi */ |
310 | /* spin_lock_bh(&(pxmitpriv->vi_pending.lock)); */ |
311 | rtw_free_xmitframe_queue(pxmitpriv, pframequeue: &pstaxmitpriv->vi_q.sta_pending); |
312 | list_del_init(entry: &(pstaxmitpriv->vi_q.tx_pending)); |
313 | phwxmit = pxmitpriv->hwxmits+1; |
314 | phwxmit->accnt -= pstaxmitpriv->vi_q.qcnt; |
315 | pstaxmitpriv->vi_q.qcnt = 0; |
316 | /* spin_unlock_bh(&(pxmitpriv->vi_pending.lock)); */ |
317 | |
318 | /* be */ |
319 | /* spin_lock_bh(&(pxmitpriv->be_pending.lock)); */ |
320 | rtw_free_xmitframe_queue(pxmitpriv, pframequeue: &pstaxmitpriv->be_q.sta_pending); |
321 | list_del_init(entry: &(pstaxmitpriv->be_q.tx_pending)); |
322 | phwxmit = pxmitpriv->hwxmits+2; |
323 | phwxmit->accnt -= pstaxmitpriv->be_q.qcnt; |
324 | pstaxmitpriv->be_q.qcnt = 0; |
325 | /* spin_unlock_bh(&(pxmitpriv->be_pending.lock)); */ |
326 | |
327 | /* bk */ |
328 | /* spin_lock_bh(&(pxmitpriv->bk_pending.lock)); */ |
329 | rtw_free_xmitframe_queue(pxmitpriv, pframequeue: &pstaxmitpriv->bk_q.sta_pending); |
330 | list_del_init(entry: &(pstaxmitpriv->bk_q.tx_pending)); |
331 | phwxmit = pxmitpriv->hwxmits+3; |
332 | phwxmit->accnt -= pstaxmitpriv->bk_q.qcnt; |
333 | pstaxmitpriv->bk_q.qcnt = 0; |
334 | /* spin_unlock_bh(&(pxmitpriv->bk_pending.lock)); */ |
335 | |
336 | spin_unlock_bh(lock: &pxmitpriv->lock); |
337 | |
338 | spin_lock_bh(lock: &pstapriv->sta_hash_lock); |
339 | list_del_init(entry: &psta->hash_list); |
340 | pstapriv->asoc_sta_count--; |
341 | spin_unlock_bh(lock: &pstapriv->sta_hash_lock); |
342 | |
343 | /* re-init sta_info; 20061114 will be init in alloc_stainfo */ |
344 | /* _rtw_init_sta_xmit_priv(&psta->sta_xmitpriv); */ |
345 | /* _rtw_init_sta_recv_priv(&psta->sta_recvpriv); */ |
346 | |
347 | del_timer_sync(timer: &psta->addba_retry_timer); |
348 | |
349 | /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */ |
350 | for (i = 0; i < 16 ; i++) { |
351 | struct list_head *phead, *plist; |
352 | union recv_frame *prframe; |
353 | struct __queue *ppending_recvframe_queue; |
354 | struct __queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue; |
355 | |
356 | preorder_ctrl = &psta->recvreorder_ctrl[i]; |
357 | |
358 | del_timer_sync(timer: &preorder_ctrl->reordering_ctrl_timer); |
359 | |
360 | ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; |
361 | |
362 | spin_lock_bh(lock: &ppending_recvframe_queue->lock); |
363 | |
364 | phead = get_list_head(queue: ppending_recvframe_queue); |
365 | plist = get_next(list: phead); |
366 | |
367 | while (!list_empty(head: phead)) { |
368 | prframe = (union recv_frame *)plist; |
369 | |
370 | plist = get_next(list: plist); |
371 | |
372 | list_del_init(entry: &(prframe->u.hdr.list)); |
373 | |
374 | rtw_free_recvframe(precvframe: prframe, pfree_recv_queue); |
375 | } |
376 | |
377 | spin_unlock_bh(lock: &ppending_recvframe_queue->lock); |
378 | } |
379 | |
380 | if (!(psta->state & WIFI_AP_STATE)) |
381 | rtw_hal_set_odm_var(padapter, eVariable: HAL_ODM_STA_INFO, pValue1: psta, bSet: false); |
382 | |
383 | /* release mac id for non-bc/mc station, */ |
384 | rtw_release_macid(padapter: pstapriv->padapter, psta); |
385 | |
386 | /* |
387 | spin_lock_bh(&pstapriv->asoc_list_lock); |
388 | list_del_init(&psta->asoc_list); |
389 | spin_unlock_bh(&pstapriv->asoc_list_lock); |
390 | */ |
391 | spin_lock_bh(lock: &pstapriv->auth_list_lock); |
392 | if (!list_empty(head: &psta->auth_list)) { |
393 | list_del_init(entry: &psta->auth_list); |
394 | pstapriv->auth_list_cnt--; |
395 | } |
396 | spin_unlock_bh(lock: &pstapriv->auth_list_lock); |
397 | |
398 | psta->expire_to = 0; |
399 | psta->sleepq_ac_len = 0; |
400 | psta->qos_info = 0; |
401 | |
402 | psta->max_sp_len = 0; |
403 | psta->uapsd_bk = 0; |
404 | psta->uapsd_be = 0; |
405 | psta->uapsd_vi = 0; |
406 | psta->uapsd_vo = 0; |
407 | |
408 | psta->has_legacy_ac = 0; |
409 | |
410 | pstapriv->sta_dz_bitmap &= ~BIT(psta->aid); |
411 | pstapriv->tim_bitmap &= ~BIT(psta->aid); |
412 | |
413 | if ((psta->aid > 0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) { |
414 | pstapriv->sta_aid[psta->aid - 1] = NULL; |
415 | psta->aid = 0; |
416 | } |
417 | |
418 | psta->under_exist_checking = 0; |
419 | |
420 | /* spin_lock_bh(&(pfree_sta_queue->lock)); */ |
421 | list_add_tail(new: &psta->list, head: get_list_head(queue: pfree_sta_queue)); |
422 | /* spin_unlock_bh(&(pfree_sta_queue->lock)); */ |
423 | |
424 | exit: |
425 | return _SUCCESS; |
426 | } |
427 | |
428 | /* free all stainfo which in sta_hash[all] */ |
429 | void rtw_free_all_stainfo(struct adapter *padapter) |
430 | { |
431 | struct list_head *plist, *phead, *tmp; |
432 | s32 index; |
433 | struct sta_info *psta = NULL; |
434 | struct sta_priv *pstapriv = &padapter->stapriv; |
435 | struct sta_info *pbcmc_stainfo = rtw_get_bcmc_stainfo(padapter); |
436 | LIST_HEAD(stainfo_free_list); |
437 | |
438 | if (pstapriv->asoc_sta_count == 1) |
439 | return; |
440 | |
441 | spin_lock_bh(lock: &pstapriv->sta_hash_lock); |
442 | |
443 | for (index = 0; index < NUM_STA; index++) { |
444 | phead = &(pstapriv->sta_hash[index]); |
445 | list_for_each_safe(plist, tmp, phead) { |
446 | psta = list_entry(plist, struct sta_info, hash_list); |
447 | |
448 | if (pbcmc_stainfo != psta) |
449 | list_move(list: &psta->hash_list, head: &stainfo_free_list); |
450 | } |
451 | } |
452 | |
453 | spin_unlock_bh(lock: &pstapriv->sta_hash_lock); |
454 | |
455 | list_for_each_safe(plist, tmp, &stainfo_free_list) { |
456 | psta = list_entry(plist, struct sta_info, hash_list); |
457 | rtw_free_stainfo(padapter, psta); |
458 | } |
459 | } |
460 | |
461 | /* any station allocated can be searched by hash list */ |
462 | struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) |
463 | { |
464 | struct list_head *plist, *phead; |
465 | struct sta_info *psta = NULL; |
466 | u32 index; |
467 | u8 *addr; |
468 | u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
469 | |
470 | if (!hwaddr) |
471 | return NULL; |
472 | |
473 | if (is_multicast_ether_addr(addr: hwaddr)) |
474 | addr = bc_addr; |
475 | else |
476 | addr = hwaddr; |
477 | |
478 | index = wifi_mac_hash(mac: addr); |
479 | |
480 | spin_lock_bh(lock: &pstapriv->sta_hash_lock); |
481 | |
482 | phead = &(pstapriv->sta_hash[index]); |
483 | list_for_each(plist, phead) { |
484 | psta = list_entry(plist, struct sta_info, hash_list); |
485 | |
486 | if ((!memcmp(p: psta->hwaddr, q: addr, ETH_ALEN))) |
487 | /* if found the matched address */ |
488 | break; |
489 | |
490 | psta = NULL; |
491 | } |
492 | |
493 | spin_unlock_bh(lock: &pstapriv->sta_hash_lock); |
494 | return psta; |
495 | } |
496 | |
497 | u32 rtw_init_bcmc_stainfo(struct adapter *padapter) |
498 | { |
499 | struct sta_info *psta; |
500 | NDIS_802_11_MAC_ADDRESS bcast_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
501 | |
502 | struct sta_priv *pstapriv = &padapter->stapriv; |
503 | /* struct __queue *pstapending = &padapter->xmitpriv.bm_pending; */ |
504 | |
505 | psta = rtw_alloc_stainfo(pstapriv, hwaddr: bcast_addr); |
506 | |
507 | if (!psta) |
508 | return _FAIL; |
509 | |
510 | /* default broadcast & multicast use macid 1 */ |
511 | psta->mac_id = 1; |
512 | |
513 | return _SUCCESS; |
514 | } |
515 | |
516 | struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter) |
517 | { |
518 | struct sta_priv *pstapriv = &padapter->stapriv; |
519 | u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
520 | |
521 | return rtw_get_stainfo(pstapriv, hwaddr: bc_addr); |
522 | } |
523 | |
524 | u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr) |
525 | { |
526 | bool res = true; |
527 | struct list_head *plist, *phead; |
528 | struct rtw_wlan_acl_node *paclnode; |
529 | bool match = false; |
530 | struct sta_priv *pstapriv = &padapter->stapriv; |
531 | struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; |
532 | struct __queue *pacl_node_q = &pacl_list->acl_node_q; |
533 | |
534 | spin_lock_bh(lock: &(pacl_node_q->lock)); |
535 | phead = get_list_head(queue: pacl_node_q); |
536 | list_for_each(plist, phead) { |
537 | paclnode = list_entry(plist, struct rtw_wlan_acl_node, list); |
538 | |
539 | if (!memcmp(p: paclnode->addr, q: mac_addr, ETH_ALEN)) |
540 | if (paclnode->valid == true) { |
541 | match = true; |
542 | break; |
543 | } |
544 | } |
545 | spin_unlock_bh(lock: &(pacl_node_q->lock)); |
546 | |
547 | if (pacl_list->mode == 1) /* accept unless in deny list */ |
548 | res = !match; |
549 | |
550 | else if (pacl_list->mode == 2)/* deny unless in accept list */ |
551 | res = match; |
552 | else |
553 | res = true; |
554 | |
555 | return res; |
556 | } |
557 | |