diff options
Diffstat (limited to 'drivers/staging/rtl8712/rtl871x_sta_mgt.c')
-rw-r--r-- | drivers/staging/rtl8712/rtl871x_sta_mgt.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c new file mode 100644 index 00000000000..64f56961883 --- /dev/null +++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /****************************************************************************** | ||
2 | * rtl871x_sta_mgt.c | ||
3 | * | ||
4 | * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. | ||
5 | * Linux device driver for RTL8192SU | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of version 2 of the GNU General Public License as | ||
9 | * published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | ||
19 | * | ||
20 | * Modifications for inclusion into the Linux staging tree are | ||
21 | * Copyright(c) 2010 Larry Finger. All rights reserved. | ||
22 | * | ||
23 | * Contact information: | ||
24 | * WLAN FAE <wlanfae@realtek.com> | ||
25 | * Larry Finger <Larry.Finger@lwfinger.net> | ||
26 | * | ||
27 | ******************************************************************************/ | ||
28 | |||
29 | #define _RTL871X_STA_MGT_C_ | ||
30 | |||
31 | #include "osdep_service.h" | ||
32 | #include "drv_types.h" | ||
33 | #include "recv_osdep.h" | ||
34 | #include "xmit_osdep.h" | ||
35 | #include "sta_info.h" | ||
36 | |||
37 | static void _init_stainfo(struct sta_info *psta) | ||
38 | { | ||
39 | memset((u8 *)psta, 0, sizeof(struct sta_info)); | ||
40 | spin_lock_init(&psta->lock); | ||
41 | _init_listhead(&psta->list); | ||
42 | _init_listhead(&psta->hash_list); | ||
43 | _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); | ||
44 | _r8712_init_sta_recv_priv(&psta->sta_recvpriv); | ||
45 | #ifdef CONFIG_R8712_AP | ||
46 | _init_listhead(&psta->auth_list); | ||
47 | #endif | ||
48 | } | ||
49 | |||
50 | u32 _r8712_init_sta_priv(struct sta_priv *pstapriv) | ||
51 | { | ||
52 | struct sta_info *psta; | ||
53 | s32 i; | ||
54 | |||
55 | pstapriv->pallocated_stainfo_buf = _malloc(sizeof(struct sta_info) * | ||
56 | NUM_STA + 4); | ||
57 | if (pstapriv->pallocated_stainfo_buf == NULL) | ||
58 | return _FAIL; | ||
59 | pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 - | ||
60 | ((addr_t)(pstapriv->pallocated_stainfo_buf) & 3); | ||
61 | _init_queue(&pstapriv->free_sta_queue); | ||
62 | spin_lock_init(&pstapriv->sta_hash_lock); | ||
63 | pstapriv->asoc_sta_count = 0; | ||
64 | _init_queue(&pstapriv->sleep_q); | ||
65 | _init_queue(&pstapriv->wakeup_q); | ||
66 | psta = (struct sta_info *)(pstapriv->pstainfo_buf); | ||
67 | for (i = 0; i < NUM_STA; i++) { | ||
68 | _init_stainfo(psta); | ||
69 | _init_listhead(&(pstapriv->sta_hash[i])); | ||
70 | list_insert_tail(&psta->list, | ||
71 | get_list_head(&pstapriv->free_sta_queue)); | ||
72 | psta++; | ||
73 | } | ||
74 | #ifdef CONFIG_R8712_AP | ||
75 | _init_listhead(&pstapriv->asoc_list); | ||
76 | _init_listhead(&pstapriv->auth_list); | ||
77 | #endif | ||
78 | return _SUCCESS; | ||
79 | } | ||
80 | |||
81 | /* this function is used to free the memory of lock || sema for all stainfos */ | ||
82 | static void mfree_all_stainfo(struct sta_priv *pstapriv) | ||
83 | { | ||
84 | unsigned long irqL; | ||
85 | struct list_head *plist, *phead; | ||
86 | struct sta_info *psta = NULL; | ||
87 | |||
88 | spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); | ||
89 | phead = get_list_head(&pstapriv->free_sta_queue); | ||
90 | plist = get_next(phead); | ||
91 | while ((end_of_queue_search(phead, plist)) == false) { | ||
92 | psta = LIST_CONTAINOR(plist, struct sta_info, list); | ||
93 | plist = get_next(plist); | ||
94 | } | ||
95 | |||
96 | spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); | ||
97 | } | ||
98 | |||
99 | |||
100 | static void mfree_sta_priv_lock(struct sta_priv *pstapriv) | ||
101 | { | ||
102 | mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */ | ||
103 | } | ||
104 | |||
105 | u32 _r8712_free_sta_priv(struct sta_priv *pstapriv) | ||
106 | { | ||
107 | if (pstapriv) { | ||
108 | mfree_sta_priv_lock(pstapriv); | ||
109 | kfree(pstapriv->pallocated_stainfo_buf); | ||
110 | } | ||
111 | return _SUCCESS; | ||
112 | } | ||
113 | |||
114 | struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) | ||
115 | { | ||
116 | uint tmp_aid; | ||
117 | s32 index; | ||
118 | struct list_head *phash_list; | ||
119 | struct sta_info *psta; | ||
120 | struct __queue *pfree_sta_queue; | ||
121 | struct recv_reorder_ctrl *preorder_ctrl; | ||
122 | int i = 0; | ||
123 | u16 wRxSeqInitialValue = 0xffff; | ||
124 | unsigned long flags; | ||
125 | |||
126 | pfree_sta_queue = &pstapriv->free_sta_queue; | ||
127 | spin_lock_irqsave(&(pfree_sta_queue->lock), flags); | ||
128 | if (_queue_empty(pfree_sta_queue) == true) | ||
129 | psta = NULL; | ||
130 | else { | ||
131 | psta = LIST_CONTAINOR(get_next(&pfree_sta_queue->queue), | ||
132 | struct sta_info, list); | ||
133 | list_delete(&(psta->list)); | ||
134 | tmp_aid = psta->aid; | ||
135 | _init_stainfo(psta); | ||
136 | memcpy(psta->hwaddr, hwaddr, ETH_ALEN); | ||
137 | index = wifi_mac_hash(hwaddr); | ||
138 | if (index >= NUM_STA) { | ||
139 | psta = NULL; | ||
140 | goto exit; | ||
141 | } | ||
142 | phash_list = &(pstapriv->sta_hash[index]); | ||
143 | list_insert_tail(&psta->hash_list, phash_list); | ||
144 | pstapriv->asoc_sta_count++ ; | ||
145 | |||
146 | /* For the SMC router, the sequence number of first packet of WPS handshake | ||
147 | * will be 0. In this case, this packet will be dropped by recv_decache function | ||
148 | * if we use the 0x00 as the default value for tid_rxseq variable. So, we | ||
149 | * initialize the tid_rxseq variable as the 0xffff. | ||
150 | */ | ||
151 | for (i = 0; i < 16; i++) | ||
152 | memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], | ||
153 | &wRxSeqInitialValue, 2); | ||
154 | /* for A-MPDU Rx reordering buffer control */ | ||
155 | for (i = 0; i < 16 ; i++) { | ||
156 | preorder_ctrl = &psta->recvreorder_ctrl[i]; | ||
157 | preorder_ctrl->padapter = pstapriv->padapter; | ||
158 | preorder_ctrl->indicate_seq = 0xffff; | ||
159 | preorder_ctrl->wend_b = 0xffff; | ||
160 | preorder_ctrl->wsize_b = 64; | ||
161 | _init_queue(&preorder_ctrl->pending_recvframe_queue); | ||
162 | r8712_init_recv_timer(preorder_ctrl); | ||
163 | } | ||
164 | } | ||
165 | exit: | ||
166 | spin_unlock_irqrestore(&(pfree_sta_queue->lock), flags); | ||
167 | return psta; | ||
168 | } | ||
169 | |||
170 | /* using pstapriv->sta_hash_lock to protect */ | ||
171 | void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta) | ||
172 | { | ||
173 | int i; | ||
174 | unsigned long irqL0; | ||
175 | struct __queue *pfree_sta_queue; | ||
176 | struct recv_reorder_ctrl *preorder_ctrl; | ||
177 | struct sta_xmit_priv *pstaxmitpriv; | ||
178 | struct xmit_priv *pxmitpriv = &padapter->xmitpriv; | ||
179 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
180 | |||
181 | if (psta == NULL) | ||
182 | return; | ||
183 | pfree_sta_queue = &pstapriv->free_sta_queue; | ||
184 | pstaxmitpriv = &psta->sta_xmitpriv; | ||
185 | spin_lock_irqsave(&(pxmitpriv->vo_pending.lock), irqL0); | ||
186 | r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending); | ||
187 | list_delete(&(pstaxmitpriv->vo_q.tx_pending)); | ||
188 | spin_unlock_irqrestore(&(pxmitpriv->vo_pending.lock), irqL0); | ||
189 | spin_lock_irqsave(&(pxmitpriv->vi_pending.lock), irqL0); | ||
190 | r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending); | ||
191 | list_delete(&(pstaxmitpriv->vi_q.tx_pending)); | ||
192 | spin_unlock_irqrestore(&(pxmitpriv->vi_pending.lock), irqL0); | ||
193 | spin_lock_irqsave(&(pxmitpriv->bk_pending.lock), irqL0); | ||
194 | r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending); | ||
195 | list_delete(&(pstaxmitpriv->bk_q.tx_pending)); | ||
196 | spin_unlock_irqrestore(&(pxmitpriv->bk_pending.lock), irqL0); | ||
197 | spin_lock_irqsave(&(pxmitpriv->be_pending.lock), irqL0); | ||
198 | r8712_free_xmitframe_queue(pxmitpriv, &pstaxmitpriv->be_q.sta_pending); | ||
199 | list_delete(&(pstaxmitpriv->be_q.tx_pending)); | ||
200 | spin_unlock_irqrestore(&(pxmitpriv->be_pending.lock), irqL0); | ||
201 | list_delete(&psta->hash_list); | ||
202 | pstapriv->asoc_sta_count--; | ||
203 | /* re-init sta_info; 20061114 */ | ||
204 | _r8712_init_sta_xmit_priv(&psta->sta_xmitpriv); | ||
205 | _r8712_init_sta_recv_priv(&psta->sta_recvpriv); | ||
206 | /* for A-MPDU Rx reordering buffer control, | ||
207 | * cancel reordering_ctrl_timer */ | ||
208 | for (i = 0; i < 16; i++) { | ||
209 | preorder_ctrl = &psta->recvreorder_ctrl[i]; | ||
210 | _cancel_timer_ex(&preorder_ctrl->reordering_ctrl_timer); | ||
211 | } | ||
212 | spin_lock(&(pfree_sta_queue->lock)); | ||
213 | /* insert into free_sta_queue; 20061114 */ | ||
214 | list_insert_tail(&psta->list, get_list_head(pfree_sta_queue)); | ||
215 | spin_unlock(&(pfree_sta_queue->lock)); | ||
216 | } | ||
217 | |||
218 | /* free all stainfo which in sta_hash[all] */ | ||
219 | void r8712_free_all_stainfo(struct _adapter *padapter) | ||
220 | { | ||
221 | unsigned long irqL; | ||
222 | struct list_head *plist, *phead; | ||
223 | s32 index; | ||
224 | struct sta_info *psta = NULL; | ||
225 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
226 | struct sta_info *pbcmc_stainfo = r8712_get_bcmc_stainfo(padapter); | ||
227 | |||
228 | if (pstapriv->asoc_sta_count == 1) | ||
229 | return; | ||
230 | spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); | ||
231 | for (index = 0; index < NUM_STA; index++) { | ||
232 | phead = &(pstapriv->sta_hash[index]); | ||
233 | plist = get_next(phead); | ||
234 | while ((end_of_queue_search(phead, plist)) == false) { | ||
235 | psta = LIST_CONTAINOR(plist, | ||
236 | struct sta_info, hash_list); | ||
237 | plist = get_next(plist); | ||
238 | if (pbcmc_stainfo != psta) | ||
239 | r8712_free_stainfo(padapter , psta); | ||
240 | } | ||
241 | } | ||
242 | spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); | ||
243 | } | ||
244 | |||
245 | /* any station allocated can be searched by hash list */ | ||
246 | struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) | ||
247 | { | ||
248 | unsigned long irqL; | ||
249 | struct list_head *plist, *phead; | ||
250 | struct sta_info *psta = NULL; | ||
251 | u32 index; | ||
252 | |||
253 | if (hwaddr == NULL) | ||
254 | return NULL; | ||
255 | index = wifi_mac_hash(hwaddr); | ||
256 | spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL); | ||
257 | phead = &(pstapriv->sta_hash[index]); | ||
258 | plist = get_next(phead); | ||
259 | while ((end_of_queue_search(phead, plist)) == false) { | ||
260 | psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); | ||
261 | if ((!memcmp(psta->hwaddr, hwaddr, ETH_ALEN))) { | ||
262 | /* if found the matched address */ | ||
263 | break; | ||
264 | } | ||
265 | psta = NULL; | ||
266 | plist = get_next(plist); | ||
267 | } | ||
268 | spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL); | ||
269 | return psta; | ||
270 | } | ||
271 | |||
272 | void r8712_init_bcmc_stainfo(struct _adapter *padapter) | ||
273 | { | ||
274 | struct sta_info *psta; | ||
275 | struct tx_servq *ptxservq; | ||
276 | unsigned char bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
277 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
278 | |||
279 | psta = r8712_alloc_stainfo(pstapriv, bcast_addr); | ||
280 | if (psta == NULL) | ||
281 | return; | ||
282 | ptxservq = &(psta->sta_xmitpriv.be_q); | ||
283 | } | ||
284 | |||
285 | struct sta_info *r8712_get_bcmc_stainfo(struct _adapter *padapter) | ||
286 | { | ||
287 | struct sta_info *psta; | ||
288 | struct sta_priv *pstapriv = &padapter->stapriv; | ||
289 | u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
290 | |||
291 | psta = r8712_get_stainfo(pstapriv, bc_addr); | ||
292 | return psta; | ||
293 | } | ||
294 | |||
295 | |||
296 | u8 r8712_access_ctrl(struct wlan_acl_pool *pacl_list, u8 *mac_addr) | ||
297 | { | ||
298 | return true; | ||
299 | } | ||