[s3c24xx] bump to 2.6.30-rc6
[openwrt.git] / target / linux / s3c24xx / files-2.6.30 / drivers / ar6000 / wlan / wlan_node.c
1 /*-
2 * Copyright (c) 2001 Atsushi Onoe
3 * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
4 * Copyright (c) 2004-2005 Atheros Communications
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id: //depot/sw/releases/olca2.0-GPL/host/wlan/src/wlan_node.c#1 $
34 */
35 /*
36 * IEEE 802.11 node handling support.
37 */
38 #include <a_config.h>
39 #include <athdefs.h>
40 #include <a_types.h>
41 #include <a_osapi.h>
42 #include <a_debug.h>
43 #include <ieee80211.h>
44 #include <wlan_api.h>
45 #include <ieee80211_node.h>
46 #include <htc_api.h>
47 #include <wmi.h>
48 #include <wmi_api.h>
49
50 static void wlan_node_timeout(A_ATH_TIMER arg);
51 static bss_t * _ieee80211_find_node(struct ieee80211_node_table *nt,
52 const A_UINT8 *macaddr);
53
54 bss_t *
55 wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size)
56 {
57 bss_t *ni;
58
59 ni = A_MALLOC_NOWAIT(sizeof(bss_t));
60
61 if (ni != NULL) {
62 ni->ni_buf = A_MALLOC_NOWAIT(wh_size);
63 if (ni->ni_buf == NULL) {
64 A_FREE(ni);
65 ni = NULL;
66 return ni;
67 }
68 } else {
69 return ni;
70 }
71
72 /* Make sure our lists are clean */
73 ni->ni_list_next = NULL;
74 ni->ni_list_prev = NULL;
75 ni->ni_hash_next = NULL;
76 ni->ni_hash_prev = NULL;
77
78 //
79 // ni_scangen never initialized before and during suspend/resume of winmobile, customer (LG/SEMCO) identified
80 // that some junk has been stored in this, due to this scan list didn't properly updated
81 //
82 ni->ni_scangen = 0;
83
84 return ni;
85 }
86
87 void
88 wlan_node_free(bss_t *ni)
89 {
90 if (ni->ni_buf != NULL) {
91 A_FREE(ni->ni_buf);
92 }
93 A_FREE(ni);
94 }
95
96 void
97 wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
98 const A_UINT8 *macaddr)
99 {
100 int hash;
101
102 A_MEMCPY(ni->ni_macaddr, macaddr, IEEE80211_ADDR_LEN);
103 hash = IEEE80211_NODE_HASH(macaddr);
104 ieee80211_node_initref(ni); /* mark referenced */
105
106 ni->ni_tstamp = A_GET_MS(WLAN_NODE_INACT_TIMEOUT_MSEC);
107 IEEE80211_NODE_LOCK_BH(nt);
108
109 /* Insert at the end of the node list */
110 ni->ni_list_next = NULL;
111 ni->ni_list_prev = nt->nt_node_last;
112 if(nt->nt_node_last != NULL)
113 {
114 nt->nt_node_last->ni_list_next = ni;
115 }
116 nt->nt_node_last = ni;
117 if(nt->nt_node_first == NULL)
118 {
119 nt->nt_node_first = ni;
120 }
121
122 /* Insert into the hash list i.e. the bucket */
123 if((ni->ni_hash_next = nt->nt_hash[hash]) != NULL)
124 {
125 nt->nt_hash[hash]->ni_hash_prev = ni;
126 }
127 ni->ni_hash_prev = NULL;
128 nt->nt_hash[hash] = ni;
129
130 if (!nt->isTimerArmed) {
131 A_TIMEOUT_MS(&nt->nt_inact_timer, WLAN_NODE_INACT_TIMEOUT_MSEC, 0);
132 nt->isTimerArmed = TRUE;
133 }
134
135 IEEE80211_NODE_UNLOCK_BH(nt);
136 }
137
138 static bss_t *
139 _ieee80211_find_node(struct ieee80211_node_table *nt,
140 const A_UINT8 *macaddr)
141 {
142 bss_t *ni;
143 int hash;
144
145 IEEE80211_NODE_LOCK_ASSERT(nt);
146
147 hash = IEEE80211_NODE_HASH(macaddr);
148 for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
149 if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
150 ieee80211_node_incref(ni); /* mark referenced */
151 return ni;
152 }
153 }
154 return NULL;
155 }
156
157 bss_t *
158 wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr)
159 {
160 bss_t *ni;
161
162 IEEE80211_NODE_LOCK(nt);
163 ni = _ieee80211_find_node(nt, macaddr);
164 IEEE80211_NODE_UNLOCK(nt);
165 return ni;
166 }
167
168 /*
169 * Reclaim a node. If this is the last reference count then
170 * do the normal free work. Otherwise remove it from the node
171 * table and mark it gone by clearing the back-reference.
172 */
173 void
174 wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni)
175 {
176 IEEE80211_NODE_LOCK(nt);
177
178 if(ni->ni_list_prev == NULL)
179 {
180 /* First in list so fix the list head */
181 nt->nt_node_first = ni->ni_list_next;
182 }
183 else
184 {
185 ni->ni_list_prev->ni_list_next = ni->ni_list_next;
186 }
187
188 if(ni->ni_list_next == NULL)
189 {
190 /* Last in list so fix list tail */
191 nt->nt_node_last = ni->ni_list_prev;
192 }
193 else
194 {
195 ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
196 }
197
198 if(ni->ni_hash_prev == NULL)
199 {
200 /* First in list so fix the list head */
201 int hash;
202 hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
203 nt->nt_hash[hash] = ni->ni_hash_next;
204 }
205 else
206 {
207 ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
208 }
209
210 if(ni->ni_hash_next != NULL)
211 {
212 ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
213 }
214 wlan_node_free(ni);
215
216 IEEE80211_NODE_UNLOCK(nt);
217 }
218
219 static void
220 wlan_node_dec_free(bss_t *ni)
221 {
222 if (ieee80211_node_dectestref(ni)) {
223 wlan_node_free(ni);
224 }
225 }
226
227 void
228 wlan_free_allnodes(struct ieee80211_node_table *nt)
229 {
230 bss_t *ni;
231
232 while ((ni = nt->nt_node_first) != NULL) {
233 wlan_node_reclaim(nt, ni);
234 }
235 }
236
237 void
238 wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
239 void *arg)
240 {
241 bss_t *ni;
242 A_UINT32 gen;
243
244 gen = ++nt->nt_scangen;
245
246 IEEE80211_NODE_LOCK(nt);
247 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
248 if (ni->ni_scangen != gen) {
249 ni->ni_scangen = gen;
250 (void) ieee80211_node_incref(ni);
251 (*f)(arg, ni);
252 wlan_node_dec_free(ni);
253 }
254 }
255 IEEE80211_NODE_UNLOCK(nt);
256 }
257
258 /*
259 * Node table support.
260 */
261 void
262 wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt)
263 {
264 int i;
265
266 AR_DEBUG_PRINTF(ATH_DEBUG_WLAN, ("node table = 0x%x\n", (A_UINT32)nt));
267 IEEE80211_NODE_LOCK_INIT(nt);
268
269 nt->nt_node_first = nt->nt_node_last = NULL;
270 for(i = 0; i < IEEE80211_NODE_HASHSIZE; i++)
271 {
272 nt->nt_hash[i] = NULL;
273 }
274 A_INIT_TIMER(&nt->nt_inact_timer, wlan_node_timeout, nt);
275 nt->isTimerArmed = FALSE;
276 nt->nt_wmip = wmip;
277 }
278
279 static void
280 wlan_node_timeout(A_ATH_TIMER arg)
281 {
282 struct ieee80211_node_table *nt = (struct ieee80211_node_table *)arg;
283 bss_t *bss, *nextBss;
284 A_UINT8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = FALSE;
285
286 wmi_get_current_bssid(nt->nt_wmip, myBssid);
287
288 bss = nt->nt_node_first;
289 while (bss != NULL)
290 {
291 nextBss = bss->ni_list_next;
292 if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
293 {
294
295 if (bss->ni_tstamp <= A_GET_MS(0))
296 {
297 /*
298 * free up all but the current bss - if set
299 */
300 wlan_node_reclaim(nt, bss);
301 }
302 else
303 {
304 /*
305 * Re-arm timer, only when we have a bss other than
306 * current bss AND it is not aged-out.
307 */
308 reArmTimer = TRUE;
309 }
310 }
311 bss = nextBss;
312 }
313
314 if(reArmTimer)
315 A_TIMEOUT_MS(&nt->nt_inact_timer, WLAN_NODE_INACT_TIMEOUT_MSEC, 0);
316
317 nt->isTimerArmed = reArmTimer;
318 }
319
320 void
321 wlan_node_table_cleanup(struct ieee80211_node_table *nt)
322 {
323 A_UNTIMEOUT(&nt->nt_inact_timer);
324 A_DELETE_TIMER(&nt->nt_inact_timer);
325 wlan_free_allnodes(nt);
326 IEEE80211_NODE_LOCK_DESTROY(nt);
327 }
328
329 bss_t *
330 wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid,
331 A_UINT32 ssidLength, A_BOOL bIsWPA2)
332 {
333 bss_t *ni = NULL;
334 A_UCHAR *pIESsid = NULL;
335
336 IEEE80211_NODE_LOCK (nt);
337
338 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
339 pIESsid = ni->ni_cie.ie_ssid;
340 if (pIESsid[1] <= 32) {
341
342 // Step 1 : Check SSID
343 if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
344
345 // Step 2 : if SSID matches, check WPA or WPA2
346 if (TRUE == bIsWPA2 && NULL != ni->ni_cie.ie_rsn) {
347 ieee80211_node_incref (ni); /* mark referenced */
348 IEEE80211_NODE_UNLOCK (nt);
349 return ni;
350 }
351 if (FALSE == bIsWPA2 && NULL != ni->ni_cie.ie_wpa) {
352 ieee80211_node_incref(ni); /* mark referenced */
353 IEEE80211_NODE_UNLOCK (nt);
354 return ni;
355 }
356 }
357 }
358 }
359
360 IEEE80211_NODE_UNLOCK (nt);
361
362 return NULL;
363 }
364
365 void
366 wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni)
367 {
368 IEEE80211_NODE_LOCK (nt);
369 wlan_node_dec_free (ni);
370 IEEE80211_NODE_UNLOCK (nt);
371 }
This page took 0.064422 seconds and 5 git commands to generate.