Index: chromeos/drivers/ath6kl/wlan/src/wlan_node.c |
diff --git a/chromeos/drivers/ath6kl/wlan/src/wlan_node.c b/chromeos/drivers/ath6kl/wlan/src/wlan_node.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1a8c4744c9079dac51c26fc89ddffcb421c625ea |
--- /dev/null |
+++ b/chromeos/drivers/ath6kl/wlan/src/wlan_node.c |
@@ -0,0 +1,486 @@ |
+//------------------------------------------------------------------------------ |
+// <copyright file="wlan_node.c" company="Atheros"> |
+// Copyright (c) 2004-2008 Atheros Corporation. All rights reserved. |
+// |
+// This program is free software; you can redistribute it and/or modify |
+// it under the terms of the GNU General Public License version 2 as |
+// published by the Free Software Foundation; |
+// |
+// Software distributed under the License is distributed on an "AS |
+// IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or |
+// implied. See the License for the specific language governing |
+// rights and limitations under the License. |
+// |
+// |
+//------------------------------------------------------------------------------ |
+//============================================================================== |
+// IEEE 802.11 node handling support. |
+// |
+// Author(s): ="Atheros" |
+//============================================================================== |
+#include <a_config.h> |
+#include <athdefs.h> |
+#include <a_types.h> |
+#include <a_osapi.h> |
+#define ATH_MODULE_NAME wlan |
+#include <a_debug.h> |
+#include "htc.h" |
+#include "htc_api.h" |
+#include <wmi.h> |
+#include <ieee80211.h> |
+#include <wlan_api.h> |
+#include <wmi_api.h> |
+#include <ieee80211_node.h> |
+ |
+#define ATH_DEBUG_WLAN ATH_DEBUG_MAKE_MODULE_MASK(0) |
+ |
+#ifdef DEBUG |
+ |
+static ATH_DEBUG_MASK_DESCRIPTION wlan_debug_desc[] = { |
+ { ATH_DEBUG_WLAN , "General WLAN Node Tracing"}, |
+}; |
+ |
+ATH_DEBUG_INSTANTIATE_MODULE_VAR(wlan, |
+ "wlan", |
+ "WLAN Node Management", |
+ ATH_DEBUG_MASK_DEFAULTS, |
+ ATH_DEBUG_DESCRIPTION_COUNT(wlan_debug_desc), |
+ wlan_debug_desc); |
+ |
+#endif |
+ |
+static void wlan_node_timeout(A_ATH_TIMER arg); |
+ |
+static bss_t * _ieee80211_find_node (struct ieee80211_node_table *nt, |
+ const A_UINT8 *macaddr); |
+ |
+bss_t * |
+wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size) |
+{ |
+ bss_t *ni; |
+ |
+ ni = A_MALLOC_NOWAIT(sizeof(bss_t)); |
+ |
+ if (ni != NULL) { |
+ if (wh_size) |
+ { |
+ ni->ni_buf = A_MALLOC_NOWAIT(wh_size); |
+ if (ni->ni_buf == NULL) { |
+ A_FREE(ni); |
+ ni = NULL; |
+ return ni; |
+ } |
+ } |
+ } else { |
+ return ni; |
+ } |
+ |
+ /* Make sure our lists are clean */ |
+ ni->ni_list_next = NULL; |
+ ni->ni_list_prev = NULL; |
+ ni->ni_hash_next = NULL; |
+ ni->ni_hash_prev = NULL; |
+ |
+ // |
+ // ni_scangen never initialized before and during suspend/resume of winmobile, |
+ // that some junk has been stored in this, due to this scan list didn't properly updated |
+ // |
+ ni->ni_scangen = 0; |
+ |
+#ifdef OS_ROAM_MANAGEMENT |
+ ni->ni_si_gen = 0; |
+#endif |
+ |
+ return ni; |
+} |
+ |
+void |
+wlan_node_free(bss_t *ni) |
+{ |
+ if (ni->ni_buf != NULL) { |
+ A_FREE(ni->ni_buf); |
+ } |
+ A_FREE(ni); |
+} |
+ |
+void |
+wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni, |
+ const A_UINT8 *macaddr) |
+{ |
+ int hash; |
+ A_UINT32 timeoutValue = 0; |
+ |
+ A_MEMCPY(ni->ni_macaddr, macaddr, IEEE80211_ADDR_LEN); |
+ hash = IEEE80211_NODE_HASH (macaddr); |
+ ieee80211_node_initref (ni); /* mark referenced */ |
+ |
+ timeoutValue = nt->nt_nodeAge; |
+ |
+ ni->ni_tstamp = A_GET_MS (timeoutValue); |
+ |
+ IEEE80211_NODE_LOCK_BH(nt); |
+ |
+ /* Insert at the end of the node list */ |
+ ni->ni_list_next = NULL; |
+ ni->ni_list_prev = nt->nt_node_last; |
+ if(nt->nt_node_last != NULL) |
+ { |
+ nt->nt_node_last->ni_list_next = ni; |
+ } |
+ nt->nt_node_last = ni; |
+ if(nt->nt_node_first == NULL) |
+ { |
+ nt->nt_node_first = ni; |
+ } |
+ |
+ /* Insert into the hash list i.e. the bucket */ |
+ if((ni->ni_hash_next = nt->nt_hash[hash]) != NULL) |
+ { |
+ nt->nt_hash[hash]->ni_hash_prev = ni; |
+ } |
+ ni->ni_hash_prev = NULL; |
+ nt->nt_hash[hash] = ni; |
+ |
+ if (!nt->isTimerArmed) { |
+ A_TIMEOUT_MS(&nt->nt_inact_timer, timeoutValue, 0); |
+ nt->isTimerArmed = TRUE; |
+ } |
+ |
+ IEEE80211_NODE_UNLOCK_BH(nt); |
+} |
+ |
+static bss_t * |
+_ieee80211_find_node(struct ieee80211_node_table *nt, |
+ const A_UINT8 *macaddr) |
+{ |
+ bss_t *ni; |
+ int hash; |
+ |
+ IEEE80211_NODE_LOCK_ASSERT(nt); |
+ |
+ hash = IEEE80211_NODE_HASH(macaddr); |
+ for(ni = nt->nt_hash[hash]; ni; ni = ni->ni_hash_next) { |
+ if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { |
+ ieee80211_node_incref(ni); /* mark referenced */ |
+ return ni; |
+ } |
+ } |
+ return NULL; |
+} |
+ |
+bss_t * |
+wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr) |
+{ |
+ bss_t *ni; |
+ |
+ IEEE80211_NODE_LOCK(nt); |
+ ni = _ieee80211_find_node(nt, macaddr); |
+ IEEE80211_NODE_UNLOCK(nt); |
+ return ni; |
+} |
+ |
+/* |
+ * Reclaim a node. If this is the last reference count then |
+ * do the normal free work. Otherwise remove it from the node |
+ * table and mark it gone by clearing the back-reference. |
+ */ |
+void |
+wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni) |
+{ |
+ IEEE80211_NODE_LOCK(nt); |
+ |
+ if(ni->ni_list_prev == NULL) |
+ { |
+ /* First in list so fix the list head */ |
+ nt->nt_node_first = ni->ni_list_next; |
+ } |
+ else |
+ { |
+ ni->ni_list_prev->ni_list_next = ni->ni_list_next; |
+ } |
+ |
+ if(ni->ni_list_next == NULL) |
+ { |
+ /* Last in list so fix list tail */ |
+ nt->nt_node_last = ni->ni_list_prev; |
+ } |
+ else |
+ { |
+ ni->ni_list_next->ni_list_prev = ni->ni_list_prev; |
+ } |
+ |
+ if(ni->ni_hash_prev == NULL) |
+ { |
+ /* First in list so fix the list head */ |
+ int hash; |
+ hash = IEEE80211_NODE_HASH(ni->ni_macaddr); |
+ nt->nt_hash[hash] = ni->ni_hash_next; |
+ } |
+ else |
+ { |
+ ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next; |
+ } |
+ |
+ if(ni->ni_hash_next != NULL) |
+ { |
+ ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev; |
+ } |
+ wlan_node_free(ni); |
+ |
+ IEEE80211_NODE_UNLOCK(nt); |
+} |
+ |
+static void |
+wlan_node_dec_free(bss_t *ni) |
+{ |
+ if (ieee80211_node_dectestref(ni)) { |
+ wlan_node_free(ni); |
+ } |
+} |
+ |
+void |
+wlan_free_allnodes(struct ieee80211_node_table *nt) |
+{ |
+ bss_t *ni; |
+ |
+ while ((ni = nt->nt_node_first) != NULL) { |
+ wlan_node_reclaim(nt, ni); |
+ } |
+} |
+ |
+void |
+wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f, |
+ void *arg) |
+{ |
+ bss_t *ni; |
+ A_UINT32 gen; |
+ |
+ gen = ++nt->nt_scangen; |
+ |
+ IEEE80211_NODE_LOCK(nt); |
+ for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { |
+ if (ni->ni_scangen != gen) { |
+ ni->ni_scangen = gen; |
+ (void) ieee80211_node_incref(ni); |
+ (*f)(arg, ni); |
+ wlan_node_dec_free(ni); |
+ } |
+ } |
+ IEEE80211_NODE_UNLOCK(nt); |
+} |
+ |
+/* |
+ * Node table support. |
+ */ |
+void |
+wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt) |
+{ |
+ int i; |
+ |
+ AR_DEBUG_PRINTF(ATH_DEBUG_WLAN, ("node table = 0x%x\n", (A_UINT32)nt)); |
+ IEEE80211_NODE_LOCK_INIT(nt); |
+ |
+ A_REGISTER_MODULE_DEBUG_INFO(wlan); |
+ |
+ nt->nt_node_first = nt->nt_node_last = NULL; |
+ for(i = 0; i < IEEE80211_NODE_HASHSIZE; i++) |
+ { |
+ nt->nt_hash[i] = NULL; |
+ } |
+ |
+ A_INIT_TIMER(&nt->nt_inact_timer, wlan_node_timeout, nt); |
+ nt->isTimerArmed = FALSE; |
+ nt->nt_wmip = wmip; |
+ nt->nt_nodeAge = WLAN_NODE_INACT_TIMEOUT_MSEC; |
+ |
+ // |
+ // nt_scangen never initialized before and during suspend/resume of winmobile, |
+ // that some junk has been stored in this, due to this scan list didn't properly updated |
+ // |
+ nt->nt_scangen = 0; |
+ |
+#ifdef OS_ROAM_MANAGEMENT |
+ nt->nt_si_gen = 0; |
+#endif |
+} |
+ |
+void |
+wlan_set_nodeage(struct ieee80211_node_table *nt, A_UINT32 nodeAge) |
+{ |
+ nt->nt_nodeAge = nodeAge; |
+ return; |
+} |
+static void |
+wlan_node_timeout (A_ATH_TIMER arg) |
+{ |
+ struct ieee80211_node_table *nt = (struct ieee80211_node_table *)arg; |
+ bss_t *bss, *nextBss; |
+ A_UINT8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = FALSE; |
+ A_UINT32 timeoutValue = 0; |
+ |
+ timeoutValue = nt->nt_nodeAge; |
+ |
+ wmi_get_current_bssid(nt->nt_wmip, myBssid); |
+ |
+ bss = nt->nt_node_first; |
+ while (bss != NULL) |
+ { |
+ nextBss = bss->ni_list_next; |
+ if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0) |
+ { |
+ |
+ if (bss->ni_tstamp <= A_GET_MS(0)) |
+ { |
+ /* |
+ * free up all but the current bss - if set |
+ */ |
+ wlan_node_reclaim(nt, bss); |
+ } |
+ else |
+ { |
+ /* |
+ * Re-arm timer, only when we have a bss other than |
+ * current bss AND it is not aged-out. |
+ */ |
+ reArmTimer = TRUE; |
+ } |
+ } |
+ bss = nextBss; |
+ } |
+ |
+ if (reArmTimer) |
+ A_TIMEOUT_MS (&nt->nt_inact_timer, timeoutValue, 0); |
+ |
+ nt->isTimerArmed = reArmTimer; |
+} |
+ |
+void |
+wlan_node_table_cleanup(struct ieee80211_node_table *nt) |
+{ |
+ A_UNTIMEOUT(&nt->nt_inact_timer); |
+ A_DELETE_TIMER(&nt->nt_inact_timer); |
+ wlan_free_allnodes(nt); |
+ IEEE80211_NODE_LOCK_DESTROY(nt); |
+} |
+ |
+bss_t * |
+wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid, |
+ A_UINT32 ssidLength, A_BOOL bIsWPA2, A_BOOL bMatchSSID) |
+{ |
+ bss_t *ni = NULL; |
+ A_UCHAR *pIESsid = NULL; |
+ |
+ IEEE80211_NODE_LOCK (nt); |
+ |
+ for (ni = nt->nt_node_first; ni; ni = ni->ni_list_next) { |
+ pIESsid = ni->ni_cie.ie_ssid; |
+ if (pIESsid[1] <= 32) { |
+ |
+ // Step 1 : Check SSID |
+ if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) { |
+ |
+ // |
+ // Step 2.1 : Check MatchSSID is TRUE, if so, return Matched SSID |
+ // Profile, otherwise check whether WPA2 or WPA |
+ // |
+ if (TRUE == bMatchSSID) { |
+ ieee80211_node_incref (ni); /* mark referenced */ |
+ IEEE80211_NODE_UNLOCK (nt); |
+ return ni; |
+ } |
+ |
+ // Step 2 : if SSID matches, check WPA or WPA2 |
+ if (TRUE == bIsWPA2 && NULL != ni->ni_cie.ie_rsn) { |
+ ieee80211_node_incref (ni); /* mark referenced */ |
+ IEEE80211_NODE_UNLOCK (nt); |
+ return ni; |
+ } |
+ if (FALSE == bIsWPA2 && NULL != ni->ni_cie.ie_wpa) { |
+ ieee80211_node_incref(ni); /* mark referenced */ |
+ IEEE80211_NODE_UNLOCK (nt); |
+ return ni; |
+ } |
+ } |
+ } |
+ } |
+ |
+ IEEE80211_NODE_UNLOCK (nt); |
+ |
+ return NULL; |
+} |
+ |
+void |
+wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni) |
+{ |
+ IEEE80211_NODE_LOCK (nt); |
+ wlan_node_dec_free (ni); |
+ IEEE80211_NODE_UNLOCK (nt); |
+} |
+ |
+void |
+wlan_node_remove_core (struct ieee80211_node_table *nt, bss_t *ni) |
+{ |
+ if(ni->ni_list_prev == NULL) |
+ { |
+ /* First in list so fix the list head */ |
+ nt->nt_node_first = ni->ni_list_next; |
+ } |
+ else |
+ { |
+ ni->ni_list_prev->ni_list_next = ni->ni_list_next; |
+ } |
+ |
+ if(ni->ni_list_next == NULL) |
+ { |
+ /* Last in list so fix list tail */ |
+ nt->nt_node_last = ni->ni_list_prev; |
+ } |
+ else |
+ { |
+ ni->ni_list_next->ni_list_prev = ni->ni_list_prev; |
+ } |
+ |
+ if(ni->ni_hash_prev == NULL) |
+ { |
+ /* First in list so fix the list head */ |
+ int hash; |
+ hash = IEEE80211_NODE_HASH(ni->ni_macaddr); |
+ nt->nt_hash[hash] = ni->ni_hash_next; |
+ } |
+ else |
+ { |
+ ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next; |
+ } |
+ |
+ if(ni->ni_hash_next != NULL) |
+ { |
+ ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev; |
+ } |
+} |
+ |
+bss_t * |
+wlan_node_remove(struct ieee80211_node_table *nt, A_UINT8 *bssid) |
+{ |
+ bss_t *bss, *nextBss; |
+ |
+ IEEE80211_NODE_LOCK(nt); |
+ |
+ bss = nt->nt_node_first; |
+ |
+ while (bss != NULL) |
+ { |
+ nextBss = bss->ni_list_next; |
+ |
+ if (A_MEMCMP(bssid, bss->ni_macaddr, 6) == 0) |
+ { |
+ wlan_node_remove_core (nt, bss); |
+ IEEE80211_NODE_UNLOCK(nt); |
+ return bss; |
+ } |
+ |
+ bss = nextBss; |
+ } |
+ |
+ IEEE80211_NODE_UNLOCK(nt); |
+ return NULL; |
+} |