| /* |
| * smeSm.c |
| * |
| * Copyright(c) 1998 - 2010 Texas Instruments. All rights reserved. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name Texas Instruments nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /** \file smeSm.c |
| * \brief SME state machine implementation |
| * |
| * \see smeSm.h, sme.c, sme.h |
| */ |
| |
| |
| #define __FILE_ID__ FILE_ID_43 |
| #include "GenSM.h" |
| #include "smeSm.h" |
| #include "smePrivate.h" |
| #include "connApi.h" |
| #include "apConn.h" |
| #include "ScanCncn.h" |
| #include "scanResultTable.h" |
| #include "EvHandler.h" |
| #include "regulatoryDomainApi.h" |
| #include "siteMgrApi.h" |
| #include "DrvMain.h" |
| |
| |
| static OS_802_11_DISASSOCIATE_REASON_E eDisassocConvertTable[ MGMT_STATUS_MAX_NUM +1] = |
| { |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_AUTH_REJECT, |
| OS_DISASSOC_STATUS_ASSOC_REJECT, |
| OS_DISASSOC_STATUS_SECURITY_FAILURE, |
| OS_DISASSOC_STATUS_AP_DEAUTHENTICATE, |
| OS_DISASSOC_STATUS_AP_DISASSOCIATE, |
| OS_DISASSOC_STATUS_ROAMING_TRIGGER, |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_UNSPECIFIED, |
| OS_DISASSOC_STATUS_UNSPECIFIED |
| }; |
| |
| #define SME_CONVERT_DISASSOC_CODES(disassocReason) (eDisassocConvertTable[ (disassocReason) ]) |
| |
| static void smeSm_Start (TI_HANDLE hSme); |
| static void smeSm_Stop (TI_HANDLE hSme); |
| static void smeSm_PreConnect (TI_HANDLE hSme); |
| static void smeSm_Connect (TI_HANDLE hSme); |
| static void smeSm_ConnectSuccess (TI_HANDLE hSme); |
| static void smeSm_Disconnect (TI_HANDLE hSme); |
| static void smeSm_DisconnectDone (TI_HANDLE hSme); |
| static void smeSm_StopScan (TI_HANDLE hSme); |
| static void smeSm_StopConnect (TI_HANDLE hSme); |
| static void smeSm_ConnWhenConnecting (TI_HANDLE hSme); |
| static void smeSm_ActionUnexpected (TI_HANDLE hSme); |
| static void smeSm_NopAction (TI_HANDLE hSme); |
| static void smeSm_CheckStartConditions (TI_HANDLE hSme); |
| |
| static TI_STATUS sme_StartScan (TI_HANDLE hSme); |
| static void sme_updateScanCycles (TI_HANDLE hSme, |
| TI_BOOL bDEnabled, |
| TI_BOOL bCountryValid, |
| TI_BOOL bConstantScan); |
| static void sme_CalculateCyclesNumber (TI_HANDLE hSme, TI_UINT32 uTotalTimeMs); |
| |
| TGenSM_actionCell tSmMatrix[ SME_SM_NUMBER_OF_STATES ][ SME_SM_NUMBER_OF_EVENTS ] = |
| { |
| { /* SME_SM_STATE_IDLE */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_Start }, /* SME_SM_EVENT_START */ |
| { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_STOP */ |
| { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */ |
| { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ |
| { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_FAILURE */ |
| { SME_SM_STATE_IDLE, smeSm_CheckStartConditions }, /* SME_SM_EVENT_DISCONNECT */ |
| }, |
| { /* SME_SM_STATE_WAIT_CONNECT */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ |
| { SME_SM_STATE_IDLE, smeSm_Stop }, /* SME_SM_EVENT_STOP */ |
| { SME_SM_STATE_SCANNING, smeSm_PreConnect }, /* SME_SM_EVENT_CONNECT */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_FAILURE */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_Start }, /* SME_SM_EVENT_DISCONNECT */ |
| }, |
| { /* SME_SM_STATE_SCANNING */ |
| { SME_SM_STATE_SCANNING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_StopScan }, /* SME_SM_EVENT_STOP */ |
| { SME_SM_STATE_CONNECTING, smeSm_Connect }, /* SME_SM_EVENT_CONNECT */ |
| { SME_SM_STATE_SCANNING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_StopScan }, /* SME_SM_EVENT_DISCONNECT */ |
| }, |
| { /* SME_SM_STATE_CONNECTING */ |
| { SME_SM_STATE_CONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_StopConnect }, /* SME_SM_EVENT_STOP */ |
| { SME_SM_STATE_CONNECTING, smeSm_ConnWhenConnecting }, /* SME_SM_EVENT_CONNECT */ |
| { SME_SM_STATE_CONNECTED, smeSm_ConnectSuccess }, /* SME_SM_EVENT_CONNECT_SUCCESS */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_StopConnect }, /* SME_SM_EVENT_DISCONNECT */ |
| }, |
| { /* SME_SM_STATE_CONNECTED */ |
| { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_Disconnect }, /* SME_SM_EVENT_STOP */ |
| { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */ |
| { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_Disconnect }, /* SME_SM_EVENT_DISCONNECT */ |
| }, |
| { /* SME_SM_STATE_DISCONNECTING */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_STOP */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */ |
| { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */ |
| { SME_SM_STATE_DISCONNECTING, smeSm_NopAction }, /* SME_SM_EVENT_DISCONNECT */ |
| } |
| }; |
| |
| TI_INT8* uStateDescription[] = |
| { |
| "IDLE", |
| "WAIT_CONNECT", |
| "SCANNING", |
| "CONNECTING", |
| "CONNECTED", |
| "DISCONNECTING" |
| }; |
| |
| TI_INT8* uEventDescription[] = |
| { |
| "START", |
| "STOP", |
| "CONNECT", |
| "CONNECT_SUCCESS", |
| "CONNECT_FAILURE", |
| "DISCONNECT" |
| }; |
| |
| /** |
| * \fn smeSm_Start |
| * \brief Starts STA opeartion by moving SCR out of idle group and starting connection process |
| * |
| * Starts STA opeartion by moving SCR out of idle group and starting connection process |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_Stop, sme_start |
| */ |
| void smeSm_Start (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| |
| /* set SCR group according to connection mode */ |
| if (CONNECT_MODE_AUTO == pSme->eConnectMode) |
| { |
| TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_Start: changing SCR group to DRV scan\n"); |
| scr_setGroup (pSme->hScr, SCR_GID_DRV_SCAN); |
| } |
| else |
| { |
| TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_Start: changing SCR group to APP scan\n"); |
| scr_setGroup (pSme->hScr, SCR_GID_APP_SCAN); |
| } |
| |
| if ((TI_FALSE == pSme->bRadioOn) || (TI_FALSE == pSme->bRunning)) |
| { |
| /* Radio is off so send stop event */ |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_STOP, hSme); |
| } |
| else if (TI_TRUE == pSme->bConnectRequired) |
| { |
| /* if connection was required, start the process */ |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme); |
| } |
| } |
| |
| /** |
| * \fn smeSm_Stop |
| * \brief Turns off the STA |
| * |
| * Turns off the STA by moving the SCr to idle |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_Start, sme_Stop |
| */ |
| void smeSm_Stop (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| |
| /* set SCR group to idle */ |
| scr_setGroup (pSme->hScr, SCR_GID_IDLE); |
| |
| if (TI_FALSE == pSme->bRunning) |
| { |
| /* call DrvMain */ |
| drvMain_SmeStop (pSme->hDrvMain); |
| } |
| } |
| |
| /** |
| * \fn smeSm_PreConnect |
| * \brief Initiates the connection process |
| * |
| * Initiates the connection process - for automatic mode, start scan, for manual mode - triggers connection |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_Connect, smeSm_ConnectSuccess |
| */ |
| void smeSm_PreConnect (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme *)hSme; |
| paramInfo_t *pParam; |
| |
| /* set the connection mode with which this connection attempt is starting */ |
| pSme->eLastConnectMode = pSme->eConnectMode; |
| |
| /* mark that no authentication/assocaition was yet sent */ |
| pSme->bAuthSent = TI_FALSE; |
| |
| /* try to find a connection candidate (manual mode have already performed scann */ |
| pSme->pCandidate = sme_Select (hSme); |
| if (NULL != pSme->pCandidate) |
| { |
| /* candidate is available - attempt connection */ |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme); |
| } |
| /* no candidate */ |
| else |
| { |
| if (CONNECT_MODE_AUTO == pSme->eConnectMode) |
| { |
| /* automatic mode - start scanning */ |
| if (TI_OK != sme_StartScan (hSme)) |
| { |
| TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_PreConnect: unable to start scan, stopping the SME\n"); |
| pSme->bRadioOn = TI_FALSE; |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); |
| } |
| |
| /* update scan count counter */ |
| if(pSme->uScanCount < PERIODIC_SCAN_MAX_INTERVAL_NUM) |
| { |
| pSme->uScanCount++; |
| } |
| |
| } |
| else /* Manual mode */ |
| { |
| /* for IBSS or any, if no entries where found, add the self site */ |
| if (pSme->eBssType == BSS_INFRASTRUCTURE) |
| { |
| /* makr whether we need to stop the attempt connection in manual mode */ |
| pSme->bConnectRequired = TI_FALSE; |
| |
| TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_PreConnect: No candidate available, sending connect failure\n"); |
| /* manual mode and no connection candidate is available - connection failed */ |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); |
| } |
| |
| else /* IBSS */ |
| { |
| TI_UINT8 uDesiredChannel; |
| TI_BOOL channelValidity; |
| |
| pSme->bConnectRequired = TI_FALSE; |
| |
| pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t)); |
| if (!pParam) |
| { |
| return; |
| } |
| |
| pParam->paramType = SITE_MGR_DESIRED_CHANNEL_PARAM; |
| siteMgr_getParam(pSme->hSiteMgr, pParam); |
| uDesiredChannel = pParam->content.siteMgrDesiredChannel; |
| |
| if (uDesiredChannel >= SITE_MGR_CHANNEL_A_MIN) |
| { |
| pParam->content.channelCapabilityReq.band = RADIO_BAND_5_0_GHZ; |
| } |
| else |
| { |
| pParam->content.channelCapabilityReq.band = RADIO_BAND_2_4_GHZ; |
| } |
| |
| /* |
| update the regulatory domain with the selected band |
| */ |
| /* Check if the selected channel is valid according to regDomain */ |
| pParam->paramType = REGULATORY_DOMAIN_GET_SCAN_CAPABILITIES; |
| pParam->content.channelCapabilityReq.scanOption = ACTIVE_SCANNING; |
| pParam->content.channelCapabilityReq.channelNum = uDesiredChannel; |
| |
| regulatoryDomain_getParam (pSme->hRegDomain, pParam); |
| channelValidity = pParam->content.channelCapabilityRet.channelValidity; |
| os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t)); |
| if (!channelValidity) |
| { |
| TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "IBSS SELECT FAILURE - No channel !!!\n\n"); |
| |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); |
| |
| return; |
| } |
| |
| pSme->pCandidate = (TSiteEntry *)addSelfSite(pSme->hSiteMgr); |
| |
| if (pSme->pCandidate == NULL) |
| { |
| TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "IBSS SELECT FAILURE - could not open self site !!!\n\n"); |
| |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); |
| |
| return; |
| } |
| |
| #ifdef REPORT_LOG |
| 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]); |
| 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])); |
| #endif |
| /* a connection candidate is available, send a connect event */ |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme); |
| } |
| } |
| } |
| } |
| |
| /** |
| * \fn smeSm_Connect |
| * \brief Starts a connection process with the selected network |
| * |
| * Starts a connection process with the selected network |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_PreConnect, smeSm_ConnectSuccess |
| */ |
| void smeSm_Connect (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| TI_STATUS tStatus; |
| paramInfo_t *pParam; |
| |
| /* Sanity check - if no connection candidate was found so far */ |
| if (NULL == pSme->pCandidate) |
| { |
| TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Connect: No candidate available, sending connect failure\n"); |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme); |
| } |
| else |
| { |
| pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t)); |
| if (!pParam) |
| { |
| return; |
| } |
| |
| /* set SCR group */ |
| if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType) |
| { |
| scr_setGroup (pSme->hScr, SCR_GID_CONNECT); |
| } |
| |
| /***************** Config Connection *************************/ |
| pParam->paramType = CONN_TYPE_PARAM; |
| if (BSS_INDEPENDENT == pSme->pCandidate->bssType) |
| if (SITE_SELF == pSme->pCandidate->siteType) |
| { |
| pParam->content.connType = CONNECTION_SELF; |
| } |
| else |
| { |
| pParam->content.connType = CONNECTION_IBSS; |
| } |
| else |
| pParam->content.connType = CONNECTION_INFRA; |
| conn_setParam(pSme->hConn, pParam); |
| os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t)); |
| |
| /* start the connection process */ |
| tStatus = conn_start (pSme->hConn, CONN_TYPE_FIRST_CONN, sme_ReportConnStatus, hSme, TI_FALSE, TI_FALSE); |
| if (TI_OK != tStatus) |
| { |
| TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Connect: conn_start returned status %d\n", tStatus); |
| } |
| } |
| } |
| |
| /** |
| * \fn smeSm_ConnectSuccess |
| * \brief Handles connection success indication |
| * |
| * Handles connection success indication - starts AP conn and set SCR group to connected |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_PreConnect, smeSm_Connect |
| */ |
| void smeSm_ConnectSuccess (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| |
| pSme->uScanCount = 0; |
| |
| /* connection succedded to the connection candidate - start AP connection */ |
| if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType) |
| { |
| /* Start the AP connection */ |
| apConn_start (pSme->hApConn, |
| (pSme->tSsid.len != 0) && !OS_802_11_SSID_JUNK (pSme->tSsid.str, pSme->tSsid.len)); |
| } |
| |
| /* Set SCR group to connected */ |
| scr_setGroup (pSme->hScr, SCR_GID_CONNECTED); |
| } |
| |
| /** |
| * \fn smeSm_Disconnect |
| * \brief Starts a disconnect by calling the AP connection or connect modules |
| * |
| * Starts a disconnect by calling the AP connection or connect modules |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_DisconnectDone |
| */ |
| void smeSm_Disconnect (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| TI_STATUS tStatus; |
| |
| /* set the SCr group to connecting */ |
| scr_setGroup (pSme->hScr, SCR_GID_CONNECT); |
| |
| if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType) |
| { |
| /* Call the AP connection to perform disconnect */ |
| tStatus = apConn_stop (pSme->hApConn, TI_TRUE); |
| } |
| else |
| { |
| /* In IBSS disconnect is done directly with the connection SM */ |
| tStatus = conn_stop(pSme->hConn, DISCONNECT_DE_AUTH, STATUS_UNSPECIFIED, |
| TI_TRUE, sme_ReportConnStatus, hSme); |
| if (tStatus != TI_OK) |
| { |
| TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Disconnect: conn_stop retruned %d\n", tStatus); |
| } |
| } |
| } |
| |
| /** |
| * \fn smeSm_DisconnectDone |
| * \brief Finish a disconnect process |
| * |
| * Finish a disconnect process by sending the appropriate event and restarting the state-machine |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_Disconnect |
| */ |
| void smeSm_DisconnectDone (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| OS_802_11_DISASSOCIATE_REASON_T tEventReason; |
| |
| if (TI_FALSE == pSme->bReselect) |
| { |
| /* send an event notifying the disassocation */ |
| if (TI_TRUE == pSme->bAuthSent) |
| { |
| tEventReason.eDisAssocType = SME_CONVERT_DISASSOC_CODES (pSme->tDisAssoc.eMgmtStatus); |
| tEventReason.uStatusCode = pSme->tDisAssoc.uStatusCode; |
| EvHandlerSendEvent (pSme->hEvHandler, IPC_EVENT_DISASSOCIATED, (TI_UINT8*)&tEventReason, |
| sizeof(OS_802_11_DISASSOCIATE_REASON_T)); |
| } |
| else if (CONNECT_MODE_AUTO != pSme->eLastConnectMode) |
| { |
| EvHandlerSendEvent (pSme->hEvHandler, IPC_EVENT_NOT_ASSOCIATED, NULL, 0); |
| } |
| } |
| |
| siteMgr_disSelectSite (pSme->hSiteMgr); |
| |
| /* try to reconnect */ |
| smeSm_Start (hSme); |
| } |
| |
| /** |
| * \fn smeSm_StopScan |
| * \brief Stops the SME scan operation |
| * |
| * Stops the SME scan operation |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_PreConnect, sme_StartScan |
| */ |
| void smeSm_StopScan (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| |
| scanCncn_StopPeriodicScan (pSme->hScanCncn, SCAN_SCC_DRIVER); |
| } |
| |
| /** |
| * \fn smeSm_StopConnect |
| * \brief Stops the connect module |
| * |
| * Stops the connect module (if the SME is stopped during a connect attempt |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_Connect |
| */ |
| void smeSm_StopConnect (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| TI_STATUS tStatus; |
| |
| tStatus = conn_stop (pSme->hConn, DISCONNECT_DE_AUTH, STATUS_UNSPECIFIED, |
| TI_TRUE, sme_ReportConnStatus, hSme); |
| |
| if (TI_OK != tStatus) |
| { |
| TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_StopConnect: conn_stop returned status %d\n", tStatus); |
| } |
| } |
| |
| /** |
| * \fn smeSm_ConnWhenConnecting |
| * \brief Starts the connect process again |
| * |
| * Starts the connect process again |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| * \sa smeSm_Connect |
| */ |
| void smeSm_ConnWhenConnecting (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| TI_STATUS tStatus; |
| |
| /* start the connection process */ |
| tStatus = conn_start (pSme->hConn, CONN_TYPE_FIRST_CONN, sme_ReportConnStatus, hSme, TI_FALSE, TI_FALSE); |
| if (TI_OK != tStatus) |
| { |
| TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_ConnWhenConnecting: conn_start returned status %d\n", tStatus); |
| } |
| } |
| |
| /** |
| * \fn smeSm_ActionUnexpected |
| * \brief Called when an unexpected event (for current state) is received |
| * |
| * Called when an unexpected event (for current state) is received |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| */ |
| void smeSm_ActionUnexpected (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| |
| TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_ActionUnexpected called\n"); |
| } |
| |
| /** |
| * \fn smeSm_NopAction |
| * \brief Called when event call and don't need to do nothing. |
| * |
| * \param hSme - handle to the SME object |
| * \return None |
| */ |
| void smeSm_NopAction (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| |
| TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_NopAction called\n"); |
| } |
| |
| void smeSm_CheckStartConditions (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| |
| if ((TI_TRUE == pSme->bRunning) && (TI_TRUE == pSme->bRadioOn)) |
| { |
| /* send a start event */ |
| sme_SmEvent (pSme->hSmeSm, SME_SM_EVENT_START, hSme); |
| } |
| } |
| |
| |
| /* do we need to verify G only / A only / dual-band with site mgr? or rely on channels only? */ |
| |
| /** |
| * \fn sme_StartScan |
| * \brief Set scan parameters and calls scan concnetartor to start the scan operation. |
| * |
| * Set scan parameters and calls scan concnetartor to start the scan operation. |
| * |
| * Scan parameters are set according to scan target - find country IE, find desired SSID, or both |
| * (one on each band). To find country IE we use passive scan forever, to find the desired SSID we |
| * use active scan until the current country IE expires. In addition, we take into account the WSC PB |
| * mode - scan constantly for two minutes (but under the country validity and expiry constraints) |
| * |
| * \param hSme - handle to the SME object |
| * \return TI_OK if scan started successfully, TI_NOK otherwise |
| * \sa smeSm_PreConnect |
| */ |
| TI_STATUS sme_StartScan (TI_HANDLE hSme) |
| { |
| TSme *pSme = (TSme*)hSme; |
| paramInfo_t *pParam; |
| TI_BOOL bDEnabled, bCountryValid; |
| TI_BOOL bBandChannelExist[ RADIO_BAND_NUM_OF_BANDS ]; |
| TI_BOOL bBandCountryFound[ RADIO_BAND_NUM_OF_BANDS ]; |
| TI_STATUS tStatus; |
| TI_UINT32 uIndex; |
| |
| /* get 802.11d enable state */ |
| pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t)); |
| if (!pParam) |
| { |
| return TI_NOK; |
| } |
| |
| pParam->paramType = REGULATORY_DOMAIN_ENABLED_PARAM; |
| regulatoryDomain_getParam (pSme->hRegDomain, pParam); |
| bDEnabled = pParam->content.regulatoryDomainEnabled; |
| |
| pParam->paramType = REGULATORY_DOMAIN_IS_COUNTRY_FOUND; |
| /* get country validity for all bands */ |
| for (uIndex = 0; uIndex < RADIO_BAND_NUM_OF_BANDS; uIndex++) |
| { |
| pParam->content.eRadioBand = (ERadioBand)uIndex; |
| regulatoryDomain_getParam (pSme->hRegDomain, pParam); |
| bBandCountryFound[ uIndex ] = pParam->content.bIsCountryFound; |
| /* also nullify the channel exist indication for this band */ |
| bBandChannelExist[ uIndex ] = TI_FALSE; |
| } |
| os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t)); |
| |
| /* First fill the channels */ |
| for (uIndex = 0; uIndex < pSme->tInitParams.uChannelNum; uIndex++) |
| { |
| /* for each channel, if country is found, set active scan */ |
| pSme->tScanParams.tChannels[ uIndex ].eBand = pSme->tInitParams.tChannelList[ uIndex ].eBand; |
| pSme->tScanParams.tChannels[ uIndex ].uChannel = pSme->tInitParams.tChannelList[ uIndex ].uChannel; |
| pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs = pSme->tInitParams.uMaxScanDuration; |
| pSme->tScanParams.tChannels[ uIndex ].uMinDwellTimeMs = pSme->tInitParams.uMinScanDuration; |
| pSme->tScanParams.tChannels[ uIndex ].uTxPowerLevelDbm = DEF_TX_POWER; |
| |
| /* if 802.11d is disabled, or country is available for this band */ |
| if ((TI_FALSE == bDEnabled) || |
| (TI_TRUE == bBandCountryFound[ pSme->tInitParams.tChannelList[ uIndex ].eBand ])) |
| { |
| /* set active scan */ |
| pSme->tScanParams.tChannels[ uIndex ].eScanType = SCAN_TYPE_NORMAL_ACTIVE; |
| } |
| /* 802.11d is enabled and no country available */ |
| else |
| { |
| /* set passive scan */ |
| pSme->tScanParams.tChannels[ uIndex ].eScanType = SCAN_TYPE_NORMAL_PASSIVE; |
| |
| /* |
| * in order to fined country set uMaxDwellTimeMs ( that at passive scan set the passiveScanDuration ) |
| * to significant value |
| */ |
| pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs = SCAN_CNCN_REGULATORY_DOMAIN_PASSIVE_DWELL_TIME_DEF; |
| } |
| /* mark that a channel exists for this band */ |
| bBandChannelExist[ pSme->tInitParams.tChannelList[ uIndex ].eBand ] = TI_TRUE; |
| } |
| /* set number of channels */ |
| pSme->tScanParams.uChannelNum = pSme->tInitParams.uChannelNum; |
| |
| /* now, fill global parameters */ |
| pSme->tScanParams.uProbeRequestNum = pSme->tInitParams.uProbeReqNum; |
| pSme->tScanParams.iRssiThreshold = pSme->tInitParams.iRssiThreshold; |
| pSme->tScanParams.iSnrThreshold = pSme->tInitParams.iSnrThreshold; |
| pSme->tScanParams.bTerminateOnReport = TI_TRUE; |
| pSme->tScanParams.uFrameCountReportThreshold = 1; |
| |
| /* |
| * if for at least one band country is known and scan is performed on this band - means we need to |
| * take into consideration country expiry, plus we are scanning for the desired SSID |
| */ |
| bCountryValid = ((TI_TRUE == bBandChannelExist[ RADIO_BAND_2_4_GHZ ]) && (TI_TRUE == bBandCountryFound[ RADIO_BAND_2_4_GHZ ])) || |
| ((TI_TRUE == bBandChannelExist[ RADIO_BAND_5_0_GHZ ]) && (TI_TRUE == bBandCountryFound[ RADIO_BAND_5_0_GHZ ])); |
| |
| /* set SSID(s) and BSS type according to 802.11d status, and country availability */ |
| /* if 802.11d is disabled */ |
| if (TI_FALSE == bDEnabled) |
| { |
| pSme->tScanParams.eBssType = pSme->eBssType; |
| /* set the deisred SSID, or any SSID if this is the desired SSID */ |
| if (SSID_TYPE_ANY == pSme->eSsidType) |
| { |
| pSme->tScanParams.uSsidNum = 0; |
| pSme->tScanParams.uSsidListFilterEnabled = 1; |
| } |
| else |
| { |
| pSme->tScanParams.tDesiredSsid[ 0 ].eVisability = SCAN_SSID_VISABILITY_HIDDEN; |
| os_memoryCopy (pSme->hOS, &(pSme->tScanParams.tDesiredSsid[ 0 ].tSsid), &(pSme->tSsid), sizeof (TSsid)); |
| pSme->tScanParams.uSsidNum = 1; |
| pSme->tScanParams.uSsidListFilterEnabled = 1; |
| |
| #ifdef XCC_MODULE_INCLUDED |
| pSme->tScanParams.uSsidListFilterEnabled = (TI_UINT8)TI_FALSE; |
| pSme->tScanParams.uSsidNum = 2; |
| pSme->tScanParams.tDesiredSsid[ 1 ].tSsid.len = 0; |
| pSme->tScanParams.tDesiredSsid[ 1 ].eVisability = SCAN_SSID_VISABILITY_PUBLIC; |
| #endif |
| |
| } |
| } |
| /* Country code exists and scan is performed on this band - take country expiry timr into account */ |
| else if (TI_TRUE == bCountryValid) |
| { |
| TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_StartScan: performing active scan to find desired SSID\n"); |
| |
| /* we already know that at least on one band we know the country IE, so we scan for our SSID */ |
| pSme->tScanParams.tDesiredSsid[ 0 ].eVisability = SCAN_SSID_VISABILITY_HIDDEN; |
| os_memoryCopy (pSme->hOS, &(pSme->tScanParams.tDesiredSsid[ 0 ].tSsid), &(pSme->tSsid), sizeof (TSsid)); |
| /* |
| * if, in addition, we scan the other band to find its country, and the desired SSDI is not any SSID, |
| * add an empty SSID |
| */ |
| if ((SSID_TYPE_ANY != pSme->eSsidType) && |
| (((TI_TRUE == bBandChannelExist[ RADIO_BAND_2_4_GHZ ]) && (TI_FALSE == bBandCountryFound[ RADIO_BAND_2_4_GHZ ])) || |
| ((TI_TRUE == bBandChannelExist[ RADIO_BAND_5_0_GHZ ]) && (TI_FALSE == bBandCountryFound[ RADIO_BAND_5_0_GHZ ])))) |
| { |
| pSme->tScanParams.tDesiredSsid[ 1 ].eVisability = SCAN_SSID_VISABILITY_PUBLIC; |
| pSme->tScanParams.tDesiredSsid[ 1 ].tSsid.len = 0; |
| pSme->tScanParams.uSsidNum = 2; |
| pSme->tScanParams.uSsidListFilterEnabled = 1; |
| /* |
| * since we are also looking for an AP with country IE (not include in IBSS), we need to make sure |
| * the desired BSS type include infrastructure BSSes. |
| */ |
| if (BSS_INDEPENDENT == pSme->eBssType) |
| { |
| /* the desired is only IBSS - scan for any */ |
| pSme->tScanParams.eBssType = BSS_ANY; |
| } |
| else |
| { |
| /* the desired is either infrastructure or any - use it */ |
| pSme->tScanParams.eBssType = pSme->eBssType; |
| } |
| } |
| else |
| { |
| pSme->tScanParams.uSsidNum = 1; |
| pSme->tScanParams.uSsidListFilterEnabled = 1; |
| /* only looking for the desired SSID - set the desired BSS type */ |
| pSme->tScanParams.eBssType = pSme->eBssType; |
| } |
| } |
| /* no scanned band has a counrty code - meaning all scan is passive (to find country) */ |
| else |
| { |
| TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_StartScan: performing passive scan to find country IE\n"); |
| pSme->tScanParams.eBssType = BSS_INFRASTRUCTURE; /* only an AP would transmit a country IE */ |
| pSme->tScanParams.uSsidNum = 0; |
| pSme->tScanParams.uSsidListFilterEnabled = 1; |
| } |
| |
| /* update scan cycle number and scan intervals according to 802.11d status and country availability */ |
| sme_updateScanCycles (hSme, bDEnabled, bCountryValid, pSme->bConstantScan); |
| |
| /* Finally(!!!), start the scan */ |
| tStatus = scanCncn_StartPeriodicScan (pSme->hScanCncn, SCAN_SCC_DRIVER, &(pSme->tScanParams)); |
| if (SCAN_CRS_SCAN_RUNNING != tStatus) |
| { |
| TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "sme_StartScan: scan concentrator returned status %d\n", tStatus); |
| return TI_NOK; |
| } |
| |
| return TI_OK; |
| } |
| |
| /** |
| * \fn sme_updateScanCycles |
| * \brief Updates the scan intervals and cycle number according to 802.11d status, country availability and WSC PB mode |
| * |
| * Updates the scan intervals and cycle number according to 802.11d status, country availability and WSC PB mode. |
| * Possible scenarios - D disabled - WSC PB off - scan forever with supplied intervals |
| * - D enabled - country unknown - WSC PB off - scan forever with supplied intervals |
| * - D disabled - WSC PB on - scan for two minutes with zero intervals |
| * - D enabled - country unknown - WSC PB on - scan for two minutes with zero intervals |
| * - D enabled - country known - WSC PB off - scan until country expiry with supplied intervals |
| * - D enabled - country known - WSC PB on - scan for the minimu of two minutes and country expiry with zero intervals |
| * |
| * \param hSme - handle to the SME object |
| * \param bDEnabled - TRUE if 802.11d is enabled |
| * \param bCountryValid - TRUE if a country IE is valid for a band on which we scan |
| * \param bConstantScan - TRUE if WSC PB mode is on |
| * \return None |
| * \sa sme_CalculateCyclesNumber, sme_StartScan |
| */ |
| void sme_updateScanCycles (TI_HANDLE hSme, |
| TI_BOOL bDEnabled, |
| TI_BOOL bCountryValid, |
| TI_BOOL bConstantScan) |
| { |
| TSme *pSme = (TSme*)hSme; |
| TI_UINT32 uIndex, uScanPeriodMs, uScanDurationMs; |
| paramInfo_t *pParam; |
| |
| /* 802.11d is disabled, or no country is valid */ |
| if ((TI_FALSE == bDEnabled) || (TI_FALSE == bCountryValid)) |
| { |
| /* WSC PB mode is disabled */ |
| if (TI_FALSE == bConstantScan) |
| { |
| /* |
| * copy intervals |
| * In order to avoid tight loop of scan-select or scan-select-connecting operation, |
| * the prepare scan function takes into account the value of the scan_count when setting the 16 periods in the scan command |
| */ |
| os_memoryCopy (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]), |
| &(pSme->tInitParams.uScanIntervals[ pSme->uScanCount ]), sizeof (TI_UINT32) * (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount)); |
| |
| for(uIndex = (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount); uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM; uIndex++) |
| { |
| pSme->tScanParams.uCycleIntervalMsec[ uIndex ] = pSme->tInitParams.uScanIntervals[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1 ]; |
| } |
| |
| /* scan for default number (until a result is found) */ |
| pSme->tScanParams.uCycleNum = pSme->tInitParams.uCycleNum; |
| } |
| /* WSC PB mode is enabled */ |
| else |
| { |
| |
| /* nullify all intervals */ |
| os_memoryZero (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]), |
| sizeof (TI_UINT32) * PERIODIC_SCAN_MAX_INTERVAL_NUM); |
| |
| /* calculate the duration of one scan cycle */ |
| uScanDurationMs = 0; |
| for (uIndex = 0; uIndex < pSme->tScanParams.uChannelNum; uIndex++) |
| { |
| uScanDurationMs += pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs; |
| } |
| |
| /* set the number of cycles - 2 minutes divided by one cycle duration */ |
| pSme->tScanParams.uCycleNum = (120000 / uScanDurationMs) + 1; |
| } |
| } |
| /* 802.11d is enabled, and country is valid on at least one band */ |
| else |
| { |
| pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t)); |
| if (!pParam) |
| { |
| return; |
| } |
| |
| /* get country expiry time */ |
| pParam->paramType = REGULATORY_DOMAIN_TIME_TO_COUNTRY_EXPIRY; |
| regulatoryDomain_getParam (pSme->hRegDomain, pParam); |
| |
| /* WSC PB mode is disabled */ |
| if (TI_FALSE == bConstantScan) |
| { |
| /* |
| * copy intervals |
| * In order to avoid tight loop of scan-select or scan-select-connecting operation, |
| * the prepare scan function takes into account the value of the scan_count when setting the 16 periods in the scan command |
| */ |
| os_memoryCopy (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]), |
| &(pSme->tInitParams.uScanIntervals[ pSme->uScanCount ]), sizeof (TI_UINT32) * (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount)); |
| |
| for(uIndex = (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount); uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM; uIndex++) |
| { |
| pSme->tScanParams.uCycleIntervalMsec[ uIndex ] = pSme->tInitParams.uScanIntervals[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1 ]; |
| } |
| |
| /* set cycle number according to country expiry time */ |
| sme_CalculateCyclesNumber (hSme, pParam->content.uTimeToCountryExpiryMs); |
| } |
| /* WSC PB mode is enabled */ |
| else |
| { |
| /* turn off WSC PB mode (for next scan) */ |
| pSme->bConstantScan = TI_FALSE; |
| |
| /* set scan period to minimum of WSC PB duration (2 minutes) and country expiry time */ |
| uScanPeriodMs = TI_MIN (120000, pParam->content.uTimeToCountryExpiryMs); |
| |
| /* nullify all intervals */ |
| os_memoryZero (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]), |
| sizeof (TI_UINT32) * PERIODIC_SCAN_MAX_INTERVAL_NUM); |
| |
| /* calculate the duration of one scan cycle */ |
| uScanDurationMs = 0; |
| for (uIndex = 0; uIndex < pSme->tScanParams.uChannelNum; uIndex++) |
| { |
| uScanDurationMs += pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs; |
| } |
| |
| if (uScanDurationMs != 0) |
| { |
| /* set the number of cycles - scan period divided by one cycle duration */ |
| pSme->tScanParams.uCycleNum = (uScanPeriodMs / uScanDurationMs) + 1; |
| } |
| else |
| { |
| pSme->tScanParams.uCycleNum = pSme->tInitParams.uCycleNum; |
| } |
| } |
| os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t)); |
| } |
| |
| /* in case independent mode and to avoid supplicant send disconnect event after 60s */ |
| if (pSme->eBssType != BSS_INFRASTRUCTURE) |
| { |
| pSme->tScanParams.uCycleNum = 1; |
| } |
| } |
| |
| /** |
| * \fn sme_CalculateCyclesNumber |
| * \brief Calculates the cycle number required for a gicen time, according to scan intervals |
| * |
| * Calculates the cycle number required for a gicen time, according to scan intervals. First check the 16 |
| * different intervals, and if more time is available, find how many cycles still fit. Write the result |
| * to the SME scan command |
| * |
| * \param hSme - handle to the SME object |
| * \param uToTalTimeMs - the total periodic scan operation duartion |
| * \return None |
| * \sa sme_updateScanCycles, sme_StartScan |
| */ |
| void sme_CalculateCyclesNumber (TI_HANDLE hSme, TI_UINT32 uTotalTimeMs) |
| { |
| TSme *pSme = (TSme*)hSme; |
| TI_UINT32 uIndex, uCurrentTimeMs = 0; |
| |
| /* |
| * the total time should exceed country code expiration by one interval (so that next scan wouldn't |
| * have a valid country code) |
| */ |
| |
| /* nullify cycle number */ |
| pSme->tScanParams.uCycleNum = 0; |
| /* now find how many cycles fit within this time. First, check if all first 16 configured intervals fit */ |
| for (uIndex = 0; |
| (uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM) && (uCurrentTimeMs < uTotalTimeMs); |
| uIndex++) |
| { |
| pSme->tScanParams.uCycleNum++; |
| uCurrentTimeMs += pSme->tScanParams.uCycleIntervalMsec[ uIndex ]; |
| } |
| /* now find out how many more cycles with the last interval still fits */ |
| if (uCurrentTimeMs < uTotalTimeMs) |
| { |
| /* |
| * divide the reamining time (time until expiry minus the total time calculated so far) |
| * by the last interval time, to get how many more scans would fit after the first 16 intervals |
| */ |
| pSme->tScanParams.uCycleNum += (uTotalTimeMs - uCurrentTimeMs) / |
| pSme->tScanParams.uCycleIntervalMsec[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1]; |
| /* and add one, to compensate for the reminder */ |
| pSme->tScanParams.uCycleNum++; |
| } |
| } |
| |