blob: bd364ed0986a95d883e58151547b1d23389a1b9b [file] [log] [blame]
/*
* smeSelect.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 smeSelect.c
* \brief SME select function implementation
*
* \see smeSm.h, smeSm.c, sme.c, sme.h, smePrivate.h
*/
#define __FILE_ID__ FILE_ID_42
#include "smePrivate.h"
#include "scanResultTable.h"
#include "rsnApi.h"
#include "siteMgrApi.h"
#include "EvHandler.h"
#include "GenSM.h"
#include "smeSm.h"
#include "tidef.h"
static TI_BOOL sme_SelectSsidMatch (TI_HANDLE hSme, TSsid *pSiteSsid, TSsid *pDesiredSsid,
ESsidType eDesiredSsidType);
static TI_BOOL sme_SelectBssidMatch (TMacAddr *pSiteBssid, TMacAddr *pDesiredBssid);
static TI_BOOL sme_SelectBssTypeMatch (ScanBssType_e eSiteBssType, ScanBssType_e eDesiredBssType);
static TI_BOOL sme_SelectWscMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite,
TI_BOOL *pbWscPbAbort, TI_BOOL *pbWscPbApFound);
static TI_BOOL sme_SelectRsnMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite);
/**
* \fn sme_Select
* \brief Select a connection candidate from the scan result table
*
* Select a connection candidate from the scan result table.
*
* Connection candidate must match SSID, BSSID, BSS type, RSN and WSC settings, has the best
* RSSI level from all matching sites, and connection was not attempted to it in this SME cycle
* (since last scan was completed)
*
* \param hSme - handle to the SME object
* \return A pointer to the selected site, NULL if no site macthes the selection criteria
*/
TSiteEntry *sme_Select (TI_HANDLE hSme)
{
TSme *pSme = (TSme*)hSme;
TSiteEntry *pCurrentSite, *pSelectedSite = NULL;
TI_INT8 iSelectedSiteRssi = -127; /* minimum RSSI */
TI_BOOL bWscPbAbort, pWscPbApFound = TI_FALSE;
int apFoundCtr =0;
TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select called\n");
/* on SG avalanche, select is not needed, send connect event automatically */
if (TI_TRUE == pSme->bReselect)
{
paramInfo_t *pParam;
TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: reselect flag is on, reselecting the current site\n");
pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t));
if (!pParam)
return NULL;
pSme->bReselect = TI_FALSE;
/* Get Primary Site */
pParam->paramType = SITE_MGR_GET_PRIMARY_SITE;
siteMgr_getParam(pSme->hSiteMgr, pParam);
pCurrentSite = pParam->content.pPrimarySite;
os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t));
return pCurrentSite;
}
/* get the first site from the scan result table */
pCurrentSite = scanResultTable_GetFirst (pSme->hScanResultTable);
/* check all sites */
while (NULL != pCurrentSite)
{
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: considering BSSID: %02x:%02x:%02x:%02x:%02x:%02x for selection\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
/* if this site was previously selected in the current SME connection attempt, and conn mode is auto */
if (TI_TRUE == pCurrentSite->bConsideredForSelect)
{
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: BSSID: %02x:%02x:%02x:%02x:%02x:%02x was selected previously\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
/* get the next site and continue the loop */
pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
continue;
}
/* check if site matches */
/* first check SSID match */
if (TI_FALSE == sme_SelectSsidMatch (hSme, &(pCurrentSite->ssid), &(pSme->tSsid), pSme->eSsidType))
/* site doesn't match */
{
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: BSSID: %02x:%02x:%02x:%02x:%02x:%02x doesn't match SSID\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
/* get the next site and continue the loop */
pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
continue;
}
/* Now check BSSID match */
if (TI_FALSE == sme_SelectBssidMatch (&(pCurrentSite->bssid), &(pSme->tBssid)))
/* site doesn't match */
{
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: BSSID: %02x:%02x:%02x:%02x:%02x:%02x doesn't match SSID\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
/* get the next site and continue the loop */
pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
continue;
}
/* and BSS type match */
if (TI_FALSE == sme_SelectBssTypeMatch (pCurrentSite->bssType, pSme->eBssType))
/* site doesn't match */
{
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: BSSID: %02x:%02x:%02x:%02x:%02x:%02x doesn't match BSS type\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
/* get the next site and continue the loop */
pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
continue;
}
if (pCurrentSite->WSCSiteMode == TIWLN_SIMPLE_CONFIG_PBC_METHOD)
{
apFoundCtr++;
}
if (apFoundCtr > 1)
{
pWscPbApFound = TI_TRUE;
}
/* and simple config match */
if (TI_FALSE == sme_SelectWscMatch (hSme, pCurrentSite, &bWscPbAbort, &pWscPbApFound))
/* site doesn't match */
{
/* also check if abort was indicated */
if (TI_TRUE == bWscPbAbort)
{
/* send event to user mode to indicate this */
EvHandlerSendEvent (pSme->hEvHandler, IPC_EVENT_WPS_SESSION_OVERLAP, NULL, 0);
/* select failed - will rescan in time */
return NULL;
}
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: BSSID: %02x:%02x:%02x:%02x:%02x:%02x doesn't match WSC\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
/* get the next site and continue the loop */
pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
continue;
}
/* and security match */
if (TI_FALSE == sme_SelectRsnMatch (hSme, pCurrentSite))
/* site doesn't match */
{
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: BSSID: %02x:%02x:%02x:%02x:%02x:%02x doesn't match RSN\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
/* get the next site and continue the loop */
pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
continue;
}
/* and rate match */
if (TI_FALSE == siteMgr_SelectRateMatch (pSme->hSiteMgr, pCurrentSite))
/* site doesn't match */
{
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: BSSID: %02x:%02x:%02x:%02x:%02x:%02x doesn't match rates\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
/* get the next site and continue the loop */
pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
continue;
}
/* if this site RSSI is higher than current maximum, select it */
if (pCurrentSite->rssi > iSelectedSiteRssi)
{
TRACE6(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: BSSID: %02x:%02x:%02x:%02x:%02x:%02x match and has highest RSSI so far!\n", pCurrentSite->bssid[ 0 ], pCurrentSite->bssid[ 1 ], pCurrentSite->bssid[ 2 ], pCurrentSite->bssid[ 3 ], pCurrentSite->bssid[ 4 ], pCurrentSite->bssid[ 5 ]);
pSelectedSite = pCurrentSite;
iSelectedSiteRssi = pCurrentSite->rssi;
}
/* and continue to the next site */
pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
}
/* if a matching site was found */
if (NULL != pSelectedSite)
{
/* mark that a connection to this site was (actually is) attempted */
pSelectedSite->bConsideredForSelect = TI_TRUE;
/* hope this is the correct place for siteMgr_changeBandParams */
siteMgr_changeBandParams (pSme->hSiteMgr, pSelectedSite->eBand);
/*
* Coordinate between SME module site table and Site module site Table
* copy candidate AP to Site module site Table.
*/
siteMgr_CopyToPrimarySite(pSme->hSiteMgr, pSelectedSite);
}
/* return the selected site (or NULL, if no site was selected) */
return pSelectedSite;
}
/**
* \fn sme_SelectSsidMatch
* \brief Check if a site SSID matches the desired SSID for selection
*
* Check if a site SSID matches the desired SSID for selection
*
* \param hSme - handle to the SME object
* \param pSiteSsid - the site SSID
* \param pDesiredSsid - the desired SSID
* \param edesiredSsidType - the desired SSID type
* \return TI_TRUE if SSIDs match, TI_FALSE if they don't
* \sa sme_Select
*/
TI_BOOL sme_SelectSsidMatch (TI_HANDLE hSme, TSsid *pSiteSsid, TSsid *pDesiredSsid,
ESsidType eDesiredSsidType)
{
TSme *pSme = (TSme*)hSme;
/* if the desired SSID type is any, return TRUE (site matches) */
if (SSID_TYPE_ANY == eDesiredSsidType)
{
return TI_TRUE;
}
/* otherwise, check if the SSIDs match */
if ((pSiteSsid->len == pDesiredSsid->len) && /* lngth match */
(0 == os_memoryCompare (pSme->hOS, &(pSiteSsid->str[ 0 ]), &(pDesiredSsid->str[ 0 ]), pSiteSsid->len))) /* content match */
{
return TI_TRUE;
}
else
{
return TI_FALSE;
}
}
/**
* \fn sme_SelectBssidMatch
* \brief Check if a site BSSID matches the desired BSSID for selection
*
* Check if a site BSSID matches the desired BSSID for selection
*
* \param pSiteBssid - the site BSSID
* \param pDesiredBssid - the desired BSSID
* \return TI_TRUE if BSSIDs match, TI_FALSE if they don't
* \sa sme_Select
*/
TI_BOOL sme_SelectBssidMatch (TMacAddr *pSiteBssid, TMacAddr *pDesiredBssid)
{
/* check if the desired BSSID is broadcast (no need to match) */
if (TI_TRUE == MAC_BROADCAST (*pDesiredBssid))
{
return TI_TRUE;
}
/* if the desired BSSID is not any BSSID, check if the site BSSID equals the desired BSSID */
if (TI_TRUE == MAC_EQUAL (*pDesiredBssid, *pSiteBssid))
{
return TI_TRUE;
}
/* no match */
return TI_FALSE;
}
/**
* \fn sme_SelectBssTypeMatch
* \brief Checks if the desired BSS type match the BSS type of a site
*
* Checks if the desired BSS type match the BSS type of a site
*
* \param eSiteBssType - the site BSS type
* \param edesiredBssType - the desired BSS type
* \return TI_TRUE if the BSS types matches, TI_FALSE if they don't
* \sa sme_Select
*/
TI_BOOL sme_SelectBssTypeMatch (ScanBssType_e eSiteBssType, ScanBssType_e eDesiredBssType)
{
/* if the desired type is any, there is a match */
if (BSS_ANY == eDesiredBssType)
{
return TI_TRUE;
}
/* if the BSS types equal, there is a match */
if (eDesiredBssType == eSiteBssType)
{
return TI_TRUE;
}
/* no match */
return TI_FALSE;
}
/**
* \fn sme_SelectWscMatch
* \brief checks if the configred WSC mode equals the WSC mode of a site
*
* checks if the configred WSC mode equals the WSC mode of a site
*
* \param hSme - handle to the SME object
* \param pCurrentSite - site to check
* \return TI_TRUE if site macthes current WSC mode, TI_FALSE if it doesn't match
* \sa sme_Select
*/
TI_BOOL sme_SelectWscMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite,
TI_BOOL *pbWscPbAbort, TI_BOOL *pbWscPbApFound)
{
TSme *pSme = (TSme*)hSme;
TIWLN_SIMPLE_CONFIG_MODE wscMode;
siteMgr_getParamWSC(pSme->hSiteMgr, &wscMode); /* SITE_MGR_SIMPLE_CONFIG_MODE - get the WSC mode from site mgr */
/* if simple config is off, site match */
if (TIWLN_SIMPLE_CONFIG_OFF == wscMode)
{
return TI_TRUE;
}
/* if WSC is supported, and more than one AP with PB configuration is found - indicate to abort */
if ((TI_TRUE == *pbWscPbApFound) && (TIWLN_SIMPLE_CONFIG_PBC_METHOD == pCurrentSite->WSCSiteMode))
{
TRACE1(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_SelectWscMatch: WSC mode is %d, and more than one AP with WSC PB found - aborting\n", wscMode);
*pbWscPbAbort = TI_TRUE;
return TI_FALSE;
}
else
{
/* indicate NOT to abort the select process */
*pbWscPbAbort = TI_FALSE;
}
/* if configured simple config mode equals site simple config mode, site match */
if (pCurrentSite->WSCSiteMode == wscMode)
{
return TI_TRUE;
}
/* site doesn't match */
return TI_FALSE;
}
/**
* \fn sme_SelectRsnMatch
* \brief Checks if the configured scurity settings match those of a site
*
* Checks if the configured scurity settings match those of a site
*
* \param hSme - handle to the SME object
* \param pCurrentSite - the site to check
* \return TI_TRUE if site matches RSN settings, TI FALSE if it doesn't
* \sa sme_Select
*/
TI_BOOL sme_SelectRsnMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite)
{
TSme *pSme = (TSme*)hSme;
TRsnData tRsnData;
dot11_RSN_t *pRsnIe;
TI_UINT8 uRsnIECount=0;
TI_UINT8 uCurRsnData[255];
TI_UINT8 uLength = 0;
TI_UINT32 uMetric;
TRsnSiteParams tRsnSiteParams;
tRsnSiteParams.bssType = pCurrentSite->bssType;
MAC_COPY(tRsnSiteParams.bssid, pCurrentSite->bssid);
tRsnSiteParams.pHTCapabilities = &pCurrentSite->tHtCapabilities;
tRsnSiteParams.pHTInfo = &pCurrentSite->tHtInformation;
/* copy all RSN IE's */
pRsnIe = pCurrentSite->pRsnIe;
while ((uLength < pCurrentSite->rsnIeLen) && (uRsnIECount < MAX_RSN_IE))
{
uCurRsnData[ 0 + uLength ] = pRsnIe->hdr[ 0 ];
uCurRsnData[ 1 + uLength ] = pRsnIe->hdr[ 1 ];
os_memoryCopy (pSme->hOS, &uCurRsnData[ 2 + uLength ], pRsnIe->rsnIeData, pRsnIe->hdr[ 1 ]);
uLength += pRsnIe->hdr[ 1 ] + 2;
pRsnIe += 1;
uRsnIECount++;
}
/* sanity check - make sure RSN IE's size is not too big */
if (uLength < pCurrentSite->rsnIeLen)
{
TRACE2(pSme->hReport, REPORT_SEVERITY_ERROR , "sme_SelectRsnMatch, RSN IE is too long: rsnIeLen=%d, MAX_RSN_IE=%d\n", pCurrentSite->rsnIeLen, MAX_RSN_IE);
}
/* call the RSN to evaluate the site */
tRsnData.pIe = (pCurrentSite->rsnIeLen == 0) ? NULL : uCurRsnData;
tRsnData.ieLen = pCurrentSite->rsnIeLen;
tRsnData.privacy = pCurrentSite->privacy;
if (rsn_evalSite (pSme->hRsn, &tRsnData, &tRsnSiteParams , &uMetric) != TI_OK)
{
/* no match */
return TI_FALSE;
}
else
{
/* match! */
return TI_TRUE;
}
}