1 /*
2 * smeSm.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 smeSm.c
35 * \brief SME state machine implementation
36 *
37 * \see smeSm.h, sme.c, sme.h
38 */
39
40
41 #define __FILE_ID__ FILE_ID_43
42 #include "GenSM.h"
43 #include "smeSm.h"
44 #include "smePrivate.h"
45 #include "connApi.h"
46 #include "apConn.h"
47 #include "ScanCncn.h"
48 #include "scanResultTable.h"
49 #include "EvHandler.h"
50 #include "regulatoryDomainApi.h"
51 #include "siteMgrApi.h"
52 #include "DrvMain.h"
53
54
55 static OS_802_11_DISASSOCIATE_REASON_E eDisassocConvertTable[ MGMT_STATUS_MAX_NUM ] =
56 {
57 OS_DISASSOC_STATUS_UNSPECIFIED,
58 OS_DISASSOC_STATUS_UNSPECIFIED,
59 OS_DISASSOC_STATUS_AUTH_REJECT,
60 OS_DISASSOC_STATUS_ASSOC_REJECT,
61 OS_DISASSOC_STATUS_SECURITY_FAILURE,
62 OS_DISASSOC_STATUS_AP_DEAUTHENTICATE,
63 OS_DISASSOC_STATUS_AP_DISASSOCIATE,
64 OS_DISASSOC_STATUS_ROAMING_TRIGGER,
65 OS_DISASSOC_STATUS_UNSPECIFIED,
66 OS_DISASSOC_STATUS_UNSPECIFIED,
67 OS_DISASSOC_STATUS_UNSPECIFIED,
68 OS_DISASSOC_STATUS_UNSPECIFIED,
69 OS_DISASSOC_STATUS_UNSPECIFIED,
70 OS_DISASSOC_STATUS_UNSPECIFIED,
71 OS_DISASSOC_STATUS_UNSPECIFIED,
72 };
73
74 #define SME_CONVERT_DISASSOC_CODES(disassocReason) (eDisassocConvertTable[ (disassocReason) ])
75
76 static void smeSm_Start (TI_HANDLE hSme);
77 static void smeSm_Stop (TI_HANDLE hSme);
78 static void smeSm_PreConnect (TI_HANDLE hSme);
79 static void smeSm_Connect (TI_HANDLE hSme);
80 static void smeSm_ConnectSuccess (TI_HANDLE hSme);
81 static void smeSm_Disconnect (TI_HANDLE hSme);
82 static void smeSm_DisconnectDone (TI_HANDLE hSme);
83 static void smeSm_StopScan (TI_HANDLE hSme);
84 static void smeSm_StopConnect (TI_HANDLE hSme);
85 static void smeSm_ConnWhenConnecting (TI_HANDLE hSme);
86 static void smeSm_ActionUnexpected (TI_HANDLE hSme);
87 static void smeSm_NopAction (TI_HANDLE hSme);
88 static void smeSm_CheckStartConditions (TI_HANDLE hSme);
89
90 static TI_STATUS sme_StartScan (TI_HANDLE hSme);
91 static void sme_updateScanCycles (TI_HANDLE hSme,
92 TI_BOOL bDEnabled,
93 TI_BOOL bCountryValid,
94 TI_BOOL bConstantScan);
95 static void sme_CalculateCyclesNumber (TI_HANDLE hSme, TI_UINT32 uTotalTimeMs);
96
97 TGenSM_actionCell tSmMatrix[ SME_SM_NUMBER_OF_STATES ][ SME_SM_NUMBER_OF_EVENTS ] =
98 {
99 { /* SME_SM_STATE_IDLE */
100 { SME_SM_STATE_WAIT_CONNECT, smeSm_Start }, /* SME_SM_EVENT_START */
101 { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_STOP */
102 { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */
103 { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */
104 { SME_SM_STATE_IDLE, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_FAILURE */
105 { SME_SM_STATE_IDLE, smeSm_CheckStartConditions }, /* SME_SM_EVENT_DISCONNECT */
106 },
107 { /* SME_SM_STATE_WAIT_CONNECT */
108 { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */
109 { SME_SM_STATE_IDLE, smeSm_Stop }, /* SME_SM_EVENT_STOP */
110 { SME_SM_STATE_SCANNING, smeSm_PreConnect }, /* SME_SM_EVENT_CONNECT */
111 { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */
112 { SME_SM_STATE_WAIT_CONNECT, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_FAILURE */
113 { SME_SM_STATE_WAIT_CONNECT, smeSm_Start }, /* SME_SM_EVENT_DISCONNECT */
114 },
115 { /* SME_SM_STATE_SCANNING */
116 { SME_SM_STATE_SCANNING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */
117 { SME_SM_STATE_DISCONNECTING, smeSm_StopScan }, /* SME_SM_EVENT_STOP */
118 { SME_SM_STATE_CONNECTING, smeSm_Connect }, /* SME_SM_EVENT_CONNECT */
119 { SME_SM_STATE_SCANNING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */
120 { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */
121 { SME_SM_STATE_DISCONNECTING, smeSm_StopScan }, /* SME_SM_EVENT_DISCONNECT */
122 },
123 { /* SME_SM_STATE_CONNECTING */
124 { SME_SM_STATE_CONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */
125 { SME_SM_STATE_DISCONNECTING, smeSm_StopConnect }, /* SME_SM_EVENT_STOP */
126 { SME_SM_STATE_CONNECTING, smeSm_ConnWhenConnecting }, /* SME_SM_EVENT_CONNECT */
127 { SME_SM_STATE_CONNECTED, smeSm_ConnectSuccess }, /* SME_SM_EVENT_CONNECT_SUCCESS */
128 { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */
129 { SME_SM_STATE_DISCONNECTING, smeSm_StopConnect }, /* SME_SM_EVENT_DISCONNECT */
130 },
131 { /* SME_SM_STATE_CONNECTED */
132 { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */
133 { SME_SM_STATE_DISCONNECTING, smeSm_Disconnect }, /* SME_SM_EVENT_STOP */
134 { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */
135 { SME_SM_STATE_CONNECTED, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */
136 { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */
137 { SME_SM_STATE_DISCONNECTING, smeSm_Disconnect }, /* SME_SM_EVENT_DISCONNECT */
138 },
139 { /* SME_SM_STATE_DISCONNECTING */
140 { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_START */
141 { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_STOP */
142 { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT */
143 { SME_SM_STATE_DISCONNECTING, smeSm_ActionUnexpected }, /* SME_SM_EVENT_CONNECT_SUCCESS */
144 { SME_SM_STATE_WAIT_CONNECT, smeSm_DisconnectDone }, /* SME_SM_EVENT_CONNECT_FAILURE */
145 { SME_SM_STATE_DISCONNECTING, smeSm_NopAction }, /* SME_SM_EVENT_DISCONNECT */
146 }
147 };
148
149 TI_INT8* uStateDescription[] =
150 {
151 "IDLE",
152 "WAIT_CONNECT",
153 "SCANNING",
154 "CONNECTING",
155 "CONNECTED",
156 "DISCONNECTING"
157 };
158
159 TI_INT8* uEventDescription[] =
160 {
161 "START",
162 "STOP",
163 "CONNECT",
164 "CONNECT_SUCCESS",
165 "CONNECT_FAILURE",
166 "DISCONNECT"
167 };
168
169 /**
170 * \fn smeSm_Start
171 * \brief Starts STA opeartion by moving SCR out of idle group and starting connection process
172 *
173 * Starts STA opeartion by moving SCR out of idle group and starting connection process
174 *
175 * \param hSme - handle to the SME object
176 * \return None
177 * \sa smeSm_Stop, sme_start
178 */
smeSm_Start(TI_HANDLE hSme)179 void smeSm_Start (TI_HANDLE hSme)
180 {
181 TSme *pSme = (TSme*)hSme;
182
183 /* set SCR group according to connection mode */
184 if (CONNECT_MODE_AUTO == pSme->eConnectMode)
185 {
186 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_Start: changing SCR group to DRV scan\n");
187 scr_setGroup (pSme->hScr, SCR_GID_DRV_SCAN);
188 }
189 else
190 {
191 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_Start: changing SCR group to APP scan\n");
192 scr_setGroup (pSme->hScr, SCR_GID_APP_SCAN);
193 }
194
195 if ((TI_FALSE == pSme->bRadioOn) || (TI_FALSE == pSme->bRunning))
196 {
197 /* Radio is off so send stop event */
198 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_STOP, hSme);
199 }
200 else if (TI_TRUE == pSme->bConnectRequired)
201 {
202 /* if connection was required, start the process */
203 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme);
204 }
205 }
206
207 /**
208 * \fn smeSm_Stop
209 * \brief Turns off the STA
210 *
211 * Turns off the STA by moving the SCr to idle
212 *
213 * \param hSme - handle to the SME object
214 * \return None
215 * \sa smeSm_Start, sme_Stop
216 */
smeSm_Stop(TI_HANDLE hSme)217 void smeSm_Stop (TI_HANDLE hSme)
218 {
219 TSme *pSme = (TSme*)hSme;
220
221 /* set SCR group to idle */
222 scr_setGroup (pSme->hScr, SCR_GID_IDLE);
223
224 if (TI_FALSE == pSme->bRunning)
225 {
226 /* call DrvMain */
227 drvMain_SmeStop (pSme->hDrvMain);
228 }
229 }
230
231 /**
232 * \fn smeSm_PreConnect
233 * \brief Initiates the connection process
234 *
235 * Initiates the connection process - for automatic mode, start scan, for manual mode - triggers connection
236 *
237 * \param hSme - handle to the SME object
238 * \return None
239 * \sa smeSm_Connect, smeSm_ConnectSuccess
240 */
smeSm_PreConnect(TI_HANDLE hSme)241 void smeSm_PreConnect (TI_HANDLE hSme)
242 {
243 TSme *pSme = (TSme *)hSme;
244 paramInfo_t *pParam;
245
246 /* set the connection mode with which this connection attempt is starting */
247 pSme->eLastConnectMode = pSme->eConnectMode;
248
249 /* mark that no authentication/assocaition was yet sent */
250 pSme->bAuthSent = TI_FALSE;
251
252 /* try to find a connection candidate (manual mode have already performed scann */
253 pSme->pCandidate = sme_Select (hSme);
254 if (NULL != pSme->pCandidate)
255 {
256 /* candidate is available - attempt connection */
257 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme);
258 }
259 /* no candidate */
260 else
261 {
262 if (CONNECT_MODE_AUTO == pSme->eConnectMode)
263 {
264 /* automatic mode - start scanning */
265 if (TI_OK != sme_StartScan (hSme))
266 {
267 TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_PreConnect: unable to start scan, stopping the SME\n");
268 pSme->bRadioOn = TI_FALSE;
269 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme);
270 }
271
272 /* update scan count counter */
273 if(pSme->uScanCount < PERIODIC_SCAN_MAX_INTERVAL_NUM)
274 {
275 pSme->uScanCount++;
276 }
277
278 }
279 else /* Manual mode */
280 {
281 /* for IBSS or any, if no entries where found, add the self site */
282 if (pSme->eBssType == BSS_INFRASTRUCTURE)
283 {
284 /* makr whether we need to stop the attempt connection in manual mode */
285 pSme->bConnectRequired = TI_FALSE;
286
287 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_PreConnect: No candidate available, sending connect failure\n");
288 /* manual mode and no connection candidate is available - connection failed */
289 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme);
290 }
291
292 else /* IBSS */
293 {
294 TI_UINT8 uDesiredChannel;
295 TI_BOOL channelValidity;
296
297 pSme->bConnectRequired = TI_FALSE;
298
299 pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t));
300 if (!pParam)
301 return;
302
303 pParam->paramType = SITE_MGR_DESIRED_CHANNEL_PARAM;
304 siteMgr_getParam(pSme->hSiteMgr, pParam);
305 uDesiredChannel = pParam->content.siteMgrDesiredChannel;
306
307 if (uDesiredChannel >= SITE_MGR_CHANNEL_A_MIN)
308 {
309 pParam->content.channelCapabilityReq.band = RADIO_BAND_5_0_GHZ;
310 }
311 else
312 {
313 pParam->content.channelCapabilityReq.band = RADIO_BAND_2_4_GHZ;
314 }
315
316 /*
317 update the regulatory domain with the selected band
318 */
319 /* Check if the selected channel is valid according to regDomain */
320 pParam->paramType = REGULATORY_DOMAIN_GET_SCAN_CAPABILITIES;
321 pParam->content.channelCapabilityReq.scanOption = ACTIVE_SCANNING;
322 pParam->content.channelCapabilityReq.channelNum = uDesiredChannel;
323
324 regulatoryDomain_getParam (pSme->hRegDomain, pParam);
325 channelValidity = pParam->content.channelCapabilityRet.channelValidity;
326 os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t));
327 if (!channelValidity)
328 {
329 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "IBSS SELECT FAILURE - No channel !!!\n\n");
330
331 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme);
332
333 return;
334 }
335
336 pSme->pCandidate = (TSiteEntry *)addSelfSite(pSme->hSiteMgr);
337
338 if (pSme->pCandidate == NULL)
339 {
340 TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "IBSS SELECT FAILURE - could not open self site !!!\n\n");
341
342 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme);
343
344 return;
345 }
346
347 #ifdef REPORT_LOG
348 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]);
349 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]));
350 #endif
351 /* a connection candidate is available, send a connect event */
352 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT, hSme);
353 }
354 }
355 }
356 }
357
358 /**
359 * \fn smeSm_Connect
360 * \brief Starts a connection process with the selected network
361 *
362 * Starts a connection process with the selected network
363 *
364 * \param hSme - handle to the SME object
365 * \return None
366 * \sa smeSm_PreConnect, smeSm_ConnectSuccess
367 */
smeSm_Connect(TI_HANDLE hSme)368 void smeSm_Connect (TI_HANDLE hSme)
369 {
370 TSme *pSme = (TSme*)hSme;
371 TI_STATUS tStatus;
372 paramInfo_t *pParam;
373
374 /* Sanity check - if no connection candidate was found so far */
375 if (NULL == pSme->pCandidate)
376 {
377 TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Connect: No candidate available, sending connect failure\n");
378 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_CONNECT_FAILURE, hSme);
379 }
380 else
381 {
382 pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t));
383 if (!pParam)
384 return;
385
386 /* set SCR group */
387 if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType)
388 {
389 scr_setGroup (pSme->hScr, SCR_GID_CONNECT);
390 }
391
392 /***************** Config Connection *************************/
393 pParam->paramType = CONN_TYPE_PARAM;
394 if (BSS_INDEPENDENT == pSme->pCandidate->bssType)
395 if (SITE_SELF == pSme->pCandidate->siteType)
396 {
397 pParam->content.connType = CONNECTION_SELF;
398 }
399 else
400 {
401 pParam->content.connType = CONNECTION_IBSS;
402 }
403 else
404 pParam->content.connType = CONNECTION_INFRA;
405 conn_setParam(pSme->hConn, pParam);
406 os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t));
407
408 /* start the connection process */
409 tStatus = conn_start (pSme->hConn, CONN_TYPE_FIRST_CONN, sme_ReportConnStatus, hSme, TI_FALSE, TI_FALSE);
410 if (TI_OK != tStatus)
411 {
412 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Connect: conn_start returned status %d\n", tStatus);
413 }
414 }
415 }
416
417 /**
418 * \fn smeSm_ConnectSuccess
419 * \brief Handles connection success indication
420 *
421 * Handles connection success indication - starts AP conn and set SCR group to connected
422 *
423 * \param hSme - handle to the SME object
424 * \return None
425 * \sa smeSm_PreConnect, smeSm_Connect
426 */
smeSm_ConnectSuccess(TI_HANDLE hSme)427 void smeSm_ConnectSuccess (TI_HANDLE hSme)
428 {
429 TSme *pSme = (TSme*)hSme;
430
431 pSme->uScanCount = 0;
432
433 /* connection succedded to the connection candidate - start AP connection */
434 if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType)
435 {
436 /* Start the AP connection */
437 apConn_start (pSme->hApConn,
438 (pSme->tSsid.len != 0) && !OS_802_11_SSID_JUNK (pSme->tSsid.str, pSme->tSsid.len));
439 }
440
441 /* Set SCR group to connected */
442 scr_setGroup (pSme->hScr, SCR_GID_CONNECTED);
443 }
444
445 /**
446 * \fn smeSm_Disconnect
447 * \brief Starts a disconnect by calling the AP connection or connect modules
448 *
449 * Starts a disconnect by calling the AP connection or connect modules
450 *
451 * \param hSme - handle to the SME object
452 * \return None
453 * \sa smeSm_DisconnectDone
454 */
smeSm_Disconnect(TI_HANDLE hSme)455 void smeSm_Disconnect (TI_HANDLE hSme)
456 {
457 TSme *pSme = (TSme*)hSme;
458 TI_STATUS tStatus;
459
460 /* set the SCr group to connecting */
461 scr_setGroup (pSme->hScr, SCR_GID_CONNECT);
462
463 if (BSS_INFRASTRUCTURE == pSme->pCandidate->bssType)
464 {
465 /* Call the AP connection to perform disconnect */
466 tStatus = apConn_stop (pSme->hApConn, TI_TRUE);
467 }
468 else
469 {
470 /* In IBSS disconnect is done directly with the connection SM */
471 tStatus = conn_stop(pSme->hConn, DISCONNECT_DE_AUTH, STATUS_UNSPECIFIED,
472 TI_TRUE, sme_ReportConnStatus, hSme);
473 if (tStatus != TI_OK)
474 {
475 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_Disconnect: conn_stop retruned %d\n", tStatus);
476 }
477 }
478 }
479
480 /**
481 * \fn smeSm_DisconnectDone
482 * \brief Finish a disconnect process
483 *
484 * Finish a disconnect process by sending the appropriate event and restarting the state-machine
485 *
486 * \param hSme - handle to the SME object
487 * \return None
488 * \sa smeSm_Disconnect
489 */
smeSm_DisconnectDone(TI_HANDLE hSme)490 void smeSm_DisconnectDone (TI_HANDLE hSme)
491 {
492 TSme *pSme = (TSme*)hSme;
493 OS_802_11_DISASSOCIATE_REASON_T tEventReason;
494
495 if (TI_FALSE == pSme->bReselect)
496 {
497 /* send an event notifying the disassocation */
498 if (TI_TRUE == pSme->bAuthSent)
499 {
500 tEventReason.eDisAssocType = SME_CONVERT_DISASSOC_CODES (pSme->tDisAssoc.eMgmtStatus);
501 tEventReason.uStatusCode = pSme->tDisAssoc.uStatusCode;
502 EvHandlerSendEvent (pSme->hEvHandler, IPC_EVENT_DISASSOCIATED, (TI_UINT8*)&tEventReason,
503 sizeof(OS_802_11_DISASSOCIATE_REASON_T));
504 }
505 else if (CONNECT_MODE_AUTO != pSme->eLastConnectMode)
506 {
507 EvHandlerSendEvent (pSme->hEvHandler, IPC_EVENT_NOT_ASSOCIATED, NULL, 0);
508 }
509 }
510
511 siteMgr_disSelectSite (pSme->hSiteMgr);
512
513 /* try to reconnect */
514 smeSm_Start (hSme);
515 }
516
517 /**
518 * \fn smeSm_StopScan
519 * \brief Stops the SME scan operation
520 *
521 * Stops the SME scan operation
522 *
523 * \param hSme - handle to the SME object
524 * \return None
525 * \sa smeSm_PreConnect, sme_StartScan
526 */
smeSm_StopScan(TI_HANDLE hSme)527 void smeSm_StopScan (TI_HANDLE hSme)
528 {
529 TSme *pSme = (TSme*)hSme;
530
531 scanCncn_StopPeriodicScan (pSme->hScanCncn, SCAN_SCC_DRIVER);
532 }
533
534 /**
535 * \fn smeSm_StopConnect
536 * \brief Stops the connect module
537 *
538 * Stops the connect module (if the SME is stopped during a connect attempt
539 *
540 * \param hSme - handle to the SME object
541 * \return None
542 * \sa smeSm_Connect
543 */
smeSm_StopConnect(TI_HANDLE hSme)544 void smeSm_StopConnect (TI_HANDLE hSme)
545 {
546 TSme *pSme = (TSme*)hSme;
547 TI_STATUS tStatus;
548
549 tStatus = conn_stop (pSme->hConn, DISCONNECT_DE_AUTH, STATUS_UNSPECIFIED,
550 TI_TRUE, sme_ReportConnStatus, hSme);
551
552 if (TI_OK != tStatus)
553 {
554 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_StopConnect: conn_stop returned status %d\n", tStatus);
555 }
556 }
557
558 /**
559 * \fn smeSm_ConnWhenConnecting
560 * \brief Starts the connect process again
561 *
562 * Starts the connect process again
563 *
564 * \param hSme - handle to the SME object
565 * \return None
566 * \sa smeSm_Connect
567 */
smeSm_ConnWhenConnecting(TI_HANDLE hSme)568 void smeSm_ConnWhenConnecting (TI_HANDLE hSme)
569 {
570 TSme *pSme = (TSme*)hSme;
571 TI_STATUS tStatus;
572
573 /* start the connection process */
574 tStatus = conn_start (pSme->hConn, CONN_TYPE_FIRST_CONN, sme_ReportConnStatus, hSme, TI_FALSE, TI_FALSE);
575 if (TI_OK != tStatus)
576 {
577 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_ConnWhenConnecting: conn_start returned status %d\n", tStatus);
578 }
579 }
580
581 /**
582 * \fn smeSm_ActionUnexpected
583 * \brief Called when an unexpected event (for current state) is received
584 *
585 * Called when an unexpected event (for current state) is received
586 *
587 * \param hSme - handle to the SME object
588 * \return None
589 */
smeSm_ActionUnexpected(TI_HANDLE hSme)590 void smeSm_ActionUnexpected (TI_HANDLE hSme)
591 {
592 TSme *pSme = (TSme*)hSme;
593
594 TRACE0(pSme->hReport, REPORT_SEVERITY_ERROR , "smeSm_ActionUnexpected called\n");
595 }
596
597 /**
598 * \fn smeSm_NopAction
599 * \brief Called when event call and don't need to do nothing.
600 *
601 * \param hSme - handle to the SME object
602 * \return None
603 */
smeSm_NopAction(TI_HANDLE hSme)604 void smeSm_NopAction (TI_HANDLE hSme)
605 {
606 TSme *pSme = (TSme*)hSme;
607
608 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "smeSm_NopAction called\n");
609 }
610
smeSm_CheckStartConditions(TI_HANDLE hSme)611 void smeSm_CheckStartConditions (TI_HANDLE hSme)
612 {
613 TSme *pSme = (TSme*)hSme;
614
615 if ((TI_TRUE == pSme->bRunning) && (TI_TRUE == pSme->bRadioOn))
616 {
617 /* send a start event */
618 genSM_Event (pSme->hSmeSm, SME_SM_EVENT_START, hSme);
619 }
620 }
621
622
623 /* do we need to verify G only / A only / dual-band with site mgr? or rely on channels only? */
624
625 /**
626 * \fn sme_StartScan
627 * \brief Set scan parameters and calls scan concnetartor to start the scan operation.
628 *
629 * Set scan parameters and calls scan concnetartor to start the scan operation.
630 *
631 * Scan parameters are set according to scan target - find country IE, find desired SSID, or both
632 * (one on each band). To find country IE we use passive scan forever, to find the desired SSID we
633 * use active scan until the current country IE expires. In addition, we take into account the WSC PB
634 * mode - scan constantly for two minutes (but under the country validity and expiry constraints)
635 *
636 * \param hSme - handle to the SME object
637 * \return TI_OK if scan started successfully, TI_NOK otherwise
638 * \sa smeSm_PreConnect
639 */
sme_StartScan(TI_HANDLE hSme)640 TI_STATUS sme_StartScan (TI_HANDLE hSme)
641 {
642 TSme *pSme = (TSme*)hSme;
643 paramInfo_t *pParam;
644 TI_BOOL bDEnabled, bCountryValid;
645 TI_BOOL bBandChannelExist[ RADIO_BAND_NUM_OF_BANDS ];
646 TI_BOOL bBandCountryFound[ RADIO_BAND_NUM_OF_BANDS ];
647 TI_STATUS tStatus;
648 TI_UINT32 uIndex;
649
650 /* get 802.11d enable state */
651 pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t));
652 if (!pParam)
653 return TI_NOK;
654
655 pParam->paramType = REGULATORY_DOMAIN_ENABLED_PARAM;
656 regulatoryDomain_getParam (pSme->hRegDomain, pParam);
657 bDEnabled = pParam->content.regulatoryDomainEnabled;
658
659 pParam->paramType = REGULATORY_DOMAIN_IS_COUNTRY_FOUND;
660 /* get country validity for all bands */
661 for (uIndex = 0; uIndex < RADIO_BAND_NUM_OF_BANDS; uIndex++)
662 {
663 pParam->content.eRadioBand = uIndex;
664 regulatoryDomain_getParam (pSme->hRegDomain, pParam);
665 bBandCountryFound[ uIndex ] = pParam->content.bIsCountryFound;
666 /* also nullify the channel exist indication for this band */
667 bBandChannelExist[ uIndex ] = TI_FALSE;
668 }
669 os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t));
670
671 /* First fill the channels */
672 for (uIndex = 0; uIndex < pSme->tInitParams.uChannelNum; uIndex++)
673 {
674 /* for each channel, if country is found, set active scan */
675 pSme->tScanParams.tChannels[ uIndex ].eBand = pSme->tInitParams.tChannelList[ uIndex ].eBand;
676 pSme->tScanParams.tChannels[ uIndex ].uChannel = pSme->tInitParams.tChannelList[ uIndex ].uChannel;
677 pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs = pSme->tInitParams.uMaxScanDuration;
678 pSme->tScanParams.tChannels[ uIndex ].uMinDwellTimeMs = pSme->tInitParams.uMinScanDuration;
679 pSme->tScanParams.tChannels[ uIndex ].uTxPowerLevelDbm = DEF_TX_POWER;
680
681 /* if 802.11d is disabled, or country is available for this band */
682 if ((TI_FALSE == bDEnabled) ||
683 (TI_TRUE == bBandCountryFound[ pSme->tInitParams.tChannelList[ uIndex ].eBand ]))
684 {
685 /* set active scan */
686 pSme->tScanParams.tChannels[ uIndex ].eScanType = SCAN_TYPE_NORMAL_ACTIVE;
687 }
688 /* 802.11d is enabled and no country available */
689 else
690 {
691 /* set passive scan */
692 pSme->tScanParams.tChannels[ uIndex ].eScanType = SCAN_TYPE_NORMAL_PASSIVE;
693
694 /*
695 * in order to fined country set uMaxDwellTimeMs ( that at passive scan set the passiveScanDuration )
696 * to significant value
697 */
698 pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs = SCAN_CNCN_REGULATORY_DOMAIN_PASSIVE_DWELL_TIME_DEF;
699 }
700 /* mark that a channel exists for this band */
701 bBandChannelExist[ pSme->tInitParams.tChannelList[ uIndex ].eBand ] = TI_TRUE;
702 }
703 /* set number of channels */
704 pSme->tScanParams.uChannelNum = pSme->tInitParams.uChannelNum;
705
706 /* now, fill global parameters */
707 pSme->tScanParams.uProbeRequestNum = pSme->tInitParams.uProbeReqNum;
708 pSme->tScanParams.iRssiThreshold = pSme->tInitParams.iRssiThreshold;
709 pSme->tScanParams.iSnrThreshold = pSme->tInitParams.iSnrThreshold;
710 pSme->tScanParams.bTerminateOnReport = TI_TRUE;
711 pSme->tScanParams.uFrameCountReportThreshold = 1;
712
713 /*
714 * if for at least one band country is known and scan is performed on this band - means we need to
715 * take into consideration country expiry, plus we are scanning for the desired SSID
716 */
717 bCountryValid = ((TI_TRUE == bBandChannelExist[ RADIO_BAND_2_4_GHZ ]) && (TI_TRUE == bBandCountryFound[ RADIO_BAND_2_4_GHZ ])) ||
718 ((TI_TRUE == bBandChannelExist[ RADIO_BAND_5_0_GHZ ]) && (TI_TRUE == bBandCountryFound[ RADIO_BAND_5_0_GHZ ]));
719
720 /* set SSID(s) and BSS type according to 802.11d status, and country availability */
721 /* if 802.11d is disabled */
722 if (TI_FALSE == bDEnabled)
723 {
724 pSme->tScanParams.eBssType = pSme->eBssType;
725 /* set the deisred SSID, or any SSID if this is the desired SSID */
726 if (SSID_TYPE_ANY == pSme->eSsidType)
727 {
728 pSme->tScanParams.uSsidNum = 0;
729 pSme->tScanParams.uSsidListFilterEnabled = 1;
730 }
731 else
732 {
733 pSme->tScanParams.tDesiredSsid[ 0 ].eVisability = SCAN_SSID_VISABILITY_HIDDEN;
734 os_memoryCopy (pSme->hOS, &(pSme->tScanParams.tDesiredSsid[ 0 ].tSsid), &(pSme->tSsid), sizeof (TSsid));
735 pSme->tScanParams.uSsidNum = 1;
736 pSme->tScanParams.uSsidListFilterEnabled = 1;
737 }
738 }
739 /* Country code exists and scan is performed on this band - take country expiry timr into account */
740 else if (TI_TRUE == bCountryValid)
741 {
742 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_StartScan: performing active scan to find desired SSID\n");
743
744 /* we already know that at least on one band we know the country IE, so we scan for our SSID */
745 pSme->tScanParams.tDesiredSsid[ 0 ].eVisability = SCAN_SSID_VISABILITY_HIDDEN;
746 os_memoryCopy (pSme->hOS, &(pSme->tScanParams.tDesiredSsid[ 0 ].tSsid), &(pSme->tSsid), sizeof (TSsid));
747 /*
748 * if, in addition, we scan the other band to find its country, and the desired SSDI is not any SSID,
749 * add an empty SSID
750 */
751 if ((SSID_TYPE_ANY != pSme->eSsidType) &&
752 (((TI_TRUE == bBandChannelExist[ RADIO_BAND_2_4_GHZ ]) && (TI_FALSE == bBandCountryFound[ RADIO_BAND_2_4_GHZ ])) ||
753 ((TI_TRUE == bBandChannelExist[ RADIO_BAND_5_0_GHZ ]) && (TI_FALSE == bBandCountryFound[ RADIO_BAND_5_0_GHZ ]))))
754 {
755 pSme->tScanParams.tDesiredSsid[ 1 ].eVisability = SCAN_SSID_VISABILITY_PUBLIC;
756 pSme->tScanParams.tDesiredSsid[ 1 ].tSsid.len = 0;
757 pSme->tScanParams.uSsidNum = 2;
758 pSme->tScanParams.uSsidListFilterEnabled = 1;
759 /*
760 * since we are also looking for an AP with country IE (not include in IBSS), we need to make sure
761 * the desired BSS type include infrastructure BSSes.
762 */
763 if (BSS_INDEPENDENT == pSme->eBssType)
764 {
765 /* the desired is only IBSS - scan for any */
766 pSme->tScanParams.eBssType = BSS_ANY;
767 }
768 else
769 {
770 /* the desired is either infrastructure or any - use it */
771 pSme->tScanParams.eBssType = pSme->eBssType;
772 }
773 }
774 else
775 {
776 pSme->tScanParams.uSsidNum = 1;
777 pSme->tScanParams.uSsidListFilterEnabled = 1;
778 /* only looking for the desired SSID - set the desired BSS type */
779 pSme->tScanParams.eBssType = pSme->eBssType;
780 }
781 }
782 /* no scanned band has a counrty code - meaning all scan is passive (to find country) */
783 else
784 {
785 TRACE0(pSme->hReport, REPORT_SEVERITY_INFORMATION , "sme_StartScan: performing passive scan to find country IE\n");
786 pSme->tScanParams.eBssType = BSS_INFRASTRUCTURE; /* only an AP would transmit a country IE */
787 pSme->tScanParams.uSsidNum = 0;
788 pSme->tScanParams.uSsidListFilterEnabled = 1;
789 }
790
791 /* update scan cycle number and scan intervals according to 802.11d status and country availability */
792 sme_updateScanCycles (hSme, bDEnabled, bCountryValid, pSme->bConstantScan);
793
794 /* Finally(!!!), start the scan */
795 tStatus = scanCncn_StartPeriodicScan (pSme->hScanCncn, SCAN_SCC_DRIVER, &(pSme->tScanParams));
796 if (SCAN_CRS_SCAN_RUNNING != tStatus)
797 {
798 TRACE1(pSme->hReport, REPORT_SEVERITY_ERROR , "sme_StartScan: scan concentrator returned status %d\n", tStatus);
799 return TI_NOK;
800 }
801
802 return TI_OK;
803 }
804
805 /**
806 * \fn sme_updateScanCycles
807 * \brief Updates the scan intervals and cycle number according to 802.11d status, country availability and WSC PB mode
808 *
809 * Updates the scan intervals and cycle number according to 802.11d status, country availability and WSC PB mode.
810 * Possible scenarios - D disabled - WSC PB off - scan forever with supplied intervals
811 * - D enabled - country unknown - WSC PB off - scan forever with supplied intervals
812 * - D disabled - WSC PB on - scan for two minutes with zero intervals
813 * - D enabled - country unknown - WSC PB on - scan for two minutes with zero intervals
814 * - D enabled - country known - WSC PB off - scan until country expiry with supplied intervals
815 * - D enabled - country known - WSC PB on - scan for the minimu of two minutes and country expiry with zero intervals
816 *
817 * \param hSme - handle to the SME object
818 * \param bDEnabled - TRUE if 802.11d is enabled
819 * \param bCountryValid - TRUE if a country IE is valid for a band on which we scan
820 * \param bConstantScan - TRUE if WSC PB mode is on
821 * \return None
822 * \sa sme_CalculateCyclesNumber, sme_StartScan
823 */
sme_updateScanCycles(TI_HANDLE hSme,TI_BOOL bDEnabled,TI_BOOL bCountryValid,TI_BOOL bConstantScan)824 void sme_updateScanCycles (TI_HANDLE hSme,
825 TI_BOOL bDEnabled,
826 TI_BOOL bCountryValid,
827 TI_BOOL bConstantScan)
828 {
829 TSme *pSme = (TSme*)hSme;
830 TI_UINT32 uIndex, uScanPeriodMs, uScanDurationMs;
831 paramInfo_t *pParam;
832
833 /* 802.11d is disabled, or no country is valid */
834 if ((TI_FALSE == bDEnabled) || (TI_FALSE == bCountryValid))
835 {
836 /* WSC PB mode is disabled */
837 if (TI_FALSE == bConstantScan)
838 {
839 /*
840 * copy intervals
841 * In order to avoid tight loop of scan-select or scan-select-connecting operation,
842 * the prepare scan function takes into account the value of the scan_count when setting the 16 periods in the scan command
843 */
844 os_memoryCopy (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]),
845 &(pSme->tInitParams.uScanIntervals[ pSme->uScanCount ]), sizeof (TI_UINT32) * (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount));
846
847 for(uIndex = (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount); uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM; uIndex++)
848 {
849 pSme->tScanParams.uCycleIntervalMsec[ uIndex ] = pSme->tInitParams.uScanIntervals[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1 ];
850 }
851
852 /* scan for default number (until a result is found) */
853 pSme->tScanParams.uCycleNum = pSme->tInitParams.uCycleNum;
854 }
855 /* WSC PB mode is enabled */
856 else
857 {
858 /* turn off WSC PB mode (for next scan) */
859 pSme->bConstantScan = TI_FALSE;
860
861 /* nullify all intervals */
862 os_memoryZero (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]),
863 sizeof (TI_UINT32) * PERIODIC_SCAN_MAX_INTERVAL_NUM);
864
865 /* calculate the duration of one scan cycle */
866 uScanDurationMs = 0;
867 for (uIndex = 0; uIndex < pSme->tScanParams.uChannelNum; uIndex++)
868 {
869 uScanDurationMs += pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs;
870 }
871
872 /* set the number of cycles - 2 minutes divided by one cycle duration */
873 pSme->tScanParams.uCycleNum = (120000 / uScanDurationMs) + 1;
874 }
875 }
876 /* 802.11d is enabled, and country is valid on at least one band */
877 else
878 {
879 pParam = (paramInfo_t *)os_memoryAlloc(pSme->hOS, sizeof(paramInfo_t));
880 if (!pParam)
881 return;
882
883 /* get country expiry time */
884 pParam->paramType = REGULATORY_DOMAIN_TIME_TO_COUNTRY_EXPIRY;
885 regulatoryDomain_getParam (pSme->hRegDomain, pParam);
886
887 /* WSC PB mode is disabled */
888 if (TI_FALSE == bConstantScan)
889 {
890 /*
891 * copy intervals
892 * In order to avoid tight loop of scan-select or scan-select-connecting operation,
893 * the prepare scan function takes into account the value of the scan_count when setting the 16 periods in the scan command
894 */
895 os_memoryCopy (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]),
896 &(pSme->tInitParams.uScanIntervals[ pSme->uScanCount ]), sizeof (TI_UINT32) * (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount));
897
898 for(uIndex = (PERIODIC_SCAN_MAX_INTERVAL_NUM - pSme->uScanCount); uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM; uIndex++)
899 {
900 pSme->tScanParams.uCycleIntervalMsec[ uIndex ] = pSme->tInitParams.uScanIntervals[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1 ];
901 }
902
903 /* set cycle number according to country expiry time */
904 sme_CalculateCyclesNumber (hSme, pParam->content.uTimeToCountryExpiryMs);
905 }
906 /* WSC PB mode is enabled */
907 else
908 {
909 /* turn off WSC PB mode (for next scan) */
910 pSme->bConstantScan = TI_FALSE;
911
912 /* set scan period to minimum of WSC PB duration (2 minutes) and country expiry time */
913 uScanPeriodMs = TI_MIN (120000, pParam->content.uTimeToCountryExpiryMs);
914
915 /* nullify all intervals */
916 os_memoryZero (pSme->hOS, &(pSme->tScanParams.uCycleIntervalMsec[ 0 ]),
917 sizeof (TI_UINT32) * PERIODIC_SCAN_MAX_INTERVAL_NUM);
918
919 /* calculate the duration of one scan cycle */
920 uScanDurationMs = 0;
921 for (uIndex = 0; uIndex < pSme->tScanParams.uChannelNum; uIndex++)
922 {
923 uScanDurationMs += pSme->tScanParams.tChannels[ uIndex ].uMaxDwellTimeMs;
924 }
925
926 if (uScanDurationMs != 0)
927 {
928 /* set the number of cycles - scan period divided by one cycle duration */
929 pSme->tScanParams.uCycleNum = (uScanPeriodMs / uScanDurationMs) + 1;
930 }
931 else
932 {
933 pSme->tScanParams.uCycleNum = pSme->tInitParams.uCycleNum;
934 }
935 }
936 os_memoryFree(pSme->hOS, pParam, sizeof(paramInfo_t));
937 }
938
939 /* in case independent mode and to avoid supplicant send disconnect event after 60s */
940 if (pSme->eBssType != BSS_INFRASTRUCTURE)
941 {
942 pSme->tScanParams.uCycleNum = 1;
943 }
944 }
945
946 /**
947 * \fn sme_CalculateCyclesNumber
948 * \brief Calculates the cycle number required for a gicen time, according to scan intervals
949 *
950 * Calculates the cycle number required for a gicen time, according to scan intervals. First check the 16
951 * different intervals, and if more time is available, find how many cycles still fit. Write the result
952 * to the SME scan command
953 *
954 * \param hSme - handle to the SME object
955 * \param uToTalTimeMs - the total periodic scan operation duartion
956 * \return None
957 * \sa sme_updateScanCycles, sme_StartScan
958 */
sme_CalculateCyclesNumber(TI_HANDLE hSme,TI_UINT32 uTotalTimeMs)959 void sme_CalculateCyclesNumber (TI_HANDLE hSme, TI_UINT32 uTotalTimeMs)
960 {
961 TSme *pSme = (TSme*)hSme;
962 TI_UINT32 uIndex, uCurrentTimeMs = 0;
963
964 /*
965 * the total time should exceed country code expiration by one interval (so that next scan wouldn't
966 * have a valid country code)
967 */
968
969 /* nullify cycle number */
970 pSme->tScanParams.uCycleNum = 0;
971 /* now find how many cycles fit within this time. First, check if all first 16 configured intervals fit */
972 for (uIndex = 0;
973 (uIndex < PERIODIC_SCAN_MAX_INTERVAL_NUM) && (uCurrentTimeMs < uTotalTimeMs);
974 uIndex++)
975 {
976 pSme->tScanParams.uCycleNum++;
977 uCurrentTimeMs += pSme->tScanParams.uCycleIntervalMsec[ uIndex ];
978 }
979 /* now find out how many more cycles with the last interval still fits */
980 if (uCurrentTimeMs < uTotalTimeMs)
981 {
982 /*
983 * divide the reamining time (time until expiry minus the total time calculated so far)
984 * by the last interval time, to get how many more scans would fit after the first 16 intervals
985 */
986 pSme->tScanParams.uCycleNum += (uTotalTimeMs - uCurrentTimeMs) /
987 pSme->tScanParams.uCycleIntervalMsec[ PERIODIC_SCAN_MAX_INTERVAL_NUM - 1];
988 /* and add one, to compensate for the reminder */
989 pSme->tScanParams.uCycleNum++;
990 }
991 }
992
993