1 /* 2 * smeSm.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 smeSm.c 35 * \brief SME state machine implementation 36 * 37 * \see smeSm.h, sme.c, sme.h 38 */ 39 40 41 #define __FILE_ID__ FILE_ID_43 42 #include "GenSM.h" 43 #include "smeSm.h" 44 #include "smePrivate.h" 45 #include "connApi.h" 46 #include "apConn.h" 47 #include "ScanCncn.h" 48 #include "scanResultTable.h" 49 #include "EvHandler.h" 50 #include "regulatoryDomainApi.h" 51 #include "siteMgrApi.h" 52 #include "DrvMain.h" 53 54 55 static OS_802_11_DISASSOCIATE_REASON_E eDisassocConvertTable[ MGMT_STATUS_MAX_NUM ] = 56 { 57 OS_DISASSOC_STATUS_UNSPECIFIED, 58 OS_DISASSOC_STATUS_UNSPECIFIED, 59 OS_DISASSOC_STATUS_AUTH_REJECT, 60 OS_DISASSOC_STATUS_ASSOC_REJECT, 61 OS_DISASSOC_STATUS_SECURITY_FAILURE, 62 OS_DISASSOC_STATUS_AP_DEAUTHENTICATE, 63 OS_DISASSOC_STATUS_AP_DISASSOCIATE, 64 OS_DISASSOC_STATUS_ROAMING_TRIGGER, 65 OS_DISASSOC_STATUS_UNSPECIFIED, 66 OS_DISASSOC_STATUS_UNSPECIFIED, 67 OS_DISASSOC_STATUS_UNSPECIFIED, 68 OS_DISASSOC_STATUS_UNSPECIFIED, 69 OS_DISASSOC_STATUS_UNSPECIFIED, 70 OS_DISASSOC_STATUS_UNSPECIFIED, 71 OS_DISASSOC_STATUS_UNSPECIFIED, 72 }; 73 74 #define SME_CONVERT_DISASSOC_CODES(disassocReason) (eDisassocConvertTable[ (disassocReason) ]) 75 76 static void smeSm_Start (TI_HANDLE hSme); 77 static void smeSm_Stop (TI_HANDLE hSme); 78 static void smeSm_PreConnect (TI_HANDLE hSme); 79 static void smeSm_Connect (TI_HANDLE hSme); 80 static void smeSm_ConnectSuccess (TI_HANDLE hSme); 81 static void smeSm_Disconnect (TI_HANDLE hSme); 82 static void smeSm_DisconnectDone (TI_HANDLE hSme); 83 static void smeSm_StopScan (TI_HANDLE hSme); 84 static void smeSm_StopConnect (TI_HANDLE hSme); 85 static void smeSm_ConnWhenConnecting (TI_HANDLE hSme); 86 static void smeSm_ActionUnexpected (TI_HANDLE hSme); 87 static void smeSm_NopAction (TI_HANDLE hSme); 88 static void smeSm_CheckStartConditions (TI_HANDLE hSme); 89 90 static TI_STATUS sme_StartScan (TI_HANDLE hSme); 91 static void sme_updateScanCycles (TI_HANDLE hSme, 92 TI_BOOL bDEnabled, 93 TI_BOOL bCountryValid, 94 TI_BOOL bConstantScan); 95 static void sme_CalculateCyclesNumber (TI_HANDLE hSme, TI_UINT32 uTotalTimeMs); 96 97 TGenSM_actionCell tSmMatrix[ SME_SM_NUMBER_OF_STATES ][ SME_SM_NUMBER_OF_EVENTS ] = 98 { 99 { /* SME_SM_STATE_IDLE */ 100 { SME_SM_STATE_WAIT_CONNECT, smeSm_Start }, /* SME_SM_EVENT_START */ 101 { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_STOP */ 102 { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */ 103 { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ 104 { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_FAILURE */ 105 { SME_SM_STATE_IDLE, smeSm_CheckStartConditions }, /* SME_SM_EVENT_DISCONNECT */ 106 }, 107 { /* SME_SM_STATE_WAIT_CONNECT */ 108 { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ 109 { SME_SM_STATE_IDLE, smeSm_Stop }, /* SME_SM_EVENT_STOP */ 110 { SME_SM_STATE_SCANNING, smeSm_PreConnect }, /* SME_SM_EVENT_CONNECT */ 111 { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ 112 { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_FAILURE */ 113 { SME_SM_STATE_WAIT_CONNECT, smeSm_Start }, /* SME_SM_EVENT_DISCONNECT */ 114 }, 115 { /* SME_SM_STATE_SCANNING */ 116 { SME_SM_STATE_SCANNING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ 117 { SME_SM_STATE_DISCONNECTING, smeSm_StopScan }, /* SME_SM_EVENT_STOP */ 118 { SME_SM_STATE_CONNECTING, smeSm_Connect }, /* SME_SM_EVENT_CONNECT */ 119 { SME_SM_STATE_SCANNING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ 120 { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */ 121 { SME_SM_STATE_DISCONNECTING, smeSm_StopScan }, /* SME_SM_EVENT_DISCONNECT */ 122 }, 123 { /* SME_SM_STATE_CONNECTING */ 124 { SME_SM_STATE_CONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ 125 { SME_SM_STATE_DISCONNECTING, smeSm_StopConnect }, /* SME_SM_EVENT_STOP */ 126 { SME_SM_STATE_CONNECTING, smeSm_ConnWhenConnecting }, /* SME_SM_EVENT_CONNECT */ 127 { SME_SM_STATE_CONNECTED, smeSm_ConnectSuccess }, /* SME_SM_EVENT_CONNECT_SUCCESS */ 128 { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */ 129 { SME_SM_STATE_DISCONNECTING, smeSm_StopConnect }, /* SME_SM_EVENT_DISCONNECT */ 130 }, 131 { /* SME_SM_STATE_CONNECTED */ 132 { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ 133 { SME_SM_STATE_DISCONNECTING, smeSm_Disconnect }, /* SME_SM_EVENT_STOP */ 134 { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */ 135 { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ 136 { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */ 137 { SME_SM_STATE_DISCONNECTING, smeSm_Disconnect }, /* SME_SM_EVENT_DISCONNECT */ 138 }, 139 { /* SME_SM_STATE_DISCONNECTING */ 140 { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ 141 { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_STOP */ 142 { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */ 143 { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ 144 { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */ 145 { SME_SM_STATE_DISCONNECTING, smeSm_NopAction }, /* SME_SM_EVENT_DISCONNECT */ 146 } 147 }; 148 149 TI_INT8* uStateDescription[] = 150 { 151 "IDLE", 152 "WAIT_CONNECT", 153 "SCANNING", 154 "CONNECTING", 155 "CONNECTED", 156 "DISCONNECTING" 157 }; 158 159 TI_INT8* uEventDescription[] = 160 { 161 "START", 162 "STOP", 163 "CONNECT", 164 "CONNECT_SUCCESS", 165 "CONNECT_FAILURE", 166 "DISCONNECT" 167 }; 168 169 /** 170 * \fn smeSm_Start 171 * \brief Starts STA opeartion by moving SCR out of idle group and starting connection process 172 * 173 * Starts STA opeartion by moving SCR out of idle group and starting connection process 174 * 175 * \param hSme - handle to the SME object 176 * \return None 177 * \sa smeSm_Stop, sme_start 178 */ 179 void smeSm_Start (TI_HANDLE hSme) 180 { 181 TSme *pSme = (TSme*)hSme; 182 183 /* set SCR group according to connection mode */ 184 if (CONNECT_MODE_AUTO == pSme->eConnectMode) 185 { 186 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_Start: changing SCR group to DRV scan\n"); 187 scr_setGroup (pSme->hScr, SCR_GID_DRV_SCAN); 188 } 189 else 190 { 191 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_Start: changing SCR group to APP scan\n"); 192 scr_setGroup (pSme->hScr, SCR_GID_APP_SCAN); 193 } 194 195 if ((TI_FALSE == pSme->bRadioOn) || (TI_FALSE == pSme->bRunning)) 196 { 197 /* Radio is off so send stop event */ 198 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_STOP, hSme); 199 } 200 else if (TI_TRUE == pSme->bConnectRequired) 201 { 202 /* if connection was required, start the process */ 203 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme); 204 } 205 } 206 207 /** 208 * \fn smeSm_Stop 209 * \brief Turns off the STA 210 * 211 * Turns off the STA by moving the SCr to idle 212 * 213 * \param hSme - handle to the SME object 214 * \return None 215 * \sa smeSm_Start, sme_Stop 216 */ 217 void smeSm_Stop (TI_HANDLE hSme) 218 { 219 TSme *pSme = (TSme*)hSme; 220 221 /* set SCR group to idle */ 222 scr_setGroup (pSme->hScr, SCR_GID_IDLE); 223 224 if (TI_FALSE == pSme->bRunning) 225 { 226 /* call DrvMain */ 227 drvMain_SmeStop (pSme->hDrvMain); 228 } 229 } 230 231 /** 232 * \fn smeSm_PreConnect 233 * \brief Initiates the connection process 234 * 235 * Initiates the connection process - for automatic mode, start scan, for manual mode - triggers connection 236 * 237 * \param hSme - handle to the SME object 238 * \return None 239 * \sa smeSm_Connect, smeSm_ConnectSuccess 240 */ 241 void smeSm_PreConnect (TI_HANDLE hSme) 242 { 243 TSme *pSme = (TSme *)hSme; 244 paramInfo_t *pParam; 245 246 /* set the connection mode with which this connection attempt is starting */ 247 pSme->eLastConnectMode = pSme->eConnectMode; 248 249 /* mark that no authentication/assocaition was yet sent */ 250 pSme->bAuthSent = TI_FALSE; 251 252 /* try to find a connection candidate (manual mode have already performed scann */ 253 pSme->pCandidate = sme_Select (hSme); 254 if (NULL != pSme->pCandidate) 255 { 256 /* candidate is available - attempt connection */ 257 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme); 258 } 259 /* no candidate */ 260 else 261 { 262 if (CONNECT_MODE_AUTO == pSme->eConnectMode) 263 { 264 /* automatic mode - start scanning */ 265 if (TI_OK != sme_StartScan (hSme)) 266 { 267 TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_PreConnect: unable to start scan, stopping the SME\n"); 268 pSme->bRadioOn = TI_FALSE; 269 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); 270 } 271 272 /* update scan count counter */ 273 if(pSme->uScanCount < PERIODIC_SCAN_MAX_INTERVAL_NUM) 274 { 275 pSme->uScanCount++; 276 } 277 278 } 279 else /* Manual mode */ 280 { 281 /* for IBSS or any, if no entries where found, add the self site */ 282 if (pSme->eBssType == BSS_INFRASTRUCTURE) 283 { 284 /* makr whether we need to stop the attempt connection in manual mode */ 285 pSme->bConnectRequired = TI_FALSE; 286 287 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_PreConnect: No candidate available, sending connect failure\n"); 288 /* manual mode and no connection candidate is available - connection failed */ 289 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); 290 } 291 292 else /* IBSS */ 293 { 294 TI_UINT8 uDesiredChannel; 295 TI_BOOL channelValidity; 296 297 pSme->bConnectRequired = TI_FALSE; 298 299 pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t)); 300 if (!pParam) 301 return; 302 303 pParam->paramType = SITE_MGR_DESIRED_CHANNEL_PARAM; 304 siteMgr_getParam(pSme->hSiteMgr, pParam); 305 uDesiredChannel = pParam->content.siteMgrDesiredChannel; 306 307 if (uDesiredChannel >= SITE_MGR_CHANNEL_A_MIN) 308 { 309 pParam->content.channelCapabilityReq.band = RADIO_BAND_5_0_GHZ; 310 } 311 else 312 { 313 pParam->content.channelCapabilityReq.band = RADIO_BAND_2_4_GHZ; 314 } 315 316 /* 317 update the regulatory domain with the selected band 318 */ 319 /* Check if the selected channel is valid according to regDomain */ 320 pParam->paramType = REGULATORY_DOMAIN_GET_SCAN_CAPABILITIES; 321 pParam->content.channelCapabilityReq.scanOption = ACTIVE_SCANNING; 322 pParam->content.channelCapabilityReq.channelNum = uDesiredChannel; 323 324 regulatoryDomain_getParam (pSme->hRegDomain, pParam); 325 channelValidity = pParam->content.channelCapabilityRet.channelValidity; 326 os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t)); 327 if (!channelValidity) 328 { 329 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "IBSS SELECT FAILURE - No channel !!!\n\n"); 330 331 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); 332 333 return; 334 } 335 336 pSme->pCandidate = (TSiteEntry *)addSelfSite(pSme->hSiteMgr); 337 338 if (pSme->pCandidate == NULL) 339 { 340 TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "IBSS SELECT FAILURE - could not open self site !!!\n\n"); 341 342 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); 343 344 return; 345 } 346 347 #ifdef REPORT_LOG 348 TRACE6(pSme->hReport, REPORT_SEVERITY_CONSOLE,"%%%%%%%%%%%%%% SELF SELECT SUCCESS, bssid: %X-%X-%X-%X-%X-%X %%%%%%%%%%%%%%\n\n", pSme->pCandidate->bssid[0], pSme->pCandidate->bssid[1], pSme->pCandidate->bssid[2], pSme->pCandidate->bssid[3], pSme->pCandidate->bssid[4], pSme->pCandidate->bssid[5]); 349 WLAN_OS_REPORT (("%%%%%%%%%%%%%% SELF SELECT SUCCESS, bssid: %02x.%02x.%02x.%02x.%02x.%02x %%%%%%%%%%%%%%\n\n", pSme->pCandidate->bssid[0], pSme->pCandidate->bssid[1], pSme->pCandidate->bssid[2], pSme->pCandidate->bssid[3], pSme->pCandidate->bssid[4], pSme->pCandidate->bssid[5])); 350 #endif 351 /* a connection candidate is available, send a connect event */ 352 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme); 353 } 354 } 355 } 356 } 357 358 /** 359 * \fn smeSm_Connect 360 * \brief Starts a connection process with the selected network 361 * 362 * Starts a connection process with the selected network 363 * 364 * \param hSme - handle to the SME object 365 * \return None 366 * \sa smeSm_PreConnect, smeSm_ConnectSuccess 367 */ 368 void smeSm_Connect (TI_HANDLE hSme) 369 { 370 TSme *pSme = (TSme*)hSme; 371 TI_STATUS tStatus; 372 paramInfo_t *pParam; 373 374 /* Sanity check - if no connection candidate was found so far */ 375 if (NULL == pSme->pCandidate) 376 { 377 TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Connect: No candidate available, sending connect failure\n"); 378 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); 379 } 380 else 381 { 382 pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t)); 383 if (!pParam) 384 return; 385 386 /* set SCR group */ 387 if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType) 388 { 389 scr_setGroup (pSme->hScr, SCR_GID_CONNECT); 390 } 391 392 /***************** Config Connection *************************/ 393 pParam->paramType = CONN_TYPE_PARAM; 394 if (BSS_INDEPENDENT == pSme->pCandidate->bssType) 395 if (SITE_SELF == pSme->pCandidate->siteType) 396 { 397 pParam->content.connType = CONNECTION_SELF; 398 } 399 else 400 { 401 pParam->content.connType = CONNECTION_IBSS; 402 } 403 else 404 pParam->content.connType = CONNECTION_INFRA; 405 conn_setParam(pSme->hConn, pParam); 406 os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t)); 407 408 /* start the connection process */ 409 tStatus = conn_start (pSme->hConn, CONN_TYPE_FIRST_CONN, sme_ReportConnStatus, hSme, TI_FALSE, TI_FALSE); 410 if (TI_OK != tStatus) 411 { 412 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Connect: conn_start returned status %d\n", tStatus); 413 } 414 } 415 } 416 417 /** 418 * \fn smeSm_ConnectSuccess 419 * \brief Handles connection success indication 420 * 421 * Handles connection success indication - starts AP conn and set SCR group to connected 422 * 423 * \param hSme - handle to the SME object 424 * \return None 425 * \sa smeSm_PreConnect, smeSm_Connect 426 */ 427 void smeSm_ConnectSuccess (TI_HANDLE hSme) 428 { 429 TSme *pSme = (TSme*)hSme; 430 431 pSme->uScanCount = 0; 432 433 /* connection succedded to the connection candidate - start AP connection */ 434 if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType) 435 { 436 /* Start the AP connection */ 437 apConn_start (pSme->hApConn, 438 (pSme->tSsid.len != 0) && !OS_802_11_SSID_JUNK (pSme->tSsid.str, pSme->tSsid.len)); 439 } 440 441 /* Set SCR group to connected */ 442 scr_setGroup (pSme->hScr, SCR_GID_CONNECTED); 443 } 444 445 /** 446 * \fn smeSm_Disconnect 447 * \brief Starts a disconnect by calling the AP connection or connect modules 448 * 449 * Starts a disconnect by calling the AP connection or connect modules 450 * 451 * \param hSme - handle to the SME object 452 * \return None 453 * \sa smeSm_DisconnectDone 454 */ 455 void smeSm_Disconnect (TI_HANDLE hSme) 456 { 457 TSme *pSme = (TSme*)hSme; 458 TI_STATUS tStatus; 459 460 /* set the SCr group to connecting */ 461 scr_setGroup (pSme->hScr, SCR_GID_CONNECT); 462 463 if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType) 464 { 465 /* Call the AP connection to perform disconnect */ 466 tStatus = apConn_stop (pSme->hApConn, TI_TRUE); 467 } 468 else 469 { 470 /* In IBSS disconnect is done directly with the connection SM */ 471 tStatus = conn_stop(pSme->hConn, DISCONNECT_DE_AUTH, STATUS_UNSPECIFIED, 472 TI_TRUE, sme_ReportConnStatus, hSme); 473 if (tStatus != TI_OK) 474 { 475 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Disconnect: conn_stop retruned %d\n", tStatus); 476 } 477 } 478 } 479 480 /** 481 * \fn smeSm_DisconnectDone 482 * \brief Finish a disconnect process 483 * 484 * Finish a disconnect process by sending the appropriate event and restarting the state-machine 485 * 486 * \param hSme - handle to the SME object 487 * \return None 488 * \sa smeSm_Disconnect 489 */ 490 void smeSm_DisconnectDone (TI_HANDLE hSme) 491 { 492 TSme *pSme = (TSme*)hSme; 493 OS_802_11_DISASSOCIATE_REASON_T tEventReason; 494 495 if (TI_FALSE == pSme->bReselect) 496 { 497 /* send an event notifying the disassocation */ 498 if (TI_TRUE == pSme->bAuthSent) 499 { 500 tEventReason.eDisAssocType = SME_CONVERT_DISASSOC_CODES (pSme->tDisAssoc.eMgmtStatus); 501 tEventReason.uStatusCode = pSme->tDisAssoc.uStatusCode; 502 EvHandlerSendEvent (pSme->hEvHandler, IPC_EVENT_DISASSOCIATED, (TI_UINT8*)&tEventReason, 503 sizeof(OS_802_11_DISASSOCIATE_REASON_T)); 504 } 505 else if (CONNECT_MODE_AUTO != pSme->eLastConnectMode) 506 { 507 EvHandlerSendEvent (pSme->hEvHandler, IPC_EVENT_NOT_ASSOCIATED, NULL, 0); 508 } 509 } 510 511 siteMgr_disSelectSite (pSme->hSiteMgr); 512 513 /* try to reconnect */ 514 smeSm_Start (hSme); 515 } 516 517 /** 518 * \fn smeSm_StopScan 519 * \brief Stops the SME scan operation 520 * 521 * Stops the SME scan operation 522 * 523 * \param hSme - handle to the SME object 524 * \return None 525 * \sa smeSm_PreConnect, sme_StartScan 526 */ 527 void smeSm_StopScan (TI_HANDLE hSme) 528 { 529 TSme *pSme = (TSme*)hSme; 530 531 scanCncn_StopPeriodicScan (pSme->hScanCncn, SCAN_SCC_DRIVER); 532 } 533 534 /** 535 * \fn smeSm_StopConnect 536 * \brief Stops the connect module 537 * 538 * Stops the connect module (if the SME is stopped during a connect attempt 539 * 540 * \param hSme - handle to the SME object 541 * \return None 542 * \sa smeSm_Connect 543 */ 544 void smeSm_StopConnect (TI_HANDLE hSme) 545 { 546 TSme *pSme = (TSme*)hSme; 547 TI_STATUS tStatus; 548 549 tStatus = conn_stop (pSme->hConn, DISCONNECT_DE_AUTH, STATUS_UNSPECIFIED, 550 TI_TRUE, sme_ReportConnStatus, hSme); 551 552 if (TI_OK != tStatus) 553 { 554 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_StopConnect: conn_stop returned status %d\n", tStatus); 555 } 556 } 557 558 /** 559 * \fn smeSm_ConnWhenConnecting 560 * \brief Starts the connect process again 561 * 562 * Starts the connect process again 563 * 564 * \param hSme - handle to the SME object 565 * \return None 566 * \sa smeSm_Connect 567 */ 568 void smeSm_ConnWhenConnecting (TI_HANDLE hSme) 569 { 570 TSme *pSme = (TSme*)hSme; 571 TI_STATUS tStatus; 572 573 /* start the connection process */ 574 tStatus = conn_start (pSme->hConn, CONN_TYPE_FIRST_CONN, sme_ReportConnStatus, hSme, TI_FALSE, TI_FALSE); 575 if (TI_OK != tStatus) 576 { 577 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_ConnWhenConnecting: conn_start returned status %d\n", tStatus); 578 } 579 } 580 581 /** 582 * \fn smeSm_ActionUnexpected 583 * \brief Called when an unexpected event (for current state) is received 584 * 585 * Called when an unexpected event (for current state) is received 586 * 587 * \param hSme - handle to the SME object 588 * \return None 589 */ 590 void smeSm_ActionUnexpected (TI_HANDLE hSme) 591 { 592 TSme *pSme = (TSme*)hSme; 593 594 TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_ActionUnexpected called\n"); 595 } 596 597 /** 598 * \fn smeSm_NopAction 599 * \brief Called when event call and don't need to do nothing. 600 * 601 * \param hSme - handle to the SME object 602 * \return None 603 */ 604 void smeSm_NopAction (TI_HANDLE hSme) 605 { 606 TSme *pSme = (TSme*)hSme; 607 608 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_NopAction called\n"); 609 } 610 611 void smeSm_CheckStartConditions (TI_HANDLE hSme) 612 { 613 TSme *pSme = (TSme*)hSme; 614 615 if ((TI_TRUE == pSme->bRunning) && (TI_TRUE == pSme->bRadioOn)) 616 { 617 /* send a start event */ 618 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_START, hSme); 619 } 620 } 621 622 623 /* do we need to verify G only / A only / dual-band with site mgr? or rely on channels only? */ 624 625 /** 626 * \fn sme_StartScan 627 * \brief Set scan parameters and calls scan concnetartor to start the scan operation. 628 * 629 * Set scan parameters and calls scan concnetartor to start the scan operation. 630 * 631 * Scan parameters are set according to scan target - find country IE, find desired SSID, or both 632 * (one on each band). To find country IE we use passive scan forever, to find the desired SSID we 633 * use active scan until the current country IE expires. In addition, we take into account the WSC PB 634 * mode - scan constantly for two minutes (but under the country validity and expiry constraints) 635 * 636 * \param hSme - handle to the SME object 637 * \return TI_OK if scan started successfully, TI_NOK otherwise 638 * \sa smeSm_PreConnect 639 */ 640 TI_STATUS sme_StartScan (TI_HANDLE hSme) 641 { 642 TSme *pSme = (TSme*)hSme; 643 paramInfo_t *pParam; 644 TI_BOOL bDEnabled, bCountryValid; 645 TI_BOOL bBandChannelExist[ RADIO_BAND_NUM_OF_BANDS ]; 646 TI_BOOL bBandCountryFound[ RADIO_BAND_NUM_OF_BANDS ]; 647 TI_STATUS tStatus; 648 TI_UINT32 uIndex; 649 650 /* get 802.11d enable state */ 651 pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t)); 652 if (!pParam) 653 return TI_NOK; 654 655 pParam->paramType = REGULATORY_DOMAIN_ENABLED_PARAM; 656 regulatoryDomain_getParam (pSme->hRegDomain, pParam); 657 bDEnabled = pParam->content.regulatoryDomainEnabled; 658 659 pParam->paramType = REGULATORY_DOMAIN_IS_COUNTRY_FOUND; 660 /* get country validity for all bands */ 661 for (uIndex = 0; uIndex < RADIO_BAND_NUM_OF_BANDS; uIndex++) 662 { 663 pParam->content.eRadioBand = uIndex; 664 regulatoryDomain_getParam (pSme->hRegDomain, pParam); 665 bBandCountryFound[ uIndex ] = pParam->content.bIsCountryFound; 666 /* also nullify the channel exist indication for this band */ 667 bBandChannelExist[ uIndex ] = TI_FALSE; 668 } 669 os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t)); 670 671 /* First fill the channels */ 672 for (uIndex = 0; uIndex < pSme->tInitParams.uChannelNum; uIndex++) 673 { 674 /* for each channel, if country is found, set active scan */ 675 pSme->tScanParams.tChannels[ uIndex ].eBand = pSme->tInitParams.tChannelList[ uIndex ].eBand; 676 pSme->tScanParams.tChannels[ uIndex ].uChannel = pSme->tInitParams.tChannelList[ uIndex ].uChannel; 677 pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs = pSme->tInitParams.uMaxScanDuration; 678 pSme->tScanParams.tChannels[ uIndex ].uMinDwellTimeMs = pSme->tInitParams.uMinScanDuration; 679 pSme->tScanParams.tChannels[ uIndex ].uTxPowerLevelDbm = DEF_TX_POWER; 680 681 /* if 802.11d is disabled, or country is available for this band */ 682 if ((TI_FALSE == bDEnabled) || 683 (TI_TRUE == bBandCountryFound[ pSme->tInitParams.tChannelList[ uIndex ].eBand ])) 684 { 685 /* set active scan */ 686 pSme->tScanParams.tChannels[ uIndex ].eScanType = SCAN_TYPE_NORMAL_ACTIVE; 687 } 688 /* 802.11d is enabled and no country available */ 689 else 690 { 691 /* set passive scan */ 692 pSme->tScanParams.tChannels[ uIndex ].eScanType = SCAN_TYPE_NORMAL_PASSIVE; 693 694 /* 695 * in order to fined country set uMaxDwellTimeMs ( that at passive scan set the passiveScanDuration ) 696 * to significant value 697 */ 698 pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs = SCAN_CNCN_REGULATORY_DOMAIN_PASSIVE_DWELL_TIME_DEF; 699 } 700 /* mark that a channel exists for this band */ 701 bBandChannelExist[ pSme->tInitParams.tChannelList[ uIndex ].eBand ] = TI_TRUE; 702 } 703 /* set number of channels */ 704 pSme->tScanParams.uChannelNum = pSme->tInitParams.uChannelNum; 705 706 /* now, fill global parameters */ 707 pSme->tScanParams.uProbeRequestNum = pSme->tInitParams.uProbeReqNum; 708 pSme->tScanParams.iRssiThreshold = pSme->tInitParams.iRssiThreshold; 709 pSme->tScanParams.iSnrThreshold = pSme->tInitParams.iSnrThreshold; 710 pSme->tScanParams.bTerminateOnReport = TI_TRUE; 711 pSme->tScanParams.uFrameCountReportThreshold = 1; 712 713 /* 714 * if for at least one band country is known and scan is performed on this band - means we need to 715 * take into consideration country expiry, plus we are scanning for the desired SSID 716 */ 717 bCountryValid = ((TI_TRUE == bBandChannelExist[ RADIO_BAND_2_4_GHZ ]) && (TI_TRUE == bBandCountryFound[ RADIO_BAND_2_4_GHZ ])) || 718 ((TI_TRUE == bBandChannelExist[ RADIO_BAND_5_0_GHZ ]) && (TI_TRUE == bBandCountryFound[ RADIO_BAND_5_0_GHZ ])); 719 720 /* set SSID(s) and BSS type according to 802.11d status, and country availability */ 721 /* if 802.11d is disabled */ 722 if (TI_FALSE == bDEnabled) 723 { 724 pSme->tScanParams.eBssType = pSme->eBssType; 725 /* set the deisred SSID, or any SSID if this is the desired SSID */ 726 if (SSID_TYPE_ANY == pSme->eSsidType) 727 { 728 pSme->tScanParams.uSsidNum = 0; 729 pSme->tScanParams.uSsidListFilterEnabled = 1; 730 } 731 else 732 { 733 pSme->tScanParams.tDesiredSsid[ 0 ].eVisability = SCAN_SSID_VISABILITY_HIDDEN; 734 os_memoryCopy (pSme->hOS, &(pSme->tScanParams.tDesiredSsid[ 0 ].tSsid), &(pSme->tSsid), sizeof (TSsid)); 735 pSme->tScanParams.uSsidNum = 1; 736 pSme->tScanParams.uSsidListFilterEnabled = 1; 737 } 738 } 739 /* Country code exists and scan is performed on this band - take country expiry timr into account */ 740 else if (TI_TRUE == bCountryValid) 741 { 742 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_StartScan: performing active scan to find desired SSID\n"); 743 744 /* we already know that at least on one band we know the country IE, so we scan for our SSID */ 745 pSme->tScanParams.tDesiredSsid[ 0 ].eVisability = SCAN_SSID_VISABILITY_HIDDEN; 746 os_memoryCopy (pSme->hOS, &(pSme->tScanParams.tDesiredSsid[ 0 ].tSsid), &(pSme->tSsid), sizeof (TSsid)); 747 /* 748 * if, in addition, we scan the other band to find its country, and the desired SSDI is not any SSID, 749 * add an empty SSID 750 */ 751 if ((SSID_TYPE_ANY != pSme->eSsidType) && 752 (((TI_TRUE == bBandChannelExist[ RADIO_BAND_2_4_GHZ ]) && (TI_FALSE == bBandCountryFound[ RADIO_BAND_2_4_GHZ ])) || 753 ((TI_TRUE == bBandChannelExist[ RADIO_BAND_5_0_GHZ ]) && (TI_FALSE == bBandCountryFound[ RADIO_BAND_5_0_GHZ ])))) 754 { 755 pSme->tScanParams.tDesiredSsid[ 1 ].eVisability = SCAN_SSID_VISABILITY_PUBLIC; 756 pSme->tScanParams.tDesiredSsid[ 1 ].tSsid.len = 0; 757 pSme->tScanParams.uSsidNum = 2; 758 pSme->tScanParams.uSsidListFilterEnabled = 1; 759 /* 760 * since we are also looking for an AP with country IE (not include in IBSS), we need to make sure 761 * the desired BSS type include infrastructure BSSes. 762 */ 763 if (BSS_INDEPENDENT == pSme->eBssType) 764 { 765 /* the desired is only IBSS - scan for any */ 766 pSme->tScanParams.eBssType = BSS_ANY; 767 } 768 else 769 { 770 /* the desired is either infrastructure or any - use it */ 771 pSme->tScanParams.eBssType = pSme->eBssType; 772 } 773 } 774 else 775 { 776 pSme->tScanParams.uSsidNum = 1; 777 pSme->tScanParams.uSsidListFilterEnabled = 1; 778 /* only looking for the desired SSID - set the desired BSS type */ 779 pSme->tScanParams.eBssType = pSme->eBssType; 780 } 781 } 782 /* no scanned band has a counrty code - meaning all scan is passive (to find country) */ 783 else 784 { 785 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_StartScan: performing passive scan to find country IE\n"); 786 pSme->tScanParams.eBssType = BSS_INFRASTRUCTURE; /* only an AP would transmit a country IE */ 787 pSme->tScanParams.uSsidNum = 0; 788 pSme->tScanParams.uSsidListFilterEnabled = 1; 789 } 790 791 /* update scan cycle number and scan intervals according to 802.11d status and country availability */ 792 sme_updateScanCycles (hSme, bDEnabled, bCountryValid, pSme->bConstantScan); 793 794 /* Finally(!!!), start the scan */ 795 tStatus = scanCncn_StartPeriodicScan (pSme->hScanCncn, SCAN_SCC_DRIVER, &(pSme->tScanParams)); 796 if (SCAN_CRS_SCAN_RUNNING != tStatus) 797 { 798 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "sme_StartScan: scan concentrator returned status %d\n", tStatus); 799 return TI_NOK; 800 } 801 802 return TI_OK; 803 } 804 805 /** 806 * \fn sme_updateScanCycles 807 * \brief Updates the scan intervals and cycle number according to 802.11d status, country availability and WSC PB mode 808 * 809 * Updates the scan intervals and cycle number according to 802.11d status, country availability and WSC PB mode. 810 * Possible scenarios - D disabled - WSC PB off - scan forever with supplied intervals 811 * - D enabled - country unknown - WSC PB off - scan forever with supplied intervals 812 * - D disabled - WSC PB on - scan for two minutes with zero intervals 813 * - D enabled - country unknown - WSC PB on - scan for two minutes with zero intervals 814 * - D enabled - country known - WSC PB off - scan until country expiry with supplied intervals 815 * - D enabled - country known - WSC PB on - scan for the minimu of two minutes and country expiry with zero intervals 816 * 817 * \param hSme - handle to the SME object 818 * \param bDEnabled - TRUE if 802.11d is enabled 819 * \param bCountryValid - TRUE if a country IE is valid for a band on which we scan 820 * \param bConstantScan - TRUE if WSC PB mode is on 821 * \return None 822 * \sa sme_CalculateCyclesNumber, sme_StartScan 823 */ 824 void sme_updateScanCycles (TI_HANDLE hSme, 825 TI_BOOL bDEnabled, 826 TI_BOOL bCountryValid, 827 TI_BOOL bConstantScan) 828 { 829 TSme *pSme = (TSme*)hSme; 830 TI_UINT32 uIndex, uScanPeriodMs, uScanDurationMs; 831 paramInfo_t *pParam; 832 833 /* 802.11d is disabled, or no country is valid */ 834 if ((TI_FALSE == bDEnabled) || (TI_FALSE == bCountryValid)) 835 { 836 /* WSC PB mode is disabled */ 837 if (TI_FALSE == bConstantScan) 838 { 839 /* 840 * copy intervals 841 * In order to avoid tight loop of scan-select or scan-select-connecting operation, 842 * the prepare scan function takes into account the value of the scan_count when setting the 16 periods in the scan command 843 */ 844 os_memoryCopy (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]), 845 &(pSme->tInitParams.uScanIntervals[ pSme->uScanCount ]), sizeof (TI_UINT32) * (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount)); 846 847 for(uIndex = (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount); uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM; uIndex++) 848 { 849 pSme->tScanParams.uCycleIntervalMsec[ uIndex ] = pSme->tInitParams.uScanIntervals[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1 ]; 850 } 851 852 /* scan for default number (until a result is found) */ 853 pSme->tScanParams.uCycleNum = pSme->tInitParams.uCycleNum; 854 } 855 /* WSC PB mode is enabled */ 856 else 857 { 858 /* turn off WSC PB mode (for next scan) */ 859 pSme->bConstantScan = TI_FALSE; 860 861 /* nullify all intervals */ 862 os_memoryZero (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]), 863 sizeof (TI_UINT32) * PERIODIC_SCAN_MAX_INTERVAL_NUM); 864 865 /* calculate the duration of one scan cycle */ 866 uScanDurationMs = 0; 867 for (uIndex = 0; uIndex < pSme->tScanParams.uChannelNum; uIndex++) 868 { 869 uScanDurationMs += pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs; 870 } 871 872 /* set the number of cycles - 2 minutes divided by one cycle duration */ 873 pSme->tScanParams.uCycleNum = (120000 / uScanDurationMs) + 1; 874 } 875 } 876 /* 802.11d is enabled, and country is valid on at least one band */ 877 else 878 { 879 pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t)); 880 if (!pParam) 881 return; 882 883 /* get country expiry time */ 884 pParam->paramType = REGULATORY_DOMAIN_TIME_TO_COUNTRY_EXPIRY; 885 regulatoryDomain_getParam (pSme->hRegDomain, pParam); 886 887 /* WSC PB mode is disabled */ 888 if (TI_FALSE == bConstantScan) 889 { 890 /* 891 * copy intervals 892 * In order to avoid tight loop of scan-select or scan-select-connecting operation, 893 * the prepare scan function takes into account the value of the scan_count when setting the 16 periods in the scan command 894 */ 895 os_memoryCopy (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]), 896 &(pSme->tInitParams.uScanIntervals[ pSme->uScanCount ]), sizeof (TI_UINT32) * (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount)); 897 898 for(uIndex = (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount); uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM; uIndex++) 899 { 900 pSme->tScanParams.uCycleIntervalMsec[ uIndex ] = pSme->tInitParams.uScanIntervals[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1 ]; 901 } 902 903 /* set cycle number according to country expiry time */ 904 sme_CalculateCyclesNumber (hSme, pParam->content.uTimeToCountryExpiryMs); 905 } 906 /* WSC PB mode is enabled */ 907 else 908 { 909 /* turn off WSC PB mode (for next scan) */ 910 pSme->bConstantScan = TI_FALSE; 911 912 /* set scan period to minimum of WSC PB duration (2 minutes) and country expiry time */ 913 uScanPeriodMs = TI_MIN (120000, pParam->content.uTimeToCountryExpiryMs); 914 915 /* nullify all intervals */ 916 os_memoryZero (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]), 917 sizeof (TI_UINT32) * PERIODIC_SCAN_MAX_INTERVAL_NUM); 918 919 /* calculate the duration of one scan cycle */ 920 uScanDurationMs = 0; 921 for (uIndex = 0; uIndex < pSme->tScanParams.uChannelNum; uIndex++) 922 { 923 uScanDurationMs += pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs; 924 } 925 926 if (uScanDurationMs != 0) 927 { 928 /* set the number of cycles - scan period divided by one cycle duration */ 929 pSme->tScanParams.uCycleNum = (uScanPeriodMs / uScanDurationMs) + 1; 930 } 931 else 932 { 933 pSme->tScanParams.uCycleNum = pSme->tInitParams.uCycleNum; 934 } 935 } 936 os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t)); 937 } 938 939 /* in case independent mode and to avoid supplicant send disconnect event after 60s */ 940 if (pSme->eBssType != BSS_INFRASTRUCTURE) 941 { 942 pSme->tScanParams.uCycleNum = 1; 943 } 944 } 945 946 /** 947 * \fn sme_CalculateCyclesNumber 948 * \brief Calculates the cycle number required for a gicen time, according to scan intervals 949 * 950 * Calculates the cycle number required for a gicen time, according to scan intervals. First check the 16 951 * different intervals, and if more time is available, find how many cycles still fit. Write the result 952 * to the SME scan command 953 * 954 * \param hSme - handle to the SME object 955 * \param uToTalTimeMs - the total periodic scan operation duartion 956 * \return None 957 * \sa sme_updateScanCycles, sme_StartScan 958 */ 959 void sme_CalculateCyclesNumber (TI_HANDLE hSme, TI_UINT32 uTotalTimeMs) 960 { 961 TSme *pSme = (TSme*)hSme; 962 TI_UINT32 uIndex, uCurrentTimeMs = 0; 963 964 /* 965 * the total time should exceed country code expiration by one interval (so that next scan wouldn't 966 * have a valid country code) 967 */ 968 969 /* nullify cycle number */ 970 pSme->tScanParams.uCycleNum = 0; 971 /* now find how many cycles fit within this time. First, check if all first 16 configured intervals fit */ 972 for (uIndex = 0; 973 (uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM) && (uCurrentTimeMs < uTotalTimeMs); 974 uIndex++) 975 { 976 pSme->tScanParams.uCycleNum++; 977 uCurrentTimeMs += pSme->tScanParams.uCycleIntervalMsec[ uIndex ]; 978 } 979 /* now find out how many more cycles with the last interval still fits */ 980 if (uCurrentTimeMs < uTotalTimeMs) 981 { 982 /* 983 * divide the reamining time (time until expiry minus the total time calculated so far) 984 * by the last interval time, to get how many more scans would fit after the first 16 intervals 985 */ 986 pSme->tScanParams.uCycleNum += (uTotalTimeMs - uCurrentTimeMs) / 987 pSme->tScanParams.uCycleIntervalMsec[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1]; 988 /* and add one, to compensate for the reminder */ 989 pSme->tScanParams.uCycleNum++; 990 } 991 } 992 993