Introduce w_info_mutex to protect g_manager_info of wifi_manager while limiting the...
authorSeongil Hahm <seongil.hahm@samsung.com>
Mon, 25 Sep 2017 10:14:00 +0000 (03:14 -0700)
committerSeongil Hahm <seongil.hahm@samsung.com>
Tue, 26 Sep 2017 08:54:57 +0000 (01:54 -0700)
1. By using this w_info_mutex, deadlock between wifi_manager and slsi_wifi callback is resolved.
2. Introduce additional wifi_manager status: WIFI_MODE_CHAING, WIFI_INITIALIZING, WIFI_DEINITIALIZING, and WIFI_FAILURE.
   In case of WIFI_FAILURE, app developers are requested to deinit and init wifi_manager.
3. wifi_manager_set_mode() returns WIFI_MANAGER_INVALID_ARGS when mode is softap without config.

apps/examples/testcase/ta_tc/wifi_manager/utc/utc_wifi_manager_main.c
framework/include/wifi_manager/wifi_manager.h
framework/src/wifi_manager/wifi_manager.c

index e82cfc8..3e5550c 100644 (file)
@@ -143,7 +143,7 @@ static void utc_wifi_manager_set_mode_n(void)
 
        ret = wifi_manager_set_mode(SOFTAP_MODE, NULL);
 
