Home | History | Annotate | Download | only in Application
      1 /*
      2  * roamingMngr_autoSM.c
      3  *
      4  * Copyright(c) 1998 - 2010 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 
    515 #ifdef XCC_MODULE_INCLUDED
    516     apConn_connectToAP(pRoamingMngr->hAPConnection, pApToConnect, &requestToApConn, pRoamingMngr->bSendTspecInReassPkt);
    517 #else
    518     apConn_connectToAP(pRoamingMngr->hAPConnection, pApToConnect, &requestToApConn, TI_TRUE);
    519 #endif
    520 }
    521 
    522 /**
    523 *
    524 * roamingMngr_smDisconnectWhileConnecting
    525 *
    526 * \b Description:
    527 *
    528 * This procedure is called when the Station is in the process of connection,
    529  * and the AP disconnects the station.
    530  *
    531 * \b ARGS:
    532 *
    533 *  I   - hRoamingMngr - roamingMngr SM context  \n
    534 *
    535 * \b RETURNS:
    536 *
    537 *  TI_OK if successful, TI_NOK otherwise.
    538 *
    539 *
    540 */
    541 static void roamingMngr_smDisconnectWhileConnecting(TI_HANDLE hRoamingMngr)
    542 {
    543     roamingMngr_t           *pRoamingMngr;
    544 
    545     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    546 
    547     TRACE1(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smDisconnectWhileConnecting, candidateApIndex=%d \n", pRoamingMngr->candidateApIndex);
    548 
    549     if (pRoamingMngr->roamingTrigger > ROAMING_TRIGGER_FAST_CONNECT_GROUP)
    550     {   /* If the trigger is from the Full Connect group, then stop the connection. */
    551         /* clean intenal variables */
    552         pRoamingMngr->maskRoamingEvents = TI_TRUE;
    553         pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    554 
    555         scanMngr_stopContScan(pRoamingMngr->hScanMngr);
    556 #ifdef TI_DBG
    557         pRoamingMngr->roamingFailedHandoverNum++;
    558 #endif
    559         apConn_disconnect(pRoamingMngr->hAPConnection);
    560 
    561     }
    562 }
    563 
    564 /**
    565 *
    566 * roamingMngr_smSuccHandover
    567 *
    568 * \b Description:
    569 *
    570 * This procedure is called when handover succeeded.
    571  * Inform Scan Manager about the new AP.
    572  * UnMask Roaming Triggers.
    573  *
    574 * \b ARGS:
    575 *
    576 *  I   - hRoamingMngr - roamingMngr SM context  \n
    577 *
    578 * \b RETURNS:
    579 *
    580 *  TI_OK if successful, TI_NOK otherwise.
    581 *
    582 *
    583 */
    584 static void roamingMngr_smSuccHandover(TI_HANDLE hRoamingMngr)
    585 {
    586     roamingMngr_t           *pRoamingMngr;
    587     bssEntry_t              *pNewConnectedAp;
    588 
    589     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    590 
    591     TRACE1(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smSuccHandover, candidateApIndex=%d \n", pRoamingMngr->candidateApIndex);
    592 
    593     if (pRoamingMngr->handoverWasPerformed &&
    594         (pRoamingMngr->pListOfAPs != NULL) &&
    595         (pRoamingMngr->pListOfAPs->numOfEntries>0))
    596     {
    597         if (pRoamingMngr->candidateApIndex == CURRENT_AP_INDEX)
    598         {
    599 			/* get the current AP */
    600             pNewConnectedAp = apConn_getBSSParams(pRoamingMngr->hAPConnection);
    601         }
    602         else
    603         {
    604 			/* get the candidate AP */
    605             pNewConnectedAp = &pRoamingMngr->pListOfAPs->BSSList[pRoamingMngr->candidateApIndex];
    606         }
    607 
    608         scanMngr_handoverDone(pRoamingMngr->hScanMngr,
    609 							  &pNewConnectedAp->BSSID,
    610 							  pNewConnectedAp->band);
    611     }
    612     pRoamingMngr->maskRoamingEvents = TI_FALSE;
    613     pRoamingMngr->candidateApIndex = INVALID_CANDIDATE_INDEX;
    614     pRoamingMngr->handoverWasPerformed = TI_FALSE;
    615     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    616 
    617     /* Start pre-authentication in order to set PMKID
    618         for the current AP */
    619     if (pRoamingMngr->staCapabilities.authMode==os802_11AuthModeWPA2)
    620     {
    621 		/* No Pre-Auth is required */
    622         bssList_t           *pBssList;
    623 
    624         pBssList = os_memoryAlloc(pRoamingMngr->hOs, sizeof(bssList_t));
    625         if (!pBssList)
    626         {
    627             return;
    628         }
    629         pBssList->numOfEntries = 0;
    630         apConn_preAuthenticate(pRoamingMngr->hAPConnection, pBssList);
    631         os_memoryFree(pRoamingMngr->hOs, pBssList, sizeof(bssList_t));
    632     }
    633 }
    634 
    635 /**
    636 *
    637 * roamingMngr_smFailHandover
    638 *
    639 * \b Description:
    640 *
    641 * This procedure is called when handover failed and there are no more
    642  * APs to roam to. Disconnect the BSS and retrun to IDLE state.
    643 *
    644 * \b ARGS:
    645 *
    646 *  I   - hRoamingMngr - roamingMngr SM context  \n
    647 *
    648 * \b RETURNS:
    649 *
    650 *  TI_OK if successful, TI_NOK otherwise.
    651 *
    652 *
    653 */
    654 static void roamingMngr_smFailHandover(TI_HANDLE hRoamingMngr)
    655 {
    656     roamingMngr_t           *pRoamingMngr;
    657 
    658     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    659     TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smFailHandover \n");
    660 
    661     /* clean intenal variables */
    662     pRoamingMngr->maskRoamingEvents = TI_TRUE;
    663     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    664 
    665     scanMngr_stopContScan(pRoamingMngr->hScanMngr);
    666 #ifdef TI_DBG
    667     pRoamingMngr->roamingFailedHandoverNum++;
    668 #endif
    669     apConn_disconnect(pRoamingMngr->hAPConnection);
    670 }
    671 
    672 /**
    673 *
    674 * roamingMngr_smScanFailure
    675 *
    676 * \b Description:
    677 *
    678 * This procedure is called when all scan attempts failed.
    679  * Send Disconnect event and return to IDLE state.
    680  *
    681 *
    682 * \b ARGS:
    683 *
    684 *  I   - hRoamingMngr - roamingMngr SM context  \n
    685 *
    686 * \b RETURNS:
    687 *
    688 *  TI_OK if successful, TI_NOK otherwise.
    689 *
    690 *
    691 */
    692 static void roamingMngr_smScanFailure(TI_HANDLE hRoamingMngr)
    693 {
    694     roamingMngr_t           *pRoamingMngr;
    695 
    696     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    697     TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smScanFailure \n");
    698 
    699     /* clean intenal variables */
    700     pRoamingMngr->maskRoamingEvents = TI_TRUE;
    701     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    702 
    703     scanMngr_stopContScan(pRoamingMngr->hScanMngr);
    704 
    705     apConn_disconnect(pRoamingMngr->hAPConnection);
    706 }
    707 
    708 #if 0
    709 /**
    710 *
    711 * roamingMngr_smCmdFailure
    712 *
    713 * \b Description:
    714 *
    715 * This procedure is called when all the driver failed to prepare to Roaming.
    716  * Mask all future Roaming triggers.
    717  *
    718 *
    719 * \b ARGS:
    720 *
    721 *  I   - hRoamingMngr - roamingMngr SM context  \n
    722 *
    723 * \b RETURNS:
    724 *
    725 *  TI_OK if successful, TI_NOK otherwise.
    726 *
    727 *
    728 */
    729 static void roamingMngr_smCmdFailure(TI_HANDLE hRoamingMngr)
    730 {
    731     roamingMngr_t           *pRoamingMngr;
    732 
    733     pRoamingMngr = (roamingMngr_t*)hRoamingMngr;
    734     TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smCmdFailure \n");
    735 
    736     /* clean intenal variables */
    737     pRoamingMngr->maskRoamingEvents = TI_TRUE;
    738     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    739 }
    740 #endif
    741 
    742 /**
    743 *
    744 * roamingMngr_smStartIdle - Start event when in Idle state
    745 *
    746 * \b Description:
    747 *
    748 * Start event when in Idle state.
    749  * This function is called when the station becomes CONNECTED.
    750  * Perform the following:
    751  * - The current state becomes WAIT_4_TRIGGER
    752  * - Unmask Roaming events
    753  * - Set handoverWasPerformed to TI_FALSE
    754  * - Start the Scan Manager
    755 *
    756 * \b ARGS:
    757 *
    758 *  I   - pData - pointer to the roamingMngr SM context  \n
    759 *
    760 * \b RETURNS:
    761 *
    762 *  TI_OK if successful, TI_NOK otherwise.
    763 *
    764 *
    765 */
    766 static void roamingMngr_smStartIdle(void *pData)
    767 {
    768     roamingMngr_t       *pRoamingMngr;
    769     bssEntry_t          *pCurBssEntry;
    770 
    771     pRoamingMngr = (roamingMngr_t*)pData;
    772     TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smStartIdle, Unmask Roaming events and start continuos scan \n");
    773 
    774     pRoamingMngr->maskRoamingEvents = TI_FALSE;
    775     pRoamingMngr->handoverWasPerformed = TI_FALSE;
    776     pRoamingMngr->roamingTrigger = ROAMING_TRIGGER_NONE;
    777 
    778     pCurBssEntry = apConn_getBSSParams(pRoamingMngr->hAPConnection);
    779     scanMngr_startContScan(pRoamingMngr->hScanMngr, &pCurBssEntry->BSSID, pCurBssEntry->band);
    780 
    781     /* Start pre-authentication in order to set PMKID
    782         for the current AP */
    783     if (pRoamingMngr->staCapabilities.authMode==os802_11AuthModeWPA2)
    784     {   /* No Pre-Auth is required */
    785         bssList_t           *pBssList;
    786 
    787         TRACE0(pRoamingMngr->hReport, REPORT_SEVERITY_INFORMATION, "roamingMngr_smStartIdle, Pre-Auth to cur AP\n");
    788         pBssList = os_memoryAlloc(pRoamingMngr->hOs, sizeof(bssList_t));
    789         if (!pBssList)
    790         {
    791             return;
    792         }
    793 
    794         pBssList->numOfEntries = 0;
    795         apConn_preAuthenticate(pRoamingMngr->hAPConnection, pBssList);
    796         os_memoryFree(pRoamingMngr->hOs, pBssList, sizeof(bssList_t));
    797     }
    798 }
    799 
    800