• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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