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, ¶m); 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