Wi-Fi Fundamentals Course - Lesson 2, Exercise 2 fix for BSSID

In the Wi-Fi Fundamentals Course, Lesson 2, Exercise 2 (step 7.2) I found that it is necessary to clear the bssid parameter in the wifi_connect_req_params structure.  If it is not cleared and happens to have a non-zero value, then the Wi-Fi stack will assume it is a valid requested BSSID and only connect to an Access Point with a matching BSSID (MAC address).  That makes it never connect unless you are lucky and the bssid bytes were cleared.  I added the `memset` line to fix the problem:

	/* STEP 7.2 - Populate the rest of the relevant members */
	params->channel = WIFI_CHANNEL_ANY;
	params->security = WIFI_SECURITY_TYPE_PSK;
	params->mfp = WIFI_MFP_DISABLE;
	params->timeout = SYS_FOREVER_MS;
	params->band = WIFI_FREQ_BAND_UNKNOWN;
	// This is required.  If a random non-zero bssid is set, then it will think we require an AP with that MAC/BSSID
	memset(params->bssid, 0, sizeof(params->bssid));

Parents
  • Hi Glen,

    Thanks for the suggestion. I've forwarded this to the team responsible for this course.

    What NCS version are you using when seeing this issue btw?

    Regards,

    Elfving

  • HI Elfving.

    I am using NCS v2.6.1.

    I went through the library code and found the point where it checks if the bssid is non-zero, and then uses that as criteria for finding a matching Access Point.

    I don't know if this matters, but I have four AP's on my network (two dual channel APs) so the library code finds the list from the scan and then has additional logic to pick which one to connect to.  But it looked to me like the code uses the BSSID as an additional filter, so whether there were several or just one APs that had the right SSID, a non-zero BSSID makes it only match to an AP with that MAC address.  So if the passed bssid is just random uninitialized bits then it will not match anything.

    Glen

  • I've had a talk with the team responsible now and they say that the solution is correct. If BSSID is specified, then only that network is chosen.

    Regards,

    Elfving

  • Agreed.  And that is the problem.  From my understanding of C initialization, only static and global structs are guaranteed to get initialized to zero automatically.  But the `cnx_params` structure in the main() function is not static or global, so it can have random trash in it unless explicitly initialized.  So since the code in the lesson didn't set the bssid member, it might not be zero, as I saw in my application.  So then the network stack thinks you want to only connect to that random BSSID, and it will fail.

    So to prevent problems, either the bssid structure member needs to be explicitly set to 0, or the whole structure can be initialized to zero in main() with:

    struct wifi_connect_req_params cnx_params = { 0 };

    These code examples make it more clear.  The first shows what is in the uninitialized cnx_params as written in the course.  As you can see, the cnx_struct is filled with whatever random stuff is in RAM, and the bssid has a non-zero value, meaning that the lesson code can fail to connect to this random BSSID:

    int main(void)
    {
    	struct wifi_connect_req_params cnx_params;
    	LOG_HEXDUMP_WRN(&cnx_params, sizeof(cnx_params), "Uninitialized cnx_params in main():");
    	LOG_HEXDUMP_INF(&cnx_params.bssid, sizeof(cnx_params.bssid), "cnx_params.bssid:");
    

    This gives the following output:

    [00:00:00.657,226] <wrn> coex: Uninitialized wifi_connect_req_params in main():
                                   a9 0b 00 00 68 d1 01 20  33 f1 01 00 e7 03 00 00 |....h..  3.......
                                   00 00 00 00 90 1c 00 20  68 a3 00 20 00 10 00 00 |.......  h.. ....
                                   7b 71 04 00                                      |{q..             
    [00:00:00.657,226] <inf> coex: cnx_params.bssid:
                                   a3 00 20 00 10 00                                |.. ...           
    

    But if the code explicitly fills the struct with 0's, then the bssid and all other members will be guaranteed to be 0 to start:

    int main(void)
    {
    	struct wifi_connect_req_params cnx_params2 = {0};
    	LOG_HEXDUMP_WRN(&cnx_params2, sizeof(cnx_params2), "Initialized cnx_params2 in main():");
    	LOG_HEXDUMP_INF(&cnx_params2.bssid, sizeof(cnx_params2.bssid), "cnx_params2.bssid:");
    

    ...as you can see below:

    [00:00:00.660,339] <wrn> coex: Initialized cnx_params2 in main():
                                   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |........ ........
                                   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |........ ........
                                   00 00 00 00                                      |....             
    [00:00:00.660,369] <inf> coex: cnx_params2.bssid:
                                   00 00 00 00 00 00                                |......           
    

Reply
  • Agreed.  And that is the problem.  From my understanding of C initialization, only static and global structs are guaranteed to get initialized to zero automatically.  But the `cnx_params` structure in the main() function is not static or global, so it can have random trash in it unless explicitly initialized.  So since the code in the lesson didn't set the bssid member, it might not be zero, as I saw in my application.  So then the network stack thinks you want to only connect to that random BSSID, and it will fail.

    So to prevent problems, either the bssid structure member needs to be explicitly set to 0, or the whole structure can be initialized to zero in main() with:

    struct wifi_connect_req_params cnx_params = { 0 };

    These code examples make it more clear.  The first shows what is in the uninitialized cnx_params as written in the course.  As you can see, the cnx_struct is filled with whatever random stuff is in RAM, and the bssid has a non-zero value, meaning that the lesson code can fail to connect to this random BSSID:

    int main(void)
    {
    	struct wifi_connect_req_params cnx_params;
    	LOG_HEXDUMP_WRN(&cnx_params, sizeof(cnx_params), "Uninitialized cnx_params in main():");
    	LOG_HEXDUMP_INF(&cnx_params.bssid, sizeof(cnx_params.bssid), "cnx_params.bssid:");
    

    This gives the following output:

    [00:00:00.657,226] <wrn> coex: Uninitialized wifi_connect_req_params in main():
                                   a9 0b 00 00 68 d1 01 20  33 f1 01 00 e7 03 00 00 |....h..  3.......
                                   00 00 00 00 90 1c 00 20  68 a3 00 20 00 10 00 00 |.......  h.. ....
                                   7b 71 04 00                                      |{q..             
    [00:00:00.657,226] <inf> coex: cnx_params.bssid:
                                   a3 00 20 00 10 00                                |.. ...           
    

    But if the code explicitly fills the struct with 0's, then the bssid and all other members will be guaranteed to be 0 to start:

    int main(void)
    {
    	struct wifi_connect_req_params cnx_params2 = {0};
    	LOG_HEXDUMP_WRN(&cnx_params2, sizeof(cnx_params2), "Initialized cnx_params2 in main():");
    	LOG_HEXDUMP_INF(&cnx_params2.bssid, sizeof(cnx_params2.bssid), "cnx_params2.bssid:");
    

    ...as you can see below:

    [00:00:00.660,339] <wrn> coex: Initialized cnx_params2 in main():
                                   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |........ ........
                                   00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 |........ ........
                                   00 00 00 00                                      |....             
    [00:00:00.660,369] <inf> coex: cnx_params2.bssid:
                                   00 00 00 00 00 00                                |......           
    

Children
Related