Home | History | Annotate | Download | only in Application
      1 /*
      2  * roamingMngr_autoSM.c
      3  *
      4  * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
      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  *
     11  *  * Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  *  * Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in
     15  *    the documentation and/or other materials provided with the
     16  *    distribution.
     17  *  * Neither the name Texas Instruments nor the names of its
     18  *    contributors may be used to endorse or promote products derived
     19  *    from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     27  * 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
     31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 /** \file roamingMngr_autoSM.c
     35  *  \brief Roaming Manager
     36  *
     37  *  \see roamingMngr_autoSM.h
     38  */
     39 
     40 /****************************************************************************
     41  *                                                                          *
     42  *   MODULE:  Roaming Manager                                               *
     43  *   PURPOSE:                                                               *
     44  *   Roaming manager is responsible to receive Roaming triggers and try
     45  *      to select a better AP.
     46  *      The Roaming triggers are: Low RSSI, PER, consecutive No ACK on TX,
     47  *      beacon Missed or External request.
     48  *      In each Internal Roaming request, scan is performed and selection for
     49  *      better AP. Better AP is defined as a different AP with better RSSI,
     50  *      and similar SSID and security settings.
     51  *      If better AP is found, there is a check for fast-roaming via the
     52  *      Supplicant. Then connection to the new AP is invoked.
     53  *                                                                          *
     54  ****************************************************************************/
     55 
     56 #define __FILE_ID__  FILE_ID_135
     57 #include "osApi.h"
     58 
     59 #include "paramOut.h"
     60 #include "report.h"
     61 #include "scanMngrApi.h"
     62 #include "roamingMngrApi.h"
     63 #include "apConnApi.h"
     64 #include "roamingMngrTypes.h"
     65 #include "bssTypes.h"
     66 #include "DrvMainModules.h"
     67 #include "TWDriver.h"
     68 #include "siteMgrApi.h"
     69 #include "GenSM.h"
     70 #include "roamingMngr_autoSM.h"
     71 
     72 
     73 /*****************************************************************************
     74 **         Private Function section                                      **
     75 *****************************************************************************/
     76 /* SM functions */
     77 
     78 static void roamingMngr_smStartIdle(TI_HANDLE hRoamingMngr);
     79 static void roamingMngr_smRoamTrigger(TI_HANDLE hRoamingMngr);
     80 static void roamingMngr_smInvokeScan(TI_HANDLE hRoamingMngr);
     81 static void roamingMngr_smSelection(TI_HANDLE hRoamingMngr);
     82 static void roamingMngr_smHandover(TI_HANDLE hRoamingMngr);
     83 static void roamingMngr_smSuccHandover(TI_HANDLE hRoamingMngr);
     84 static void roamingMngr_smFailHandover(TI_HANDLE hRoamingMngr);
     85 static void roamingMngr_smScanFailure(TI_HANDLE hRoamingMngr);
     86 static void roamingMngr_smDisconnectWhileConnecting(TI_HANDLE hRoamingMngr);
     87 
     88 /*static TI_STATUS roamingMngr_smUnexpected(TI_HANDLE hRoamingMngr);
     89 static TI_STATUS roamingMngr_smNop(TI_HANDLE hRoamingMngr);
     90 static TI_STATUS roamingMngr_smStopWhileScanning(TI_HANDLE hRoamingMngr);
     91 */
     92 
     93 typedef enum
     94 {
     95 	REASSOC_RESP_SUCCESS =0,
     96 	REASSOC_RESP_FAILURE,
     97     REASSOC_RESP_REJECT
     98 } reassociationResp_e;
     99 
    100 
    101 /*-----------*/
    102 /* Constants */
    103 /*-----------*/
    104 
    105 TGenSM_actionCell roamingMngrAuto_matrix[ROAMING_MNGR_NUM_STATES][ROAMING_MNGR_NUM_EVENTS] =
    106 {
    107     /* next state and actions for IDLE state */
    108         {   {ROAMING_STATE_WAIT_4_TRIGGER, roamingMngr_smStartIdle},        /* START            */
    109             {ROAMING_STATE_IDLE, roamingMngr_smNop},                        /* STOP             */
    110             {ROAMING_STATE_IDLE, roamingMngr_smNop},                        /* ROAM_TRIGGER     */
    111             {ROAMING_STATE_IDLE, roamingMngr_smUnexpected},                 /* SCAN             */
    112             {ROAMING_STATE_IDLE, roamingMngr_smUnexpected},                 /* SELECT           */
    113             {ROAMING_STATE_IDLE, roamingMngr_smUnexpected},                 /* REQ_HANDOVER     */
    114             {ROAMING_STATE_IDLE, roamingMngr_smUnexpected},                 /* ROAM_SUCCESS     */
    115             {ROAMING_STATE_IDLE, roamingMngr_smUnexpected}                  /* FAILURE          */
    116         },
    117 
    118         /* next state and actions for WAIT_4_TRIGGER state */
    119         {   {ROAMING_STATE_WAIT_4_TRIGGER, roamingMngr_smUnexpected},   /* START            */
    120             {ROAMING_STATE_IDLE, roamingMngr_smStop},                   /* STOP             */
    121             {ROAMING_STATE_WAIT_4_CMD, roamingMngr_smRoamTrigger},      /* ROAM_TRIGGER     */
    122             {ROAMING_STATE_WAIT_4_TRIGGER, roamingMngr_smUnexpected},   /* SCAN             */
    123             {ROAMING_STATE_WAIT_4_TRIGGER, roamingMngr_smUnexpected},   /* SELECT           */
    124             {ROAMING_STATE_WAIT_4_TRIGGER, roamingMngr_smUnexpected},   /* REQ_HANDOVER     */
    125             {ROAMING_STATE_WAIT_4_TRIGGER, roamingMngr_smUnexpected},   /* ROAM_SUCCESS     */
    126             {ROAMING_STATE_WAIT_4_TRIGGER, roamingMngr_smUnexpected}    /* FAILURE          */
    127         },
    128 
    129         /* next state and actions for WAIT_4_CMD state */
    130         {   {ROAMING_STATE_WAIT_4_CMD, roamingMngr_smUnexpected},               /* START            */
    131             {ROAMING_STATE_WAIT_4_CMD, roamingMngr_smUnexpected},               /* STOP             */
    132             {ROAMING_STATE_WAIT_4_CMD, roamingMngr_smUnexpected},               /* ROAM_TRIGGER     */
    133             {ROAMING_STATE_SCANNING, roamingMngr_smInvokeScan},                 /* SCAN             */
    134             {ROAMING_STATE_SELECTING, roamingMngr_smSelection},                 /* SELECT           */
    135             {ROAMING_STATE_WAIT_4_CMD, roamingMngr_smUnexpected},               /* REQ_HANDOVER     */
    136             {ROAMING_STATE_WAIT_4_CMD, roamingMngr_smUnexpected},               /* ROAM_SUCCESS     */
    137             {ROAMING_STATE_WAIT_4_CMD, roamingMngr_smUnexpected}                /* FAILURE          */
    138         },
    139 
    140         /* next state and actions for SCANNING state */
    141         {   {ROAMING_STATE_SCANNING, roamingMngr_smUnexpected},              /* START            */
    142             {ROAMING_STATE_IDLE, roamingMngr_smStopWhileScanning},           /* STOP             */
    143             {ROAMING_STATE_SCANNING, roamingMngr_smNop},                     /* ROAM_TRIGGER     */
    144             {ROAMING_STATE_SCANNING, roamingMngr_smInvokeScan},              /* SCAN             */
    145             {ROAMING_STATE_SELECTING, roamingMngr_smSelection},              /* SELECT           */
    146             {ROAMING_STATE_SCANNING, roamingMngr_smUnexpected},              /* REQ_HANDOVER     */
    147             {ROAMING_STATE_SCANNING, roamingMngr_smUnexpected},              /* ROAM_SUCCESS     */
    148             {ROAMING_STATE_IDLE, roamingMngr_smScanFailure}                  /* FAILURE          */
    149 
    150         },
    151 
    152         /* next state and actions for SELECTING state */
    153         {   {ROAMING_STATE_SELECTING, roamingMngr_smUnexpected},             /* START            */
    154             {ROAMING_STATE_SELECTING, roamingMngr_smUnexpected},             /* STOP             */
    155             {ROAMING_STATE_SELECTING, roamingMngr_smUnexpected},             /* ROAM_TRIGGER     */
    156             {ROAMING_STATE_SELECTING, roamingMngr_smUnexpected},             /* SCAN             */
    157             {ROAMING_STATE_SELECTING, roamingMngr_smUnexpected},             /* SELECT           */
    158             {ROAMING_STATE_CONNECTING, roamingMngr_smHandover},              /* REQ_HANDOVER     */
    159             {ROAMING_STATE_SELECTING, roamingMngr_smUnexpected},             /* ROAM_SUCCESS     */
    160             {ROAMING_STATE_SELECTING, roamingMngr_smUnexpected}              /* FAILURE          */
    161 
    162         },
    163 
    164         /* next state and actions for CONNECTING state */
    165         {   {ROAMING_STATE_CONNECTING, roamingMngr_smUnexpected},           /* START            */
    166             {ROAMING_STATE_IDLE, roamingMngr_smStop},                       /* STOP             */
    167             {ROAMING_STATE_IDLE, roamingMngr_smDisconnectWhileConnecting},      /* ROAM_TRIGGER     */
    168             {ROAMING_STATE_CONNECTING, roamingMngr_smUnexpected},           /* SCAN,            */
    169             {ROAMING_STATE_CONNECTING, roamingMngr_smUnexpected},           /* SELECT           */
    170             {ROAMING_STATE_CONNECTING, roamingMngr_smHandover},             /* REQ_HANDOVER     */
    171             {ROAMING_STATE_WAIT_4_TRIGGER, roamingMngr_smSuccHandover} ,    /* ROAM_SUCCESS     */
    172             {ROAMING_STATE_IDLE, roamingMngr_smFailHandover}                /* FAILURE          */
    173 
    174         }
    175 };
    176 
    177 
    178 TI_INT8*  AutoRoamStateDescription[] =
    179 {
    180     "IDLE",
    181     "WAIT_4_TRIGGER",
    182     "WAIT_4_CMD",
    183     "SCANNING",
    184     "SELECTING",
    185     "CONNECTING"
    186 };
    187 
    188 TI_INT8*  AutoRoamEventDescription[] =
    189 {
    190     "START",
    191     "STOP",
    192     "ROAM_TRIGGER",
    193     "SCAN",
    194     "SELECT",
    195     "REQ_HANDOVER",
    196     "ROAM_SUCCESS",
    197     "FAILURE"
    198 };
    199 
    200 /**
    201 *
    202 * roamingMngr_smRoamTrigger
    203 *
    204 * \b Description:
    205 *
    206 * This procedure is called when an Roaming event occurs: BSS LOSS, LOW Quality etc.
    207  * Performs the following:
    208  * - If Roaming is disabled, ignore.
    209  * - Indicate Driver that Roaming process is starting
    210  * - Get the BSS list from the Scan Manager.
    211  * - If the list is not empty, start SELECTION
    212  * - If the list is empty, start SCANNING. The type of scan is decided
    213  *      according to the Neigbor APs existence.
    214 *
    215 * \b ARGS:
    216 *
    217 *  I   - hRoamingMngr - roamingMngr SM context  \n
    218 *
    219 * \b RETURNS:
    220 *
    221 *  TI_OK if successful, TI_NOK otherwise.
    222 *
    223 *
    224 */
    225 static void roamingMngr_smRoamTrigger(TI_HANDLE hRoamingMngr)
    226 {
    227     roamingMngr_t           *pRoamingMngr;
    228     roamingMngr_smEvents    roamingEvent;
    229 
    230     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    231     TRACE1(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smRoamTrigger, enableDisable = %d\n",pRoamingMngr->roamingMngrConfig.enableDisable);
    232 
    233     if (!pRoamingMngr->roamingMngrConfig.enableDisable)
    234     {
    235 		/* Ignore any other Roaming event when Roaming is disabled */
    236         TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_ERROR, "roamingMngr_smRoamTrigger, when Roaming is disabled\n");
    237         return;
    238     }
    239     /* Indicate the driver that Roaming process is starting */
    240     apConn_prepareToRoaming(pRoamingMngr->hAPConnection, pRoamingMngr->roamingTrigger);
    241 
    242     /* Get the current BSSIDs from ScanMngr */
    243     pRoamingMngr->pListOfAPs = scanMngr_getBSSList(pRoamingMngr->hScanMngr);
    244     if ((pRoamingMngr->pListOfAPs != NULL) && (pRoamingMngr->pListOfAPs->numOfEntries > 0))
    245     {   /* No need to SCAN, start SELECTING */
    246         roamingEvent = ROAMING_EVENT_SELECT;
    247     }
    248     else
    249     {   /* check if list of APs exists in order to verify which scan to start */
    250         roamingEvent = ROAMING_EVENT_SCAN;
    251         if (pRoamingMngr->neighborApsExist)
    252         {   /* Scan only Neighbor APs */
    253             pRoamingMngr->scanType = ROAMING_PARTIAL_SCAN;
    254         }
    255         else
    256         {   /* Scan all channels */
    257             pRoamingMngr->scanType = ROAMING_FULL_SCAN;
    258         }
    259     }
    260     TRACE1(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smRoamTrigger, scanType = %d\n", pRoamingMngr->scanType);
    261 
    262     roamingMngr_smEvent(roamingEvent, pRoamingMngr);
    263 }
    264 
    265 /**
    266 *
    267 * roamingMngr_smInvokeScan
    268 *
    269 * \b Description:
    270 *
    271 * This procedure is called when scan should be performed in order
    272  * to select an AP to roam to.
    273  * This can be the first scan, a second scan after partail scan,
    274  * or scan after previous scan was failed.
    275  * In any case, the scan can either be:
    276  *  partail, on list of channles or
    277  *  full on all channels.
    278 *
    279 * \b ARGS:
    280 *
    281 *  I   - hRoamingMngr - roamingMngr SM context  \n
    282 *
    283 * \b RETURNS:
    284 *
    285 *  TI_OK if successful, TI_NOK otherwise.
    286 *
    287 *
    288 */
    289 static void roamingMngr_smInvokeScan(TI_HANDLE hRoamingMngr)
    290 {
    291     roamingMngr_t       *pRoamingMngr;
    292     scan_mngrResultStatus_e     scanResult;
    293 
    294     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    295 
    296     /* check which scan should be performed: Partial on list of channels, or full scan */
    297     if ((pRoamingMngr->scanType == ROAMING_PARTIAL_SCAN) ||
    298         (pRoamingMngr->scanType == ROAMING_PARTIAL_SCAN_RETRY))
    299     {
    300         scanResult = scanMngr_startImmediateScan (pRoamingMngr->hScanMngr, TI_TRUE);
    301     }
    302     else
    303     {    /* Scan all channels */
    304         scanResult = scanMngr_startImmediateScan (pRoamingMngr->hScanMngr, TI_FALSE);
    305     }
    306 
    307     if (scanResult != SCAN_MRS_SCAN_RUNNING)
    308     {   /* the scan failed, immitate scan complete event */
    309         TRACE1(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smInvokeScan, scanResult = %d\n", scanResult);
    310         roamingMngr_immediateScanComplete(pRoamingMngr, scanResult);
    311     }
    312 }
    313 
    314 /**
    315 *
    316 * roamingMngr_smSelection
    317 *
    318 * \b Description:
    319 *
    320 * This procedure is called when selection should be performed.
    321 *   It perform the following:
    322  * Prepare the candidate APs to roam according to:
    323  *  - Priority APs
    324  *  - Pre-Authenticated APs
    325  * If the candidate AP list is empty, only the current AP can be re-selected
    326  * Select one AP and trigger REQ_HANDOVER event.
    327  *
    328 * \b ARGS:
    329 *
    330 *  I   - hRoamingMngr - roamingMngr SM context  \n
    331 *
    332 * \b RETURNS:
    333 *
    334 *  TI_OK if successful, TI_NOK otherwise.
    335 *
    336 *
    337 */
    338 static void roamingMngr_smSelection(TI_HANDLE hRoamingMngr)
    339 {
    340     roamingMngr_t               *pRoamingMngr;
    341     TI_UINT32                      index;
    342 
    343 
    344     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    345     pRoamingMngr->listOfCandidateAps.numOfNeighborBSS = 0;
    346     pRoamingMngr->listOfCandidateAps.numOfPreAuthBSS = 0;
    347     pRoamingMngr->listOfCandidateAps.numOfRegularBSS = 0;
    348 
    349     pRoamingMngr->candidateApIndex = INVALID_CANDIDATE_INDEX;
    350 
    351     if ((pRoamingMngr->pListOfAPs == NULL) ||
    352         (pRoamingMngr->pListOfAPs->numOfEntries == 0))
    353     {   /* Error, there cannot be selection  */
    354         TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smSelection pListOfAPs is empty \n");
    355         roamingMngr_smEvent(ROAMING_EVENT_REQ_HANDOVER, pRoamingMngr);
    356         return;
    357     }
    358 
    359     /* Build the candidate AP list */
    360     for (index=0; index<pRoamingMngr->pListOfAPs->numOfEntries; index++ )
    361     {
    362         if ( (pRoamingMngr->roamingTrigger <= ROAMING_TRIGGER_LOW_QUALITY_GROUP) &&
    363             (pRoamingMngr->pListOfAPs->BSSList[index].RSSI < pRoamingMngr->roamingMngrConfig.apQualityThreshold))
    364         {   /* Do not insert APs with low quality to the selection table,
    365                 if the Roaming Trigger was low Quality */
    366             TRACE8(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "candidate AP %x-%x-%x-%x-%x-%x with RSSI too low =%d, Quality=%d  \n", pRoamingMngr->pListOfAPs->BSSList[index].BSSID[0], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[1], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[2], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[3], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[4], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[5], pRoamingMngr->pListOfAPs->BSSList[index].RSSI, pRoamingMngr->roamingMngrConfig.apQualityThreshold);
    367 
    368             continue;
    369         }
    370 
    371         if (apConn_isSiteBanned(pRoamingMngr->hAPConnection, &pRoamingMngr->pListOfAPs->BSSList[index].BSSID) == TI_TRUE)
    372         {
    373             TRACE6(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, ": Candidate AP %02X-%02X-%02X-%02X-%02X-%02X is banned!\n",									 pRoamingMngr->pListOfAPs->BSSList[index].BSSID[0],	pRoamingMngr->pListOfAPs->BSSList[index].BSSID[1], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[2], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[3], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[4], pRoamingMngr->pListOfAPs->BSSList[index].BSSID[5]);
    374             continue;
    375         }
    376 
    377         if (pRoamingMngr->pListOfAPs->BSSList[index].bNeighborAP)
    378         {   /* The AP is a neighbor AP, insert its index to the neighbor APs list */
    379             pRoamingMngr->listOfCandidateAps.neighborBSSList[pRoamingMngr->listOfCandidateAps.numOfNeighborBSS] = index;
    380             pRoamingMngr->listOfCandidateAps.numOfNeighborBSS++;
    381         }
    382         else if (apConn_getPreAuthAPStatus(pRoamingMngr->hAPConnection,
    383 										   &pRoamingMngr->pListOfAPs->BSSList[index].BSSID))
    384         {   /* This AP is a pre-auth AP */
    385             pRoamingMngr->listOfCandidateAps.preAuthBSSList[pRoamingMngr->listOfCandidateAps.numOfPreAuthBSS] = index;
    386             pRoamingMngr->listOfCandidateAps.numOfPreAuthBSS++;
    387         }
    388         else
    389         {   /* This AP is not Neighbor nor Pre-Auth */
    390             pRoamingMngr->listOfCandidateAps.regularBSSList[pRoamingMngr->listOfCandidateAps.numOfRegularBSS] = index;
    391             pRoamingMngr->listOfCandidateAps.numOfRegularBSS++;
    392         }
    393     }
    394 
    395 #ifdef TI_DBG
    396     {   /* for debug */
    397         paramInfo_t     param;
    398 
    399         param.paramType = ROAMING_MNGR_PRINT_CANDIDATE_TABLE;
    400         roamingMngr_getParam(pRoamingMngr, &param);
    401 
    402     }
    403 #endif
    404     roamingMngr_smEvent(ROAMING_EVENT_REQ_HANDOVER, pRoamingMngr);
    405 
    406 }
    407 
    408 /**
    409 *
    410 * roamingMngr_smHandover
    411 *
    412 * \b Description:
    413 *
    414 * This procedure is called when handover should be invoked.
    415 *   Go over the candidate APs and start handover to each of them.
    416  * If there's no candidate APs, disconnect.
    417  * Handover to the current AP is allowed only if the trigger is
    418  * low quality.
    419  *
    420 * \b ARGS:
    421 *
    422 *  I   - hRoamingMngr - roamingMngr SM context  \n
    423 *
    424 * \b RETURNS:
    425 *
    426 *  TI_OK if successful, TI_NOK otherwise.
    427 *
    428 *
    429 */
    430 static void roamingMngr_smHandover(TI_HANDLE hRoamingMngr)
    431 {
    432     roamingMngr_t           *pRoamingMngr;
    433     bssEntry_t              *pApToConnect;
    434     apConn_connRequest_t    requestToApConn;
    435 
    436     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    437 
    438     if ((pRoamingMngr->handoverWasPerformed) && (pRoamingMngr->candidateApIndex == CURRENT_AP_INDEX))
    439     {   /* Handover with the current AP already failed, Disconnect */
    440         roamingMngr_smEvent(ROAMING_EVENT_FAILURE, pRoamingMngr);
    441         return;
    442     }
    443     if (pRoamingMngr->listOfCandidateAps.numOfNeighborBSS > 0)
    444     {   /* Neighbor APs are the highest priority to Roam */
    445         pRoamingMngr->candidateApIndex =
    446             pRoamingMngr->listOfCandidateAps.neighborBSSList[pRoamingMngr->listOfCandidateAps.numOfNeighborBSS-1];
    447         pRoamingMngr->listOfCandidateAps.numOfNeighborBSS--;
    448     }
    449     else if (pRoamingMngr->listOfCandidateAps.numOfPreAuthBSS > 0)
    450     {   /* Pre-Auth APs are the second priority to Roam */
    451         pRoamingMngr->candidateApIndex =
    452             pRoamingMngr->listOfCandidateAps.preAuthBSSList[pRoamingMngr->listOfCandidateAps.numOfPreAuthBSS-1];
    453         pRoamingMngr->listOfCandidateAps.numOfPreAuthBSS--;
    454     }
    455     else if (pRoamingMngr->listOfCandidateAps.numOfRegularBSS > 0)
    456     {   /* Regular APs are APs that are not pre-authenticated and not Neighbor */
    457         pRoamingMngr->candidateApIndex =
    458             pRoamingMngr->listOfCandidateAps.regularBSSList[pRoamingMngr->listOfCandidateAps.numOfRegularBSS-1];
    459         pRoamingMngr->listOfCandidateAps.numOfRegularBSS--;
    460     }
    461     else
    462     {   /* No Candidate APs */
    463         pRoamingMngr->candidateApIndex = INVALID_CANDIDATE_INDEX;
    464     }
    465 
    466     TRACE1(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smHandover, candidateApIndex=%d \n", pRoamingMngr->candidateApIndex);
    467 
    468 
    469     if (pRoamingMngr->candidateApIndex == INVALID_CANDIDATE_INDEX)
    470     {   /* No cnadidate to Roam to, only the current AP is candidate */
    471         if (pRoamingMngr->roamingTrigger <= ROAMING_TRIGGER_LOW_QUALITY_GROUP)
    472         {   /* If the trigger to Roam is low quality, and there are no candidate APs
    473                 to roam to, retain connected to the current AP */
    474             requestToApConn.requestType = (pRoamingMngr->handoverWasPerformed) ? AP_CONNECT_RECONNECT_CURR_AP : AP_CONNECT_RETAIN_CURR_AP;
    475             pRoamingMngr->candidateApIndex = CURRENT_AP_INDEX;
    476         }
    477         else
    478         {   /* Disconnect the BSS, there are no more APs to roam to */
    479             roamingMngr_smEvent(ROAMING_EVENT_FAILURE, pRoamingMngr);
    480             return;
    481         }
    482     }
    483     else
    484     {   /* There is a valid candidate AP */
    485         if (pRoamingMngr->roamingTrigger > ROAMING_TRIGGER_FAST_CONNECT_GROUP)
    486         {   /* Full re-connection should be perfromed */
    487             requestToApConn.requestType = AP_CONNECT_FULL_TO_AP;
    488         }
    489         else
    490         {   /* Fast re-connection should be perfromed */
    491             requestToApConn.requestType = AP_CONNECT_FAST_TO_AP;
    492         }
    493     }
    494 #ifdef TI_DBG
    495     /* For debug */
    496     if (!pRoamingMngr->handoverWasPerformed)
    497     {   /* Take the time before the first handover started */
    498         pRoamingMngr->roamingHandoverStartedTimestamp = os_timeStampMs(pRoamingMngr->hOs);
    499     }
    500 #endif
    501 
    502     if (pRoamingMngr->candidateApIndex == CURRENT_AP_INDEX)
    503     {   /* get the current AP */
    504         pApToConnect = apConn_getBSSParams(pRoamingMngr->hAPConnection);
    505     }
    506     else
    507     {   /* get the candidate AP */
    508         pRoamingMngr->handoverWasPerformed = TI_TRUE;
    509         pApToConnect = &pRoamingMngr->pListOfAPs->BSSList[pRoamingMngr->candidateApIndex];
    510     }
    511     TRACE3(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smHandover, candidateApIndex=%d, requestType = %d, channel=%d \n", 							 pRoamingMngr->candidateApIndex, requestToApConn.requestType, pApToConnect->channel);
    512 
    513     requestToApConn.dataBufLength = 0;
    514     apConn_connectToAP(pRoamingMngr->hAPConnection, pApToConnect, &requestToApConn, TI_TRUE);
    515 }
    516 
    517 /**
    518 *
    519 * roamingMngr_smDisconnectWhileConnecting
    520 *
    521 * \b Description:
    522 *
    523 * This procedure is called when the Station is in the process of connection,
    524  * and the AP disconnects the station.
    525  *
    526 * \b ARGS:
    527 *
    528 *  I   - hRoamingMngr - roamingMngr SM context  \n
    529 *
    530 * \b RETURNS:
    531 *
    532 *  TI_OK if successful, TI_NOK otherwise.
    533 *
    534 *
    535 */
    536 static void roamingMngr_smDisconnectWhileConnecting(TI_HANDLE hRoamingMngr)
    537 {
    538     roamingMngr_t           *pRoamingMngr;
    539 
    540     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    541 
    542     TRACE1(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smDisconnectWhileConnecting, candidateApIndex=%d \n", pRoamingMngr->candidateApIndex);
    543 
    544     if (pRoamingMngr->roamingTrigger > ROAMING_TRIGGER_FAST_CONNECT_GROUP)
    545     {   /* If the trigger is from the Full Connect group, then stop the connection. */
    546         /* clean intenal variables */
    547         pRoamingMngr->maskRoamingEvents = TI_TRUE;
    548         pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    549 
    550         scanMngr_stopContScan(pRoamingMngr->hScanMngr);
    551 #ifdef TI_DBG
    552         pRoamingMngr->roamingFailedHandoverNum++;
    553 #endif
    554         apConn_disconnect(pRoamingMngr->hAPConnection);
    555 
    556     }
    557 }
    558 
    559 /**
    560 *
    561 * roamingMngr_smSuccHandover
    562 *
    563 * \b Description:
    564 *
    565 * This procedure is called when handover succeeded.
    566  * Inform Scan Manager about the new AP.
    567  * UnMask Roaming Triggers.
    568  *
    569 * \b ARGS:
    570 *
    571 *  I   - hRoamingMngr - roamingMngr SM context  \n
    572 *
    573 * \b RETURNS:
    574 *
    575 *  TI_OK if successful, TI_NOK otherwise.
    576 *
    577 *
    578 */
    579 static void roamingMngr_smSuccHandover(TI_HANDLE hRoamingMngr)
    580 {
    581     roamingMngr_t           *pRoamingMngr;
    582     bssEntry_t              *pNewConnectedAp;
    583 
    584     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    585 
    586     TRACE1(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smSuccHandover, candidateApIndex=%d \n", pRoamingMngr->candidateApIndex);
    587 
    588     if (pRoamingMngr->handoverWasPerformed &&
    589         (pRoamingMngr->pListOfAPs != NULL) &&
    590         (pRoamingMngr->pListOfAPs->numOfEntries>0))
    591     {
    592         if (pRoamingMngr->candidateApIndex == CURRENT_AP_INDEX)
    593         {
    594 			/* get the current AP */
    595             pNewConnectedAp = apConn_getBSSParams(pRoamingMngr->hAPConnection);
    596         }
    597         else
    598         {
    599 			/* get the candidate AP */
    600             pNewConnectedAp = &pRoamingMngr->pListOfAPs->BSSList[pRoamingMngr->candidateApIndex];
    601         }
    602 
    603         scanMngr_handoverDone(pRoamingMngr->hScanMngr,
    604 							  &pNewConnectedAp->BSSID,
    605 							  pNewConnectedAp->band);
    606     }
    607     pRoamingMngr->maskRoamingEvents = TI_FALSE;
    608     pRoamingMngr->candidateApIndex = INVALID_CANDIDATE_INDEX;
    609     pRoamingMngr->handoverWasPerformed = TI_FALSE;
    610     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    611 
    612     /* Start pre-authentication in order to set PMKID
    613         for the current AP */
    614     if (pRoamingMngr->staCapabilities.authMode==os802_11AuthModeWPA2)
    615     {
    616 		/* No Pre-Auth is required */
    617         bssList_t           *pBssList;
    618 
    619         TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smStartIdle, Pre-Auth to cur AP\n");
    620         pBssList = os_memoryAlloc(pRoamingMngr->hOs, sizeof(bssList_t));
    621         if (!pBssList)
    622             return;
    623         pBssList->numOfEntries = 0;
    624         apConn_preAuthenticate(pRoamingMngr->hAPConnection, pBssList);
    625         os_memoryFree(pRoamingMngr->hOs, pBssList, sizeof(bssList_t));
    626     }
    627 }
    628 
    629 /**
    630 *
    631 * roamingMngr_smFailHandover
    632 *
    633 * \b Description:
    634 *
    635 * This procedure is called when handover failed and there are no more
    636  * APs to roam to. Disconnect the BSS and retrun to IDLE state.
    637 *
    638 * \b ARGS:
    639 *
    640 *  I   - hRoamingMngr - roamingMngr SM context  \n
    641 *
    642 * \b RETURNS:
    643 *
    644 *  TI_OK if successful, TI_NOK otherwise.
    645 *
    646 *
    647 */
    648 static void roamingMngr_smFailHandover(TI_HANDLE hRoamingMngr)
    649 {
    650     roamingMngr_t           *pRoamingMngr;
    651 
    652     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    653     TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smFailHandover \n");
    654 
    655     /* clean intenal variables */
    656     pRoamingMngr->maskRoamingEvents = TI_TRUE;
    657     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    658 
    659     scanMngr_stopContScan(pRoamingMngr->hScanMngr);
    660 #ifdef TI_DBG
    661     pRoamingMngr->roamingFailedHandoverNum++;
    662 #endif
    663     apConn_disconnect(pRoamingMngr->hAPConnection);
    664 }
    665 
    666 /**
    667 *
    668 * roamingMngr_smScanFailure
    669 *
    670 * \b Description:
    671 *
    672 * This procedure is called when all scan attempts failed.
    673  * Send Disconnect event and return to IDLE state.
    674  *
    675 *
    676 * \b ARGS:
    677 *
    678 *  I   - hRoamingMngr - roamingMngr SM context  \n
    679 *
    680 * \b RETURNS:
    681 *
    682 *  TI_OK if successful, TI_NOK otherwise.
    683 *
    684 *
    685 */
    686 static void roamingMngr_smScanFailure(TI_HANDLE hRoamingMngr)
    687 {
    688     roamingMngr_t           *pRoamingMngr;
    689 
    690     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    691     TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smScanFailure \n");
    692 
    693     /* clean intenal variables */
    694     pRoamingMngr->maskRoamingEvents = TI_TRUE;
    695     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    696 
    697     scanMngr_stopContScan(pRoamingMngr->hScanMngr);
    698 
    699     apConn_disconnect(pRoamingMngr->hAPConnection);
    700 }
    701 
    702 #if 0
    703 /**
    704 *
    705 * roamingMngr_smCmdFailure
    706 *
    707 * \b Description:
    708 *
    709 * This procedure is called when all the driver failed to prepare to Roaming.
    710  * Mask all future Roaming triggers.
    711  *
    712 *
    713 * \b ARGS:
    714 *
    715 *  I   - hRoamingMngr - roamingMngr SM context  \n
    716 *
    717 * \b RETURNS:
    718 *
    719 *  TI_OK if successful, TI_NOK otherwise.
    720 *
    721 *
    722 */
    723 static void roamingMngr_smCmdFailure(TI_HANDLE hRoamingMngr)
    724 {
    725     roamingMngr_t           *pRoamingMngr;
    726 
    727     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    728     TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smCmdFailure \n");
    729 
    730     /* clean intenal variables */
    731     pRoamingMngr->maskRoamingEvents = TI_TRUE;
    732     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    733 }
    734 #endif
    735 
    736 /**
    737 *
    738 * roamingMngr_smStartIdle - Start event when in Idle state
    739 *
    740 * \b Description:
    741 *
    742 * Start event when in Idle state.
    743  * This function is called when the station becomes CONNECTED.
    744  * Perform the following:
    745  * - The current state becomes WAIT_4_TRIGGER
    746  * - Unmask Roaming events
    747  * - Set handoverWasPerformed to TI_FALSE
    748  * - Start the Scan Manager
    749 *
    750 * \b ARGS:
    751 *
    752 *  I   - pData - pointer to the roamingMngr SM context  \n
    753 *
    754 * \b RETURNS:
    755 *
    756 *  TI_OK if successful, TI_NOK otherwise.
    757 *
    758 *
    759 */
    760 static void roamingMngr_smStartIdle(void *pData)
    761 {
    762     roamingMngr_t       *pRoamingMngr;
    763     bssEntry_t          *pCurBssEntry;
    764 
    765     pRoamingMngr = (roamingMngr_t*)pData;
    766     TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smStartIdle, Unmask Roaming events and start continuos scan \n");
    767 
    768     pRoamingMngr->maskRoamingEvents = TI_FALSE;
    769     pRoamingMngr->handoverWasPerformed = TI_FALSE;
    770     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    771 
    772     pCurBssEntry = apConn_getBSSParams(pRoamingMngr->hAPConnection);
    773     scanMngr_startContScan(pRoamingMngr->hScanMngr, &pCurBssEntry->BSSID, pCurBssEntry->band);
    774 
    775     /* Start pre-authentication in order to set PMKID
    776         for the current AP */
    777     if (pRoamingMngr->staCapabilities.authMode==os802_11AuthModeWPA2)
    778     {   /* No Pre-Auth is required */
    779         bssList_t           *pBssList;
    780 
    781         TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smStartIdle, Pre-Auth to cur AP\n");
    782         pBssList = os_memoryAlloc(pRoamingMngr->hOs, sizeof(bssList_t));
    783         if (!pBssList)
    784             return;
    785 
    786         pBssList->numOfEntries = 0;
    787         apConn_preAuthenticate(pRoamingMngr->hAPConnection, pBssList);
    788         os_memoryFree(pRoamingMngr->hOs, pBssList, sizeof(bssList_t));
    789     }
    790 }
    791 
    792