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