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
51 static TI_BOOL sme_SelectSsidMatch (TI_HANDLE hSme, TSsid *pSiteSsid, TSsid *pDesiredSsid,
52 ESsidType eDesiredSsidType);
53 static TI_BOOL sme_SelectBssidMatch (TMacAddr *pSiteBssid, TMacAddr *pDesiredBssid);
54 static TI_BOOL sme_SelectBssTypeMatch (ScanBssType_e eSiteBssType, ScanBssType_e eDesiredBssType);
55 static TI_BOOL sme_SelectWscMatch (TI_HANDLE hSme, TSiteEntry *pCurrentSite,
56 TI_BOOL *pbWscPbAbort, TI_BOOL *pbWscPbApFound);
57 static 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 */
sme_Select(TI_HANDLE hSme)72 TSiteEntry *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 */
sme_SelectSsidMatch(TI_HANDLE hSme,TSsid * pSiteSsid,TSsid * pDesiredSsid,ESsidType eDesiredSsidType)249 TI_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 */
sme_SelectBssidMatch(TMacAddr * pSiteBssid,TMacAddr * pDesiredBssid)283 TI_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 */
sme_SelectBssTypeMatch(ScanBssType_e eSiteBssType,ScanBssType_e eDesiredBssType)312 TI_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 */
sme_SelectWscMatch(TI_HANDLE hSme,TSiteEntry * pCurrentSite,TI_BOOL * pbWscPbAbort,TI_BOOL * pbWscPbApFound)341 TI_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 */
sme_SelectRsnMatch(TI_HANDLE hSme,TSiteEntry * pCurrentSite)388 TI_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