| 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;
|
| +}
|
|
|