-       TC_ASSERT_EQ("wifi_manager_set_mode_n", ret, WIFI_MANAGER_FAIL);
+       TC_ASSERT_EQ("wifi_manager_set_mode_n", ret, WIFI_MANAGER_INVALID_ARGS);
 
        wifi_manager_softap_config_s ap_config;
        strncpy(ap_config.ssid, CONFIG_EXAMPLES_TESTCASE_WIFI_MANAGER_UTC_SOFTAP_SSID, \
@@ -388,7 +388,7 @@ int wifi_manager_utc(int argc, FAR char *argv[])
        utc_wifi_utils_disconnect_ap_p();
 
        WIFITEST_WAIT;
-       
+
        utc_wifi_utils_disconnect_ap_n();       //  Should be run after positive tc, that is, the second disconnect gets failed.
 
        utc_wifi_manager_deinit_p();
index 5edea22..f18fc71 100644 (file)
@@ -60,7 +60,11 @@ typedef enum {
 typedef enum {
        WIFI_NONE = -1,
        STA_MODE,
-       SOFTAP_MODE
+       SOFTAP_MODE,
+       WIFI_MODE_CHANGING,
+       WIFI_INITIALIZING,
+       WIFI_DEINITIALIZING,
+       WIFI_FAILURE
 } wifi_manager_mode_e;
 
 typedef enum {
index 89ec492..935489a 100644 (file)
@@ -55,6 +55,7 @@ void __tizenrt_manual_linkset(const char *msg)
 static wifi_manager_info_s g_manager_info;
 static wifi_manager_cb_s *g_manager_callback = NULL;
 static wifi_mutex *w_mutex = NULL;
+static wifi_mutex *w_info_mutex = NULL;
 
 static wifi_utils_result_e start_dhcp_client(void)
 {
@@ -69,6 +70,7 @@ static wifi_utils_result_e start_dhcp_client(void)
        ret = dhcpc_request(g_dhcp_handle, &state);
        if (ret != OK) {
                dhcpc_close(g_dhcp_handle);
+               g_dhcp_handle = NULL;
                return WIFI_UTILS_FAIL;
        }
 
@@ -148,8 +150,7 @@ static void wifi_linkup_event_func(void)
        wifi_manager_cb_s *wifi_cb = g_manager_callback;
        wifi_utils_info info;
 
-       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
-
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
        if (g_manager_info.mode == STA_MODE) {
                nvdbg("WIFI CONNECTED AP - STA MODE");
                wifi_status_set(AP_CONNECTED);
@@ -157,7 +158,8 @@ static void wifi_linkup_event_func(void)
                /* Perform DHCP client */
                if (start_dhcp_client() != WIFI_UTILS_SUCCESS) {
                        ndbg("DHCP client start failed\n");
-                       wifi_mutex_release(w_mutex);
+                       g_manager_info.mode = WIFI_FAILURE;
+                       wifi_mutex_release(w_info_mutex);
                        return;
                }
                if (stop_dhcp_client() != WIFI_UTILS_SUCCESS) {
@@ -174,8 +176,7 @@ static void wifi_linkup_event_func(void)
                        g_manager_info.status = STATUS_UNKNOWN;
                }
                strncpy(g_manager_info.ip4_address, ip4_add_str, 18);
-
-               wifi_mutex_release(w_mutex);
+               wifi_mutex_release(w_info_mutex);
 
                if (wifi_cb != NULL && wifi_cb->sta_connected != NULL) {
                        wifi_cb->sta_connected();
@@ -185,8 +186,7 @@ static void wifi_linkup_event_func(void)
        } else if (g_manager_info.mode == SOFTAP_MODE) {
                nvdbg("CONNECTED FROM CLIENT - SOFT AP MODE");
                wifi_status_set(CLIENT_CONNECTED);
-
-               wifi_mutex_release(w_mutex);
+               wifi_mutex_release(w_info_mutex);
 
                /* No callbacks here, in case new client joins, we invoke callback
                 * from DHCP server instead
@@ -207,7 +207,7 @@ static void wifi_linkdown_event_func(void)
 // wifi_manager_init() creates the callback handler and deinit() joins the callback handler.
        wifi_manager_cb_s *wifi_cb = g_manager_callback;
 
-       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
 
        if (g_manager_info.mode == STA_MODE) {
                nvdbg("WIFI DISCONNECTED AP - STA MODE");
@@ -215,6 +215,7 @@ static void wifi_linkdown_event_func(void)
                g_manager_info.ip4_address[0] = '\0';
                g_manager_info.rssi = 0;
                wifi_status_set(AP_DISCONNECTED);
+               wifi_mutex_release(w_info_mutex);
 
                if (wifi_cb != NULL && wifi_cb->sta_disconnected != NULL) {
                        wifi_cb->sta_disconnected();
@@ -224,6 +225,8 @@ static void wifi_linkdown_event_func(void)
        } else if (g_manager_info.mode == SOFTAP_MODE) {
                nvdbg("DISCONNECTED FROM CLIENT - SOFT AP MODE");
                wifi_status_set(CLIENT_DISCONNECTED);
+               wifi_mutex_release(w_info_mutex);
+
                if (wifi_cb != NULL && wifi_cb->softap_sta_left != NULL) {
                        wifi_cb->softap_sta_left();
                } else {
@@ -231,8 +234,6 @@ static void wifi_linkdown_event_func(void)
                }
        }
 
-       wifi_mutex_release(w_mutex);
-
 #ifdef CONFIG_ENABLE_IOTIVITY
        __tizenrt_manual_linkset("del");
 #endif
@@ -339,18 +340,19 @@ wifi_manager_result_e wifi_manager_connect_ap(wifi_manager_ap_config_s *config)
        wifi_utils_info info;
        wifi_utils_ap_config_s util_config;
 
+       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
        if (wifi_utils_get_info(&info) != WIFI_UTILS_SUCCESS) {
                ndbg("Wi-Fi info retrival fails.\n");
+               wifi_mutex_release(w_mutex);
                return WIFI_MANAGER_FAIL;
        }
 
        if (info.wifi_status == WIFI_UTILS_SOFTAP_MODE) {
                ndbg("Current mode soft ap mode, can not connect ap");
+               wifi_mutex_release(w_mutex);
                return WIFI_MANAGER_FAIL;
        }
 
-       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
-
        strncpy(util_config.ssid, config->ssid, config->ssid_length + 1);
        util_config.ssid_length = config->ssid_length;
        strncpy(util_config.passphrase, config->passphrase, config->passphrase_length + 1);
@@ -364,10 +366,11 @@ wifi_manager_result_e wifi_manager_connect_ap(wifi_manager_ap_config_s *config)
                wifi_mutex_release(w_mutex);
                return WIFI_MANAGER_FAIL;
        }
+       wifi_mutex_release(w_mutex);
 
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
        strncpy(g_manager_info.ssid, config->ssid, config->ssid_length + 1);
-
-       wifi_mutex_release(w_mutex);
+       wifi_mutex_release(w_info_mutex);
 
        return WIFI_MANAGER_SUCCESS;
 }
@@ -393,119 +396,184 @@ wifi_manager_result_e wifi_manager_init(wifi_manager_cb_s *wmcb)
                        return WIFI_MANAGER_FAIL;
        }
 
+       if (w_info_mutex == NULL) {
+               w_info_mutex = (wifi_mutex *)malloc(sizeof(wifi_mutex));
+               if (w_info_mutex == NULL) {
+                       ndbg("w_info_mutex malloc fails.\n");
+                       return WIFI_MANAGER_FAIL;
+               }
+               result = wifi_mutex_create(w_info_mutex);
+               if (result != WIFI_UTILS_SUCCESS) {
+                       ndbg("w_info_mutex_create fail");
+                       goto error_without_mutex_release;
+               }
+       }
+
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
        if (w_mutex != NULL) {
                ndbg("WI-FI is already initialized.\n");
+               wifi_mutex_release(w_info_mutex);
                return WIFI_MANAGER_INITIALIZED;
        }
 
        w_mutex = (wifi_mutex *)malloc(sizeof(wifi_mutex));
        if (w_mutex == NULL) {
                ndbg("w_mutex malloc fails.\n");
-               return WIFI_MANAGER_FAIL;
+               wifi_mutex_release(w_info_mutex);
+               goto error_with_mutex_destory;
        }
 
        result = wifi_mutex_create(w_mutex);
        if (result != WIFI_UTILS_SUCCESS) {
                ndbg("wifi_mutex_create fail");
-               goto error_without_mutex_release;
+               wifi_mutex_release(w_info_mutex);
+               goto error_with_mutex_destory;
        }
 
-       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
+       /* wifi_manager mode is switched to wifi_initializing */
+       g_manager_info.mode = WIFI_INITIALIZING;
+       wifi_mutex_release(w_info_mutex);
 
-       result = wifi_utils_init();
+#ifdef CONFIG_ENABLE_IOTIVITY
+       struct mq_attr lq_attr;
+       lq_attr.mq_maxmsg = 10;
+       lq_attr.mq_msgsize = 4;
+       lq_attr.mq_flags = 0;
+       g_dw_nwevent_mqfd = mq_open("netlink_evtq", O_WRONLY | O_CREAT, 0666, &lq_attr);
 
+       if (g_dw_nwevent_mqfd == (mqd_t)ERROR) {
+               ndbg("iotivity connect event message queue init fail");
+               goto error_with_mutex_destory_all;
+       }
+#endif
+
+       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
+       result = wifi_utils_init();
        if (result != WIFI_UTILS_SUCCESS) {
                ndbg("wifi_utils_init fail");
                goto error_with_mutex_release;
        }
 
        wifi_utils_register_callback(wifi_linkup_event_func, wifi_linkdown_event_func);
+
+       if (wifi_utils_get_info(&info) != WIFI_UTILS_SUCCESS) {
+               ndbg("wifi_utils_get_info fail");
+               goto error_with_mutex_release;
+       }
+       wifi_mutex_release(w_mutex);
+
+       /* update wifi_manager info by being protected by w_info_mutex */
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
        g_manager_info.ssid[0] = '\0';
        g_manager_info.ip4_address[0] = '\0';
        g_manager_info.rssi = 0;
        g_manager_info.mode = STA_MODE;
        g_manager_callback = wmcb;
        wifi_status_set(AP_DISCONNECTED);
-
-       if (wifi_utils_get_info(&info) != WIFI_UTILS_SUCCESS) {
-               ndbg("wifi_utils_get_info fail");
-               goto error_with_mutex_release;
-       }
        strncpy(g_manager_info.mac_address, info.mac_address, 6);
+       wifi_mutex_release(w_info_mutex);
+
+       return WIFI_MANAGER_SUCCESS;
 
+error_with_mutex_release:
        wifi_mutex_release(w_mutex);
 
 #ifdef CONFIG_ENABLE_IOTIVITY
-       struct mq_attr lq_attr;
-       lq_attr.mq_maxmsg = 10;
-       lq_attr.mq_msgsize = 4;
-       lq_attr.mq_flags = 0;
-       g_dw_nwevent_mqfd = mq_open("netlink_evtq", O_WRONLY | O_CREAT, 0666, &lq_attr);
-
-       if (g_dw_nwevent_mqfd == (mqd_t)ERROR) {
-               ndbg("iotivity connect event message queue init fail");
-               goto error_with_mutex_destory;
-       }
+error_with_mutex_destory_all:
 #endif
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
+       g_manager_info.mode = WIFI_NONE;
 
-       return WIFI_MANAGER_SUCCESS;
+       result = wifi_mutex_destroy(w_mutex);
+       if (result != WIFI_UTILS_SUCCESS) {
+               ndbg("wifi_mutex_destroy fail %d", result);
+       }
+       wifi_mutex_release(w_info_mutex);
 
-error_with_mutex_release:
-       wifi_mutex_release(w_mutex);
-#ifdef CONFIG_ENABLE_IOTIVITY
 error_with_mutex_destory:
-#endif
-               result = wifi_mutex_destroy(w_mutex);
-               if (result != WIFI_UTILS_SUCCESS) {
-                       ndbg("wifi_mutex_destroy fail %d", result);
-                       return WIFI_MANAGER_FAIL;
-               }
+       result = wifi_mutex_destroy(w_info_mutex);
+       if (result != WIFI_UTILS_SUCCESS) {
+               ndbg("w_info_mutex_destroy fail %d", result);
+       }
+
 error_without_mutex_release:
+       if (w_mutex != NULL) {
                free(w_mutex);
                w_mutex = NULL;
-               return WIFI_MANAGER_FAIL;
+       }
+       if (w_info_mutex != NULL) {
+               free(w_info_mutex);
+               w_info_mutex = NULL;
+       }
+
+       return WIFI_MANAGER_FAIL;
 }
 
 wifi_manager_result_e wifi_manager_deinit()
 {
        wifi_utils_result_e result = WIFI_UTILS_SUCCESS;
+       wifi_manager_result_e ret = WIFI_MANAGER_SUCCESS;
 
        if ((g_manager_info.mode == WIFI_NONE) || (w_mutex == NULL)) {
                ndbg("WI-FI is already deinitialized.\n");
                return WIFI_MANAGER_DEINITIALIZED;
        }
 
-       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
-
-       if ((g_manager_info.mode == SOFTAP_MODE) && (stop_dhcp_server() != WIFI_UTILS_SUCCESS)) {
-               ndbg("dhcp server stop fail\n");
-               wifi_mutex_release(w_mutex);
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
+       /* wifi_manager mode is switched to wifi_deinitializing */
+       if ((g_manager_info.mode != WIFI_INITIALIZING) && (g_manager_info.mode != WIFI_MODE_CHANGING) && \
+                       (g_manager_info.mode != WIFI_DEINITIALIZING)) {
+               g_manager_info.mode = WIFI_DEINITIALIZING;
+       } else {
+               ndbg("Can't deinitilize wifi_manager from the current wifi mode %d\n", g_manager_info.mode);
+               wifi_mutex_release(w_info_mutex);
                return WIFI_MANAGER_FAIL;
        }
 
-       result = wifi_utils_deinit();
+       if ((g_manager_info.mode == SOFTAP_MODE) || (g_manager_info.mode == WIFI_FAILURE)) {
+               stop_dhcp_server();
+       }
+       wifi_mutex_release(w_info_mutex);
 
+       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
+       result = wifi_utils_deinit();
        if (result != WIFI_UTILS_SUCCESS) {
                ndbg("wifi_utils_deinit fail");
-               wifi_mutex_release(w_mutex);
-               return WIFI_MANAGER_FAIL;
+               ret = WIFI_MANAGER_FAIL;
        }
+       wifi_mutex_release(w_mutex);
 
-       g_manager_info.mode = WIFI_NONE;
-
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
        ndbg("w_mutex->semcount: %d, w_mutex->flags: %d\n", w_mutex->semcount, w_mutex->flags);
 
-       wifi_mutex_release(w_mutex);
-
        result = wifi_mutex_destroy(w_mutex);
        if (result != WIFI_UTILS_SUCCESS) {
                ndbg("wifi_mutex_destroy fail %d", result);
-               return WIFI_MANAGER_FAIL;
+               ret = WIFI_MANAGER_FAIL;
        }
-       free(w_mutex);
-       w_mutex = NULL;
 
-       return WIFI_MANAGER_SUCCESS;
+       if (ret != WIFI_MANAGER_FAIL) {
+               g_manager_info.mode = WIFI_NONE;
+       } else {
+               g_manager_info.mode = WIFI_FAILURE;
+       }
+
+       if (w_mutex != NULL) {
+               free(w_mutex);
+               w_mutex = NULL;
+       }
+       wifi_mutex_release(w_info_mutex);
+
+       result = wifi_mutex_destroy(w_info_mutex);
+       if (result != WIFI_UTILS_SUCCESS) {
+               ndbg("w_info_mutex_destroy fail %d", result);
+       }
+       if (w_info_mutex != NULL) {
+               free(w_info_mutex);
+               w_info_mutex = NULL;
+       }
+
+       return ret;
 }
 
 wifi_manager_result_e wifi_manager_set_mode(wifi_manager_mode_e mode, wifi_manager_softap_config_s *config)
@@ -517,19 +585,31 @@ wifi_manager_result_e wifi_manager_set_mode(wifi_manager_mode_e mode, wifi_manag
                return WIFI_MANAGER_INVALID_ARGS;
        }
 
-       if ((mode == SOFTAP_MODE) && ((strlen(config->ssid) > 31) || (strlen(config->passphrase) > 63))) {
-               ndbg("SoftAP configuration fails: too long ssid or passphrase\n");
+       if ((mode == SOFTAP_MODE) && ((config == NULL) || (strlen(config->ssid) > 31) || (strlen(config->passphrase) > 63))) {
+               ndbg("SoftAP configuration fails: no config or too long ssid or passphrase\n");
                ndbg("Make sure that length of SSID < 32 and length of passphrase < 64\n");
                return WIFI_MANAGER_INVALID_ARGS;
        }
 
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
        if (g_manager_info.mode == mode) {
                ndbg("wifi manager set mode failed: current mode is the same as requested.\n");
+               wifi_mutex_release(w_info_mutex);
                return WIFI_MANAGER_SUCCESS;
        }
 
+       /* wifi mode is switched to WIFI_MODE_CHANGING */
+       if ((g_manager_info.mode != STA_MODE) && (g_manager_info.mode != SOFTAP_MODE)) {
+               ndbg("Can't change wifi mode from current mode %d.\n", g_manager_info.mode);
+               wifi_mutex_release(w_info_mutex);
+               return WIFI_MANAGER_FAIL;
+       }
+
+       g_manager_info.mode = WIFI_MODE_CHANGING;
+       wifi_mutex_release(w_info_mutex);
+
        // Wifi mode is changed to SOFT AP
-       if ((mode == SOFTAP_MODE) && (config != NULL)) {
+       if (mode == SOFTAP_MODE) {
                wifi_utils_softap_config_s softap_config;
 
                softap_config.channel = config->channel;
@@ -542,60 +622,64 @@ wifi_manager_result_e wifi_manager_set_mode(wifi_manager_mode_e mode, wifi_manag
                softap_config.inform_new_sta_join = g_manager_callback->softap_sta_joined;
 
                wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
-
                g_new_sta_join = softap_config.inform_new_sta_join;
                result = wifi_utils_start_softap(&softap_config);
-
                if (result != WIFI_UTILS_SUCCESS) {
-                       ndbg("Start softap mode fail");
-                       wifi_mutex_release(w_mutex);
-                       return WIFI_MANAGER_FAIL;
+                       ndbg("Starting softap mode failed.");
+                       goto error_with_failure;
                }
 
                if (start_dhcp_server() != WIFI_UTILS_SUCCESS) {
-                       ndbg("start DHCP server Failed\n");
-                       wifi_mutex_release(w_mutex);
-                       return WIFI_MANAGER_FAIL;
+                       ndbg("Starting DHCP server failed.\n");
+                       goto error_with_failure;
                }
+               wifi_mutex_release(w_mutex);
 
+               /* update wifi_manager_info */
+               wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
                g_manager_info.mode = SOFTAP_MODE;
                strncpy(g_manager_info.ssid, config->ssid, softap_config.ssid_length + 1);
                wifi_status_set(CLIENT_DISCONNECTED);
-               wifi_mutex_release(w_mutex);
+               wifi_mutex_release(w_info_mutex);
 
                nvdbg("Wifi mode is changed to SOFT AP");
        }
        // Wifi mode is changed to station
-       else if (mode == STA_MODE) {
+       else {
                wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
-
                result = wifi_utils_stop_softap();
                if (result != WIFI_UTILS_SUCCESS) {
-                       ndbg("Wifi stop fail");
-                       wifi_mutex_release(w_mutex);
-                       return WIFI_MANAGER_FAIL;
+                       ndbg("Stoping softap failed.");
+                       goto error_with_failure;
                }
 
                stop_dhcp_server();
 
                result = wifi_utils_start_sta();
                if (result != WIFI_UTILS_SUCCESS) {
-                       ndbg("start STA fail (change STA mode fail)");
-                       wifi_mutex_release(w_mutex);
-                       return WIFI_MANAGER_FAIL;
+                       ndbg("Starting STA failed.");
+                       goto error_with_failure;
                }
+               wifi_mutex_release(w_mutex);
 
+               /* update wifi_manager_info */
+               wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
                g_manager_info.mode = STA_MODE;
                wifi_status_set(AP_DISCONNECTED);
-               wifi_mutex_release(w_mutex);
+               wifi_mutex_release(w_info_mutex);
 
                nvdbg("Wifi mode is changed to station");
-       } else {
-                       ndbg("Invalid config!\n");
-                       return WIFI_MANAGER_FAIL;
        }
 
        return WIFI_MANAGER_SUCCESS;
+
+error_with_failure:
+       wifi_mutex_release(w_mutex);
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
+       g_manager_info.mode = WIFI_FAILURE;
+       wifi_mutex_release(w_info_mutex);
+
+       return WIFI_MANAGER_FAIL;
 }
 
 wifi_manager_result_e wifi_manager_get_info(wifi_manager_info_s *info)
@@ -605,9 +689,9 @@ wifi_manager_result_e wifi_manager_get_info(wifi_manager_info_s *info)
                return WIFI_MANAGER_FAIL;
        }
 
-       wifi_mutex_acquire(w_mutex, WIFI_UTILS_FOREVER);
+       wifi_mutex_acquire(w_info_mutex, WIFI_UTILS_FOREVER);
        *info = g_manager_info;
-       wifi_mutex_release(w_mutex);
+       wifi_mutex_release(w_info_mutex);
 
        return WIFI_MANAGER_SUCCESS;
 }
@@ -630,6 +714,6 @@ wifi_manager_result_e wifi_manager_scan_ap(void)
        }
 
        wifi_mutex_release(w_mutex);
-       
+
        return ret;
 }