1/*
2 * smeSelect.c
3 *
4 * Copyright(c) 1998 - 2009 Texas Instruments. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 *  * Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *  * Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in
15 *    the documentation and/or other materials provided with the
16 *    distribution.
17 *  * Neither the name Texas Instruments nor the names of its
18 *    contributors may be used to endorse or promote products derived
19 *    from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/** \file  smeSelect.c
35 *  \brief SME select function implementation
36 *
37 *  \see   smeSm.h, smeSm.c, sme.c, sme.h, smePrivate.h
38 */
39
40
41#define __FILE_ID__  FILE_ID_42
42#include "smePrivate.h"
43#include "scanResultTable.h"
44#include "rsnApi.h"
45#include "siteMgrApi.h"
46#include "EvHandler.h"
47#include "GenSM.h"
48#include "smeSm.h"
49#include "tidef.h"
50
51static TI_BOOL sme_SelectSsidMatch (TI_HANDLE hSme, TSsid *pSiteSsid, TSsid *pDesiredSsid,
52                                    ESsidType eDesiredSsidType);
53static TI_BOOL sme_SelectBssidMatch (TMacAddr *pSiteBssid, TMacAddr *pDesiredBssid);
54static TI_BOOL sme_SelectBssTypeMatch (ScanBssType_e eSiteBssType, ScanBssType_e eDesiredBssType);
55static TI_BOOL sme_SelectWscMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite,
56                                   TI_BOOL *pbWscPbAbort, TI_BOOL *pbWscPbApFound);
57static TI_BOOL sme_SelectRsnMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite);
58
59/**
60 * \fn     sme_Select
61 * \brief  Select a connection candidate from the scan result table
62 *
63 * Select a connection candidate from the scan result table.
64 *
65 * Connection candidate must match SSID, BSSID, BSS type, RSN and WSC settings, has the best
66 * RSSI level from all matching sites, and connection was not attempted to it in this SME cycle
67 * (since last scan was completed)
68 *
69 * \param  hSme - handle to the SME object
70 * \return A pointer to the selected site, NULL if no site macthes the selection criteria
71 */
72TSiteEntry *sme_Select (TI_HANDLE hSme)
73{
74    TSme            *pSme = (TSme*)hSme;
75    TSiteEntry      *pCurrentSite, *pSelectedSite = NULL;
76    TI_INT8         iSelectedSiteRssi = -127; /* minimum RSSI */
77    TI_BOOL         bWscPbAbort, pWscPbApFound = TI_FALSE;
78    int             apFoundCtr =0;
79
80    TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select called\n");
81
82    /* on SG avalanche, select is not needed, send connect event automatically */
83    if (TI_TRUE == pSme->bReselect)
84    {
85        paramInfo_t *pParam;
86
87        TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_Select: reselect flag is on, reselecting the current site\n");
88
89        pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t));
90        if (!pParam)
91            return NULL;
92
93        pSme->bReselect = TI_FALSE;
94
95        /* Get Primary Site */
96        pParam->paramType = SITE_MGR_GET_PRIMARY_SITE;
97        siteMgr_getParam(pSme->hSiteMgr, pParam);
98        pCurrentSite = pParam->content.pPrimarySite;
99        os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t));
100        return pCurrentSite;
101    }
102
103    /* get the first site from the scan result table */
104    pCurrentSite = scanResultTable_GetFirst (pSme->hScanResultTable);
105
106    /* check all sites */
107    while (NULL != pCurrentSite)
108    {
109        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 ]);
110
111        /* if this site was previously selected in the current SME connection attempt, and conn mode is auto */
112        if (TI_TRUE == pCurrentSite->bConsideredForSelect)
113        {
114            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 ]);
115            /* get the next site and continue the loop */
116            pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
117            continue;
118        }
119
120        /* check if site matches */
121        /* first check SSID match */
122        if (TI_FALSE == sme_SelectSsidMatch (hSme, &(pCurrentSite->ssid), &(pSme->tSsid), pSme->eSsidType))
123        /* site doesn't match */
124        {
125            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 ]);
126            pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
127            /* get the next site and continue the loop */
128            pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
129            continue;
130        }
131
132        /* Now check BSSID match */
133        if (TI_FALSE == sme_SelectBssidMatch (&(pCurrentSite->bssid), &(pSme->tBssid)))
134        /* site doesn't match */
135        {
136            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 ]);
137            pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
138            /* get the next site and continue the loop */
139            pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
140            continue;
141        }
142
143        /* and BSS type match */
144        if (TI_FALSE == sme_SelectBssTypeMatch (pCurrentSite->bssType, pSme->eBssType))
145        /* site doesn't match */
146        {
147            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 ]);
148            pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
149            /* get the next site and continue the loop */
150            pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
151            continue;
152        }
153
154         if (pCurrentSite->WSCSiteMode == TIWLN_SIMPLE_CONFIG_PBC_METHOD)
155         {
156           apFoundCtr++;
157         }
158         if (apFoundCtr > 1)
159         {
160           pWscPbApFound = TI_TRUE;
161         }
162
163        /* and simple config match */
164        if (TI_FALSE == sme_SelectWscMatch (hSme, pCurrentSite, &bWscPbAbort, &pWscPbApFound))
165        /* site doesn't match */
166        {
167            /* also check if abort was indicated */
168            if (TI_TRUE == bWscPbAbort)
169            {
170                /* send event to user mode to indicate this */
171                EvHandlerSendEvent (pSme->hEvHandler, IPC_EVENT_WPS_SESSION_OVERLAP, NULL, 0);
172                /* select failed - will rescan in time */
173                return NULL;
174            }
175            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 ]);
176            pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
177            /* get the next site and continue the loop */
178            pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
179            continue;
180        }
181
182        /* and security match */
183        if (TI_FALSE == sme_SelectRsnMatch (hSme, pCurrentSite))
184        /* site doesn't match */
185        {
186            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 ]);
187            pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
188            /* get the next site and continue the loop */
189            pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
190            continue;
191        }
192
193        /* and rate match */
194        if (TI_FALSE == siteMgr_SelectRateMatch (pSme->hSiteMgr, pCurrentSite))
195        /* site doesn't match */
196        {
197            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 ]);
198            pCurrentSite->bConsideredForSelect = TI_TRUE; /* don't try this site again */
199            /* get the next site and continue the loop */
200            pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
201            continue;
202        }
203
204        /* if this site RSSI is higher than current maximum, select it */
205        if (pCurrentSite->rssi > iSelectedSiteRssi)
206        {
207            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 ]);
208            pSelectedSite = pCurrentSite;
209            iSelectedSiteRssi = pCurrentSite->rssi;
210        }
211
212        /* and continue to the next site */
213        pCurrentSite = scanResultTable_GetNext (pSme->hScanResultTable);
214    }
215
216    /* if a matching site was found */
217    if (NULL != pSelectedSite)
218    {
219        /* mark that a connection to this site was (actually is) attempted */
220        pSelectedSite->bConsideredForSelect = TI_TRUE;
221
222        /* hope this is the correct place for siteMgr_changeBandParams */
223        siteMgr_changeBandParams (pSme->hSiteMgr, pSelectedSite->eBand);
224
225        /*
226         * Coordinate between SME module site table and Site module site Table
227         * copy candidate AP to Site module site Table.
228         */
229        siteMgr_CopyToPrimarySite(pSme->hSiteMgr, pSelectedSite);
230    }
231
232    /* return the selected site (or NULL, if no site was selected) */
233    return pSelectedSite;
234}
235
236/**
237 * \fn     sme_SelectSsidMatch
238 * \brief  Check if a site SSID matches the desired SSID for selection
239 *
240 * Check if a site SSID matches the desired SSID for selection
241 *
242 * \param  hSme - handle to the SME object
243 * \param  pSiteSsid - the site SSID
244 * \param  pDesiredSsid - the desired SSID
245 * \param  edesiredSsidType - the desired SSID type
246 * \return TI_TRUE if SSIDs match, TI_FALSE if they don't
247 * \sa     sme_Select
248 */
249TI_BOOL sme_SelectSsidMatch (TI_HANDLE hSme, TSsid *pSiteSsid, TSsid *pDesiredSsid,
250                             ESsidType eDesiredSsidType)
251{
252    TSme        *pSme = (TSme*)hSme;
253
254    /* if the desired SSID type is any, return TRUE (site matches) */
255    if (SSID_TYPE_ANY == eDesiredSsidType)
256    {
257        return TI_TRUE;
258    }
259
260    /* otherwise, check if the SSIDs match */
261    if ((pSiteSsid->len == pDesiredSsid->len) && /* lngth match */
262        (0 == os_memoryCompare (pSme->hOS, &(pSiteSsid->str[ 0 ]), &(pDesiredSsid->str[ 0 ]), pSiteSsid->len))) /* content match */
263    {
264        return TI_TRUE;
265    }
266    else
267    {
268        return TI_FALSE;
269    }
270}
271
272/**
273 * \fn     sme_SelectBssidMatch
274 * \brief  Check if a site BSSID matches the desired BSSID for selection
275 *
276 * Check if a site BSSID matches the desired BSSID for selection
277 *
278 * \param  pSiteBssid - the site BSSID
279 * \param  pDesiredBssid - the desired BSSID
280 * \return TI_TRUE if BSSIDs match, TI_FALSE if they don't
281 * \sa     sme_Select
282 */
283TI_BOOL sme_SelectBssidMatch (TMacAddr *pSiteBssid, TMacAddr *pDesiredBssid)
284{
285    /* check if the desired BSSID is broadcast (no need to match) */
286    if (TI_TRUE == MAC_BROADCAST (*pDesiredBssid))
287    {
288        return TI_TRUE;
289    }
290
291    /* if the desired BSSID is not any BSSID, check if the site BSSID equals the desired BSSID */
292    if (TI_TRUE == MAC_EQUAL (*pDesiredBssid, *pSiteBssid))
293    {
294        return TI_TRUE;
295    }
296
297    /* no match */
298    return TI_FALSE;
299}
300
301/**
302 * \fn     sme_SelectBssTypeMatch
303 * \brief  Checks if the desired BSS type match the BSS type of a site
304 *
305 * Checks if the desired BSS type match the BSS type of a site
306 *
307 * \param  eSiteBssType - the site BSS type
308 * \param  edesiredBssType - the desired BSS type
309 * \return TI_TRUE if the BSS types matches, TI_FALSE if they don't
310 * \sa     sme_Select
311 */
312TI_BOOL sme_SelectBssTypeMatch (ScanBssType_e eSiteBssType, ScanBssType_e eDesiredBssType)
313{
314    /* if the desired type is any, there is a match */
315    if (BSS_ANY == eDesiredBssType)
316    {
317        return TI_TRUE;
318    }
319
320    /* if the BSS types equal, there is a match */
321    if (eDesiredBssType == eSiteBssType)
322    {
323        return TI_TRUE;
324    }
325
326    /* no match */
327    return TI_FALSE;
328}
329
330/**
331 * \fn     sme_SelectWscMatch
332 * \brief  checks if the configred WSC mode equals the WSC mode of a site
333 *
334 * checks if the configred WSC mode equals the WSC mode of a site
335 *
336 * \param  hSme - handle to the SME object
337 * \param  pCurrentSite - site to check
338 * \return TI_TRUE if site macthes current WSC mode, TI_FALSE if it doesn't match
339 * \sa     sme_Select
340 */
341TI_BOOL sme_SelectWscMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite,
342                            TI_BOOL *pbWscPbAbort, TI_BOOL *pbWscPbApFound)
343{
344    TSme            *pSme = (TSme*)hSme;
345    TIWLN_SIMPLE_CONFIG_MODE  wscMode;
346
347    siteMgr_getParamWSC(pSme->hSiteMgr, &wscMode); /* SITE_MGR_SIMPLE_CONFIG_MODE - get the WSC mode from site mgr */
348    /* if simple config is off, site match */
349    if (TIWLN_SIMPLE_CONFIG_OFF == wscMode)
350    {
351        return TI_TRUE;
352    }
353
354    /* if WSC is supported, and more than one AP with PB configuration is found - indicate to abort */
355    if ((TI_TRUE == *pbWscPbApFound) && (TIWLN_SIMPLE_CONFIG_PBC_METHOD == pCurrentSite->WSCSiteMode))
356    {
357        TRACE1(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_SelectWscMatch: WSC mode is %d, and more than one AP with WSC PB found - aborting\n", wscMode);
358        *pbWscPbAbort = TI_TRUE;
359        return TI_FALSE;
360    }
361    else
362    {
363        /* indicate NOT to abort the select process */
364        *pbWscPbAbort = TI_FALSE;
365    }
366
367    /* if configured simple config mode equals site simple config mode, site match */
368    if (pCurrentSite->WSCSiteMode == wscMode)
369    {
370        return TI_TRUE;
371    }
372
373    /* site doesn't match */
374    return TI_FALSE;
375}
376
377/**
378 * \fn     sme_SelectRsnMatch
379 * \brief  Checks if the configured scurity settings match those of a site
380 *
381 * Checks if the configured scurity settings match those of a site
382 *
383 * \param  hSme - handle to the SME object
384 * \param  pCurrentSite - the site to check
385 * \return TI_TRUE if site matches RSN settings, TI FALSE if it doesn't
386 * \sa     sme_Select
387 */
388TI_BOOL sme_SelectRsnMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite)
389{
390    TSme            *pSme = (TSme*)hSme;
391	TRsnData    	tRsnData;
392    dot11_RSN_t     *pRsnIe;
393    TI_UINT8        uRsnIECount=0;
394    TI_UINT8        uCurRsnData[255];
395    TI_UINT8        uLength = 0;
396    TI_UINT32       uMetric;
397	TRsnSiteParams  tRsnSiteParams;
398
399	tRsnSiteParams.bssType = pCurrentSite->bssType;
400	MAC_COPY(tRsnSiteParams.bssid, pCurrentSite->bssid);
401	tRsnSiteParams.pHTCapabilities = &pCurrentSite->tHtCapabilities;
402	tRsnSiteParams.pHTInfo = &pCurrentSite->tHtInformation;
403
404    /* copy all RSN IE's */
405    pRsnIe = pCurrentSite->pRsnIe;
406    while ((uLength < pCurrentSite->rsnIeLen) && (uRsnIECount < MAX_RSN_IE))
407    {
408        uCurRsnData[ 0 + uLength ] = pRsnIe->hdr[ 0 ];
409        uCurRsnData[ 1 + uLength ] = pRsnIe->hdr[ 1 ];
410        os_memoryCopy (pSme->hOS, &uCurRsnData[ 2 + uLength ], pRsnIe->rsnIeData, pRsnIe->hdr[ 1 ]);
411        uLength += pRsnIe->hdr[ 1 ] + 2;
412        pRsnIe += 1;
413        uRsnIECount++;
414    }
415    /* sanity check - make sure RSN IE's size is not too big */
416    if (uLength < pCurrentSite->rsnIeLen)
417    {
418        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);
419    }
420
421    /* call the RSN to evaluate the site */
422    tRsnData.pIe = (pCurrentSite->rsnIeLen == 0) ? NULL : uCurRsnData;
423    tRsnData.ieLen = pCurrentSite->rsnIeLen;
424    tRsnData.privacy = pCurrentSite->privacy;
425    if (rsn_evalSite (pSme->hRsn, &tRsnData, &tRsnSiteParams , &uMetric) != TI_OK)
426    {
427        /* no match */
428        return TI_FALSE;
429    }
430    else
431    {
432        /* match! */
433        return TI_TRUE;
434    }
435}
436
437