blob: 3bc238d16bf120229e76d5dea38fe47b1db87862 [file] [log] [blame]
/*
* smeSm.c
*
* Copyright(c) 1998 - 2009 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 ] =
{
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,
};
#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 */
genSM_Event (pSme->hSmeSm, SME_SM_EVENT_STOP, hSme);
}
else if (TI_TRUE == pSme->bConnectRequired)
{
/* if connection was required, start the process */
genSM_Event (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 */
genSM_Event (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;
genSM_Event (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 */
genSM_Event (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");
genSM_Event (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");
genSM_Event (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 */
genSM_Event (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");
genSM_Event (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 */
genSM_Event (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 = 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;
}
}
/* 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
{
/* turn off WSC PB mode (for next scan) */
pSme->bConstantScan = TI_FALSE;
/* 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++;
}
}