1 //------------------------------------------------------------------------------
2 // <copyright file="wlan_node.c" company="Atheros">
3 // Copyright (c) 2004-2010 Atheros Corporation. All rights reserved.
6 // Permission to use, copy, modify, and/or distribute this software for any
7 // purpose with or without fee is hereby granted, provided that the above
8 // copyright notice and this permission notice appear in all copies.
10 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 //------------------------------------------------------------------------------
20 //==============================================================================
21 // IEEE 802.11 node handling support.
23 // Author(s): ="Atheros"
24 //==============================================================================
29 #define ATH_MODULE_NAME wlan
34 #include <ieee80211.h>
37 #include <ieee80211_node.h>
39 #define ATH_DEBUG_WLAN ATH_DEBUG_MAKE_MODULE_MASK(0)
41 #ifdef ATH_DEBUG_MODULE
43 static ATH_DEBUG_MASK_DESCRIPTION wlan_debug_desc[] = {
44 { ATH_DEBUG_WLAN , "General WLAN Node Tracing"},
47 ATH_DEBUG_INSTANTIATE_MODULE_VAR(wlan,
49 "WLAN Node Management",
50 ATH_DEBUG_MASK_DEFAULTS,
51 ATH_DEBUG_DESCRIPTION_COUNT(wlan_debug_desc),
57 static void wlan_node_timeout(A_ATH_TIMER arg);
60 static bss_t * _ieee80211_find_node (struct ieee80211_node_table *nt,
61 const A_UINT8 *macaddr);
64 wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size)
68 ni = A_MALLOC_NOWAIT(sizeof(bss_t));
73 ni->ni_buf = A_MALLOC_NOWAIT(wh_size);
74 if (ni->ni_buf == NULL) {
84 /* Make sure our lists are clean */
85 ni->ni_list_next = NULL;
86 ni->ni_list_prev = NULL;
87 ni->ni_hash_next = NULL;
88 ni->ni_hash_prev = NULL;
91 // ni_scangen never initialized before and during suspend/resume of winmobile,
92 // that some junk has been stored in this, due to this scan list didn't properly updated
96 #ifdef OS_ROAM_MANAGEMENT
104 wlan_node_free(bss_t *ni)
106 if (ni->ni_buf != NULL) {
113 wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
114 const A_UINT8 *macaddr)
117 A_UINT32 timeoutValue = 0;
119 A_MEMCPY(ni->ni_macaddr, macaddr, IEEE80211_ADDR_LEN);
120 hash = IEEE80211_NODE_HASH (macaddr);
121 ieee80211_node_initref (ni); /* mark referenced */
123 timeoutValue = nt->nt_nodeAge;
125 ni->ni_tstamp = A_GET_MS (timeoutValue);
126 ni->ni_actcnt = WLAN_NODE_INACT_CNT;
128 IEEE80211_NODE_LOCK_BH(nt);
130 /* Insert at the end of the node list */
131 ni->ni_list_next = NULL;
132 ni->ni_list_prev = nt->nt_node_last;
133 if(nt->nt_node_last != NULL)
135 nt->nt_node_last->ni_list_next = ni;
137 nt->nt_node_last = ni;
138 if(nt->nt_node_first == NULL)
140 nt->nt_node_first = ni;
143 /* Insert into the hash list i.e. the bucket */
144 if((ni->ni_hash_next = nt->nt_hash[hash]) != NULL)
146 nt->nt_hash[hash]->ni_hash_prev = ni;
148 ni->ni_hash_prev = NULL;
149 nt->nt_hash[hash] = ni;
152 if (!nt->isTimerArmed) {
153 A_TIMEOUT_MS(&nt->nt_inact_timer, timeoutValue, 0);
154 nt->isTimerArmed = true;
158 IEEE80211_NODE_UNLOCK_BH(nt);
162 _ieee80211_find_node(struct ieee80211_node_table *nt,
163 const A_UINT8 *macaddr)
168 IEEE80211_NODE_LOCK_ASSERT(nt);
170 hash = IEEE80211_NODE_HASH(macaddr);
171 for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) {
172 if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
173 ieee80211_node_incref(ni); /* mark referenced */
181 wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr)
185 IEEE80211_NODE_LOCK(nt);
186 ni = _ieee80211_find_node(nt, macaddr);
187 IEEE80211_NODE_UNLOCK(nt);
192 * Reclaim a node. If this is the last reference count then
193 * do the normal free work. Otherwise remove it from the node
194 * table and mark it gone by clearing the back-reference.
197 wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni)
199 IEEE80211_NODE_LOCK(nt);
201 if(ni->ni_list_prev == NULL)
203 /* First in list so fix the list head */
204 nt->nt_node_first = ni->ni_list_next;
208 ni->ni_list_prev->ni_list_next = ni->ni_list_next;
211 if(ni->ni_list_next == NULL)
213 /* Last in list so fix list tail */
214 nt->nt_node_last = ni->ni_list_prev;
218 ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
221 if(ni->ni_hash_prev == NULL)
223 /* First in list so fix the list head */
225 hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
226 nt->nt_hash[hash] = ni->ni_hash_next;
230 ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
233 if(ni->ni_hash_next != NULL)
235 ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
239 IEEE80211_NODE_UNLOCK(nt);
243 wlan_node_dec_free(bss_t *ni)
245 if (ieee80211_node_dectestref(ni)) {
251 wlan_free_allnodes(struct ieee80211_node_table *nt)
255 while ((ni = nt->nt_node_first) != NULL) {
256 wlan_node_reclaim(nt, ni);
261 wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
267 gen = ++nt->nt_scangen;
269 IEEE80211_NODE_LOCK(nt);
270 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
271 if (ni->ni_scangen != gen) {
272 ni->ni_scangen = gen;
273 (void) ieee80211_node_incref(ni);
275 wlan_node_dec_free(ni);
278 IEEE80211_NODE_UNLOCK(nt);
282 * Node table support.
285 wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt)
289 AR_DEBUG_PRINTF(ATH_DEBUG_WLAN, ("node table = 0x%lx\n", (unsigned long)nt));
290 IEEE80211_NODE_LOCK_INIT(nt);
292 A_REGISTER_MODULE_DEBUG_INFO(wlan);
294 nt->nt_node_first = nt->nt_node_last = NULL;
295 for(i = 0; i < IEEE80211_NODE_HASHSIZE; i++)
297 nt->nt_hash[i] = NULL;
301 A_INIT_TIMER(&nt->nt_inact_timer, wlan_node_timeout, nt);
302 nt->isTimerArmed = false;
305 nt->nt_nodeAge = WLAN_NODE_INACT_TIMEOUT_MSEC;
308 // nt_scangen never initialized before and during suspend/resume of winmobile,
309 // that some junk has been stored in this, due to this scan list didn't properly updated
313 #ifdef OS_ROAM_MANAGEMENT
319 wlan_set_nodeage(struct ieee80211_node_table *nt, A_UINT32 nodeAge)
321 nt->nt_nodeAge = nodeAge;
325 wlan_refresh_inactive_nodes (struct ieee80211_node_table *nt)
328 bss_t *bss, *nextBss;
329 A_UINT8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = false;
331 wmi_get_current_bssid(nt->nt_wmip, myBssid);
333 bss = nt->nt_node_first;
336 nextBss = bss->ni_list_next;
337 if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
340 * free up all but the current bss - if set
342 wlan_node_reclaim(nt, bss);
348 bss_t *bss, *nextBss;
349 A_UINT8 myBssid[IEEE80211_ADDR_LEN];
350 A_UINT32 timeoutValue = 0;
351 A_UINT32 now = A_GET_MS(0);
352 timeoutValue = nt->nt_nodeAge;
354 wmi_get_current_bssid(nt->nt_wmip, myBssid);
356 bss = nt->nt_node_first;
359 nextBss = bss->ni_list_next;
360 if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
363 if (bss->ni_tstamp <= now || --bss->ni_actcnt == 0)
366 * free up all but the current bss - if set
368 wlan_node_reclaim(nt, bss);
378 wlan_node_timeout (A_ATH_TIMER arg)
380 struct ieee80211_node_table *nt = (struct ieee80211_node_table *)arg;
381 bss_t *bss, *nextBss;
382 A_UINT8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = false;
383 A_UINT32 timeoutValue = 0;
385 timeoutValue = nt->nt_nodeAge;
387 wmi_get_current_bssid(nt->nt_wmip, myBssid);
389 bss = nt->nt_node_first;
392 nextBss = bss->ni_list_next;
393 if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
396 if (bss->ni_tstamp <= A_GET_MS(0))
399 * free up all but the current bss - if set
401 wlan_node_reclaim(nt, bss);
406 * Re-arm timer, only when we have a bss other than
407 * current bss AND it is not aged-out.
416 A_TIMEOUT_MS (&nt->nt_inact_timer, timeoutValue, 0);
418 nt->isTimerArmed = reArmTimer;
423 wlan_node_table_cleanup(struct ieee80211_node_table *nt)
426 A_UNTIMEOUT(&nt->nt_inact_timer);
427 A_DELETE_TIMER(&nt->nt_inact_timer);
429 wlan_free_allnodes(nt);
430 IEEE80211_NODE_LOCK_DESTROY(nt);
434 wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid,
435 A_UINT32 ssidLength, bool bIsWPA2, bool bMatchSSID)
438 A_UCHAR *pIESsid = NULL;
440 IEEE80211_NODE_LOCK (nt);
442 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
443 pIESsid = ni->ni_cie.ie_ssid;
444 if (pIESsid[1] <= 32) {
446 // Step 1 : Check SSID
447 if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
450 // Step 2.1 : Check MatchSSID is true, if so, return Matched SSID
451 // Profile, otherwise check whether WPA2 or WPA
453 if (true == bMatchSSID) {
454 ieee80211_node_incref (ni); /* mark referenced */
455 IEEE80211_NODE_UNLOCK (nt);
459 // Step 2 : if SSID matches, check WPA or WPA2
460 if (true == bIsWPA2 && NULL != ni->ni_cie.ie_rsn) {
461 ieee80211_node_incref (ni); /* mark referenced */
462 IEEE80211_NODE_UNLOCK (nt);
465 if (false == bIsWPA2 && NULL != ni->ni_cie.ie_wpa) {
466 ieee80211_node_incref(ni); /* mark referenced */
467 IEEE80211_NODE_UNLOCK (nt);
474 IEEE80211_NODE_UNLOCK (nt);
480 wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni)
482 IEEE80211_NODE_LOCK (nt);
483 wlan_node_dec_free (ni);
484 IEEE80211_NODE_UNLOCK (nt);
488 wlan_node_remove_core (struct ieee80211_node_table *nt, bss_t *ni)
490 if(ni->ni_list_prev == NULL)
492 /* First in list so fix the list head */
493 nt->nt_node_first = ni->ni_list_next;
497 ni->ni_list_prev->ni_list_next = ni->ni_list_next;
500 if(ni->ni_list_next == NULL)
502 /* Last in list so fix list tail */
503 nt->nt_node_last = ni->ni_list_prev;
507 ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
510 if(ni->ni_hash_prev == NULL)
512 /* First in list so fix the list head */
514 hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
515 nt->nt_hash[hash] = ni->ni_hash_next;
519 ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
522 if(ni->ni_hash_next != NULL)
524 ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
529 wlan_node_remove(struct ieee80211_node_table *nt, A_UINT8 *bssid)
531 bss_t *bss, *nextBss;
533 IEEE80211_NODE_LOCK(nt);
535 bss = nt->nt_node_first;
539 nextBss = bss->ni_list_next;
541 if (A_MEMCMP(bssid, bss->ni_macaddr, 6) == 0)
543 wlan_node_remove_core (nt, bss);
544 IEEE80211_NODE_UNLOCK(nt);
551 IEEE80211_NODE_UNLOCK(nt);
556 wlan_find_matching_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid,
557 A_UINT32 ssidLength, A_UINT32 dot11AuthMode, A_UINT32 authMode,
558 A_UINT32 pairwiseCryptoType, A_UINT32 grpwiseCryptoTyp)
561 bss_t *best_ni = NULL;
562 A_UCHAR *pIESsid = NULL;
564 IEEE80211_NODE_LOCK (nt);
566 for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) {
567 pIESsid = ni->ni_cie.ie_ssid;
568 if (pIESsid[1] <= 32) {
570 // Step 1 : Check SSID
571 if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
573 if (ni->ni_cie.ie_capInfo & 0x10)
576 if ((NULL != ni->ni_cie.ie_rsn) && (WPA2_PSK_AUTH == authMode))
583 else if (ni->ni_rssi > best_ni->ni_rssi)
588 else if ((NULL != ni->ni_cie.ie_wpa) && (WPA_PSK_AUTH == authMode))
595 else if (ni->ni_rssi > best_ni->ni_rssi)
600 else if (WEP_CRYPT == pairwiseCryptoType)
607 else if (ni->ni_rssi > best_ni->ni_rssi)
616 if ((OPEN_AUTH == authMode) && (NONE_CRYPT == pairwiseCryptoType))
622 else if (ni->ni_rssi > best_ni->ni_rssi)
632 IEEE80211_NODE_UNLOCK (nt);