linux/drivers/staging/ath6kl/wlan/src/wlan_node.c
<<
>>
Prefs
   1//------------------------------------------------------------------------------
   2// <copyright file="wlan_node.c" company="Atheros">
   3//    Copyright (c) 2004-2010 Atheros Corporation.  All rights reserved.
   4// 
   5//
   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.
   9//
  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.
  17//
  18//
  19//------------------------------------------------------------------------------
  20//==============================================================================
  21// IEEE 802.11 node handling support.
  22//
  23// Author(s): ="Atheros"
  24//==============================================================================
  25#include <a_config.h>
  26#include <athdefs.h>
  27#include <a_types.h>
  28#include <a_osapi.h>
  29#define ATH_MODULE_NAME wlan
  30#include <a_debug.h>
  31#include "htc.h"
  32#include "htc_api.h"
  33#include <wmi.h>
  34#include <ieee80211.h>
  35#include <wlan_api.h>
  36#include <wmi_api.h>
  37#include <ieee80211_node.h>
  38
  39#define ATH_DEBUG_WLAN ATH_DEBUG_MAKE_MODULE_MASK(0)
  40
  41#ifdef ATH_DEBUG_MODULE
  42
  43static ATH_DEBUG_MASK_DESCRIPTION wlan_debug_desc[] = {
  44    { ATH_DEBUG_WLAN , "General WLAN Node Tracing"},
  45};
  46
  47ATH_DEBUG_INSTANTIATE_MODULE_VAR(wlan,
  48                                 "wlan",
  49                                 "WLAN Node Management",
  50                                 ATH_DEBUG_MASK_DEFAULTS,
  51                                 ATH_DEBUG_DESCRIPTION_COUNT(wlan_debug_desc),
  52                                 wlan_debug_desc);
  53                                 
  54#endif
  55
  56#ifdef THREAD_X
  57static void wlan_node_timeout(A_ATH_TIMER arg);
  58#endif
  59
  60static bss_t * _ieee80211_find_node (struct ieee80211_node_table *nt,
  61                                     const A_UINT8 *macaddr);
  62
  63bss_t *
  64wlan_node_alloc(struct ieee80211_node_table *nt, int wh_size)
  65{
  66    bss_t *ni;
  67
  68    ni = A_MALLOC_NOWAIT(sizeof(bss_t));
  69
  70    if (ni != NULL) {
  71        if (wh_size)
  72        {
  73        ni->ni_buf = A_MALLOC_NOWAIT(wh_size);
  74        if (ni->ni_buf == NULL) {
  75            A_FREE(ni);
  76            ni = NULL;
  77            return ni;
  78        }
  79        }
  80    } else {
  81        return ni;
  82    }
  83
  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;
  89
  90    //
  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
  93    //
  94    ni->ni_scangen   = 0;
  95
  96#ifdef OS_ROAM_MANAGEMENT
  97    ni->ni_si_gen    = 0;
  98#endif
  99
 100    return ni;
 101}
 102
 103void
 104wlan_node_free(bss_t *ni)
 105{
 106    if (ni->ni_buf != NULL) {
 107        A_FREE(ni->ni_buf);
 108    }
 109    A_FREE(ni);
 110}
 111
 112void
 113wlan_setup_node(struct ieee80211_node_table *nt, bss_t *ni,
 114                const A_UINT8 *macaddr)
 115{
 116    int hash;
 117    A_UINT32 timeoutValue = 0;
 118
 119    A_MEMCPY(ni->ni_macaddr, macaddr, IEEE80211_ADDR_LEN);
 120    hash = IEEE80211_NODE_HASH (macaddr);
 121    ieee80211_node_initref (ni);     /* mark referenced */
 122
 123    timeoutValue = nt->nt_nodeAge;
 124
 125    ni->ni_tstamp = A_GET_MS (timeoutValue);
 126    ni->ni_actcnt = WLAN_NODE_INACT_CNT;
 127
 128    IEEE80211_NODE_LOCK_BH(nt);
 129
 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)
 134    {
 135        nt->nt_node_last->ni_list_next = ni;
 136    }
 137    nt->nt_node_last = ni;
 138    if(nt->nt_node_first == NULL)
 139    {
 140        nt->nt_node_first = ni;
 141    }
 142
 143    /* Insert into the hash list i.e. the bucket */
 144    if((ni->ni_hash_next = nt->nt_hash[hash]) != NULL)
 145    {
 146        nt->nt_hash[hash]->ni_hash_prev = ni;
 147    }
 148    ni->ni_hash_prev = NULL;
 149    nt->nt_hash[hash] = ni;
 150
 151#ifdef THREAD_X
 152    if (!nt->isTimerArmed) {
 153        A_TIMEOUT_MS(&nt->nt_inact_timer, timeoutValue, 0);
 154        nt->isTimerArmed = TRUE;
 155    }
 156#endif
 157
 158    IEEE80211_NODE_UNLOCK_BH(nt);
 159}
 160
 161static bss_t *
 162_ieee80211_find_node(struct ieee80211_node_table *nt,
 163    const A_UINT8 *macaddr)
 164{
 165    bss_t *ni;
 166    int hash;
 167
 168    IEEE80211_NODE_LOCK_ASSERT(nt);
 169
 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 */
 174            return ni;
 175        }
 176    }
 177    return NULL;
 178}
 179
 180bss_t *
 181wlan_find_node(struct ieee80211_node_table *nt, const A_UINT8 *macaddr)
 182{
 183    bss_t *ni;
 184
 185    IEEE80211_NODE_LOCK(nt);
 186    ni = _ieee80211_find_node(nt, macaddr);
 187    IEEE80211_NODE_UNLOCK(nt);
 188    return ni;
 189}
 190
 191/*
 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.
 195 */
 196void
 197wlan_node_reclaim(struct ieee80211_node_table *nt, bss_t *ni)
 198{
 199    IEEE80211_NODE_LOCK(nt);
 200
 201    if(ni->ni_list_prev == NULL)
 202    {
 203        /* First in list so fix the list head */
 204        nt->nt_node_first = ni->ni_list_next;
 205    }
 206    else
 207    {
 208        ni->ni_list_prev->ni_list_next = ni->ni_list_next;
 209    }
 210
 211    if(ni->ni_list_next == NULL)
 212    {
 213        /* Last in list so fix list tail */
 214        nt->nt_node_last = ni->ni_list_prev;
 215    }
 216    else
 217    {
 218        ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
 219    }
 220
 221    if(ni->ni_hash_prev == NULL)
 222    {
 223        /* First in list so fix the list head */
 224        int hash;
 225        hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
 226        nt->nt_hash[hash] = ni->ni_hash_next;
 227    }
 228    else
 229    {
 230        ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
 231    }
 232
 233    if(ni->ni_hash_next != NULL)
 234    {
 235        ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
 236    }
 237    wlan_node_free(ni);
 238
 239    IEEE80211_NODE_UNLOCK(nt);
 240}
 241
 242static void
 243wlan_node_dec_free(bss_t *ni)
 244{
 245    if (ieee80211_node_dectestref(ni)) {
 246        wlan_node_free(ni);
 247    }
 248}
 249
 250void
 251wlan_free_allnodes(struct ieee80211_node_table *nt)
 252{
 253    bss_t *ni;
 254
 255    while ((ni = nt->nt_node_first) != NULL) {
 256        wlan_node_reclaim(nt, ni);
 257    }
 258}
 259
 260void
 261wlan_iterate_nodes(struct ieee80211_node_table *nt, wlan_node_iter_func *f,
 262                   void *arg)
 263{
 264    bss_t *ni;
 265    A_UINT32 gen;
 266
 267    gen = ++nt->nt_scangen;
 268
 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);
 274            (*f)(arg, ni);
 275            wlan_node_dec_free(ni);
 276        }
 277    }
 278    IEEE80211_NODE_UNLOCK(nt);
 279}
 280
 281/*
 282 * Node table support.
 283 */
 284void
 285wlan_node_table_init(void *wmip, struct ieee80211_node_table *nt)
 286{
 287    int i;
 288
 289    AR_DEBUG_PRINTF(ATH_DEBUG_WLAN, ("node table = 0x%lx\n", (unsigned long)nt));
 290    IEEE80211_NODE_LOCK_INIT(nt);
 291
 292    A_REGISTER_MODULE_DEBUG_INFO(wlan);
 293    
 294    nt->nt_node_first = nt->nt_node_last = NULL;
 295    for(i = 0; i < IEEE80211_NODE_HASHSIZE; i++)
 296    {
 297        nt->nt_hash[i] = NULL;
 298    }
 299
 300#ifdef THREAD_X
 301    A_INIT_TIMER(&nt->nt_inact_timer, wlan_node_timeout, nt);
 302    nt->isTimerArmed = FALSE;
 303#endif
 304    nt->nt_wmip = wmip;
 305    nt->nt_nodeAge = WLAN_NODE_INACT_TIMEOUT_MSEC;
 306
 307    //
 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
 310    //
 311    nt->nt_scangen   = 0;
 312
 313#ifdef OS_ROAM_MANAGEMENT
 314    nt->nt_si_gen    = 0;
 315#endif
 316}
 317
 318void
 319wlan_set_nodeage(struct ieee80211_node_table *nt, A_UINT32 nodeAge)
 320{
 321    nt->nt_nodeAge = nodeAge;
 322    return;
 323}
 324void
 325wlan_refresh_inactive_nodes (struct ieee80211_node_table *nt)
 326{
 327#ifdef THREAD_X
 328    bss_t *bss, *nextBss;
 329    A_UINT8 myBssid[IEEE80211_ADDR_LEN], reArmTimer = FALSE;
 330
 331    wmi_get_current_bssid(nt->nt_wmip, myBssid);
 332
 333    bss = nt->nt_node_first;
 334    while (bss != NULL)
 335    {
 336        nextBss = bss->ni_list_next;
 337        if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
 338        {
 339               /*
 340                * free up all but the current bss - if set
 341                */
 342                wlan_node_reclaim(nt, bss);
 343
 344        }
 345        bss = nextBss;
 346    }
 347#else
 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;
 353
 354    wmi_get_current_bssid(nt->nt_wmip, myBssid);
 355
 356    bss = nt->nt_node_first;
 357    while (bss != NULL)
 358    {
 359        nextBss = bss->ni_list_next;
 360        if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
 361        {
 362
 363            if (bss->ni_tstamp <= now || --bss->ni_actcnt == 0)
 364            {
 365               /*
 366                * free up all but the current bss - if set
 367                */
 368                wlan_node_reclaim(nt, bss);
 369            }
 370        }
 371        bss = nextBss;
 372    }
 373#endif
 374}
 375
 376#ifdef THREAD_X
 377static void
 378wlan_node_timeout (A_ATH_TIMER arg)
 379{
 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;
 384
 385    timeoutValue = nt->nt_nodeAge;
 386
 387    wmi_get_current_bssid(nt->nt_wmip, myBssid);
 388
 389    bss = nt->nt_node_first;
 390    while (bss != NULL)
 391    {
 392        nextBss = bss->ni_list_next;
 393        if (A_MEMCMP(myBssid, bss->ni_macaddr, sizeof(myBssid)) != 0)
 394        {
 395
 396            if (bss->ni_tstamp <= A_GET_MS(0))
 397            {
 398               /*
 399                * free up all but the current bss - if set
 400                */
 401                wlan_node_reclaim(nt, bss);
 402            }
 403            else
 404            {
 405                /*
 406                 * Re-arm timer, only when we have a bss other than
 407                 * current bss AND it is not aged-out.
 408                 */
 409                reArmTimer = TRUE;
 410            }
 411        }
 412        bss = nextBss;
 413    }
 414
 415    if (reArmTimer)
 416        A_TIMEOUT_MS (&nt->nt_inact_timer, timeoutValue, 0);
 417
 418    nt->isTimerArmed = reArmTimer;
 419}
 420#endif
 421
 422void
 423wlan_node_table_cleanup(struct ieee80211_node_table *nt)
 424{
 425#ifdef THREAD_X
 426    A_UNTIMEOUT(&nt->nt_inact_timer);
 427    A_DELETE_TIMER(&nt->nt_inact_timer);
 428#endif
 429    wlan_free_allnodes(nt);
 430    IEEE80211_NODE_LOCK_DESTROY(nt);
 431}
 432
 433bss_t *
 434wlan_find_Ssidnode (struct ieee80211_node_table *nt, A_UCHAR *pSsid,
 435                    A_UINT32 ssidLength, A_BOOL bIsWPA2, A_BOOL bMatchSSID)
 436{
 437    bss_t   *ni = NULL;
 438    A_UCHAR *pIESsid = NULL;
 439
 440    IEEE80211_NODE_LOCK (nt);
 441
 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) {
 445
 446            // Step 1 : Check SSID
 447            if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
 448
 449                //
 450                // Step 2.1 : Check MatchSSID is TRUE, if so, return Matched SSID
 451                // Profile, otherwise check whether WPA2 or WPA
 452                //
 453                if (TRUE == bMatchSSID) {
 454                    ieee80211_node_incref (ni);  /* mark referenced */
 455                    IEEE80211_NODE_UNLOCK (nt);
 456                    return ni;
 457                }
 458
 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);
 463                    return ni;
 464                }
 465                if (FALSE == bIsWPA2 && NULL != ni->ni_cie.ie_wpa) {
 466                    ieee80211_node_incref(ni);  /* mark referenced */
 467                    IEEE80211_NODE_UNLOCK (nt);
 468                    return ni;
 469                }
 470            }
 471        }
 472    }
 473
 474    IEEE80211_NODE_UNLOCK (nt);
 475
 476    return NULL;
 477}
 478
 479void
 480wlan_node_return (struct ieee80211_node_table *nt, bss_t *ni)
 481{
 482    IEEE80211_NODE_LOCK (nt);
 483    wlan_node_dec_free (ni);
 484    IEEE80211_NODE_UNLOCK (nt);
 485}
 486
 487void
 488wlan_node_remove_core (struct ieee80211_node_table *nt, bss_t *ni)
 489{
 490    if(ni->ni_list_prev == NULL)
 491    {
 492        /* First in list so fix the list head */
 493        nt->nt_node_first = ni->ni_list_next;
 494    }
 495    else
 496    {
 497        ni->ni_list_prev->ni_list_next = ni->ni_list_next;
 498    }
 499
 500    if(ni->ni_list_next == NULL)
 501    {
 502        /* Last in list so fix list tail */
 503        nt->nt_node_last = ni->ni_list_prev;
 504    }
 505    else
 506    {
 507        ni->ni_list_next->ni_list_prev = ni->ni_list_prev;
 508    }
 509
 510    if(ni->ni_hash_prev == NULL)
 511    {
 512        /* First in list so fix the list head */
 513        int hash;
 514        hash = IEEE80211_NODE_HASH(ni->ni_macaddr);
 515        nt->nt_hash[hash] = ni->ni_hash_next;
 516    }
 517    else
 518    {
 519        ni->ni_hash_prev->ni_hash_next = ni->ni_hash_next;
 520    }
 521
 522    if(ni->ni_hash_next != NULL)
 523    {
 524        ni->ni_hash_next->ni_hash_prev = ni->ni_hash_prev;
 525    }
 526}
 527
 528bss_t *
 529wlan_node_remove(struct ieee80211_node_table *nt, A_UINT8 *bssid)
 530{
 531    bss_t *bss, *nextBss;
 532
 533    IEEE80211_NODE_LOCK(nt);
 534
 535    bss = nt->nt_node_first;
 536
 537    while (bss != NULL)
 538    {
 539        nextBss = bss->ni_list_next;
 540
 541        if (A_MEMCMP(bssid, bss->ni_macaddr, 6) == 0)
 542        {
 543            wlan_node_remove_core (nt, bss);
 544            IEEE80211_NODE_UNLOCK(nt);
 545            return bss;
 546        }
 547
 548        bss = nextBss;
 549    }
 550
 551    IEEE80211_NODE_UNLOCK(nt);
 552    return NULL;
 553}
 554
 555bss_t *
 556wlan_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)
 559{
 560    bss_t   *ni = NULL;
 561    bss_t   *best_ni = NULL;
 562    A_UCHAR *pIESsid = NULL;
 563
 564    IEEE80211_NODE_LOCK (nt);
 565
 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) {
 569
 570            // Step 1 : Check SSID
 571            if (0x00 == memcmp (pSsid, &pIESsid[2], ssidLength)) {
 572
 573                if (ni->ni_cie.ie_capInfo & 0x10)
 574                {
 575
 576                    if ((NULL != ni->ni_cie.ie_rsn) && (WPA2_PSK_AUTH == authMode))
 577                    {
 578                        /* WPA2 */
 579                        if (NULL == best_ni)
 580                        {
 581                            best_ni = ni;
 582                        }
 583                        else if (ni->ni_rssi > best_ni->ni_rssi)
 584                        {
 585                            best_ni = ni;
 586                        }
 587                    }
 588                    else if ((NULL != ni->ni_cie.ie_wpa) && (WPA_PSK_AUTH == authMode))
 589                    {
 590                        /* WPA */
 591                        if (NULL == best_ni)
 592                        {
 593                            best_ni = ni;
 594                        }
 595                        else if (ni->ni_rssi > best_ni->ni_rssi)
 596                        {
 597                            best_ni = ni;
 598                        }
 599                    }
 600                    else if (WEP_CRYPT == pairwiseCryptoType)
 601                    {
 602                        /* WEP */
 603                        if (NULL == best_ni)
 604                        {
 605                            best_ni = ni;
 606                        }
 607                        else if (ni->ni_rssi > best_ni->ni_rssi)
 608                        {
 609                            best_ni = ni;
 610                        }
 611                    }
 612                }
 613                else
 614                {
 615                    /* open AP */
 616                    if ((OPEN_AUTH == authMode) && (NONE_CRYPT == pairwiseCryptoType))
 617                    {
 618                        if (NULL == best_ni)
 619                        {
 620                            best_ni = ni;
 621                        }
 622                        else if (ni->ni_rssi > best_ni->ni_rssi)
 623                        {
 624                            best_ni = ni;
 625                        }
 626                    }
 627                }
 628            }
 629        }
 630    }
 631
 632    IEEE80211_NODE_UNLOCK (nt);
 633
 634    return best_ni;
 635}
 636
 637