Merge tag 'upstream/1.40' into tizen.
[platform/upstream/connman.git] / plugins / wifi.c
index 26b988e..bcb9344 100755 (executable)
@@ -49,7 +49,6 @@
 #include <connman/service.h>
 #include <connman/peer.h>
 #include <connman/log.h>
-#include <connman/option.h>
 #include <connman/storage.h>
 #include <include/setting.h>
 #include <connman/provision.h>
 #define BGSCAN_DEFAULT "simple:30:-65:300"
 #define AUTOSCAN_EXPONENTIAL "exponential:3:300"
 #define AUTOSCAN_SINGLE "single:3"
+#define SCAN_MAX_DURATION 10
 
 #define P2P_FIND_TIMEOUT 30
 #define P2P_CONNECTION_TIMEOUT 100
 #define P2P_LISTEN_PERIOD 500
 #define P2P_LISTEN_INTERVAL 2000
 
+#define ASSOC_STATUS_AUTH_TIMEOUT 16
 #define ASSOC_STATUS_NO_CLIENT 17
 #if defined TIZEN_EXT
 #define LOAD_SHAPING_MAX_RETRIES 7
@@ -210,6 +211,11 @@ struct wifi_data {
 #endif
 };
 
+struct disconnect_data {
+       struct wifi_data *wifi;
+       struct connman_network *network;
+};
+
 #if defined TIZEN_EXT
 #include "connman.h"
 #include "dbus.h"
@@ -223,7 +229,6 @@ static GHashTable *failed_bssids = NULL;
 static unsigned char buff_bssid[WIFI_BSSID_LEN_MAX] = { 0, };
 #endif
 
-
 static GList *iface_list = NULL;
 
 static GList *pending_wifi_device = NULL;
@@ -1153,15 +1158,23 @@ static GSupplicantP2PServiceParams *fill_in_peer_service_params(
 
        if (version > 0) {
                params->version = version;
-               params->service = g_memdup(spec, spec_length);
+               if (spec_length > 0) {
+                       params->service = g_malloc(spec_length);
+                       memcpy(params->service, spec, spec_length);
+               }
        } else if (query_length > 0 && spec_length > 0) {
-               params->query = g_memdup(query, query_length);
+               params->query = g_malloc(query_length);
+               memcpy(params->query, query, query_length);
                params->query_length = query_length;
 
-               params->response = g_memdup(spec, spec_length);
+               params->response = g_malloc(spec_length);
+               memcpy(params->response, spec, spec_length);
                params->response_length = spec_length;
        } else {
-               params->wfd_ies = g_memdup(spec, spec_length);
+               if (spec_length > 0) {
+                       params->wfd_ies = g_malloc(spec_length);
+                       memcpy(params->wfd_ies, spec, spec_length);
+               }
                params->wfd_ies_length = spec_length;
        }
 
@@ -1433,14 +1446,15 @@ static void wifi_newlink(unsigned flags, unsigned change, void *user_data)
        }
 
        if ((wifi->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
-               if (flags & IFF_LOWER_UP) {
+               if (flags & IFF_LOWER_UP)
                        DBG("carrier on");
-
-                       handle_tethering(wifi);
-               } else
+               else
                        DBG("carrier off");
        }
 
+       if (flags & IFF_LOWER_UP)
+               handle_tethering(wifi);
+
        wifi->flags = flags;
 }
 
@@ -1996,11 +2010,14 @@ static int get_hidden_connections_params(struct wifi_data *wifi,
                scan_params->num_ssids = i;
                scan_params->ssids = g_slist_reverse(scan_params->ssids);
 
-               scan_params->freqs = g_memdup(orig_params->freqs,
-                               sizeof(uint16_t) * orig_params->num_freqs);
-               if (!scan_params->freqs)
+               if (orig_params->num_freqs <= 0)
                        goto err;
 
+               scan_params->freqs =
+                       g_malloc(sizeof(uint16_t) * orig_params->num_freqs);
+               memcpy(scan_params->freqs, orig_params->freqs,
+                       sizeof(uint16_t) *orig_params->num_freqs);
+
                scan_params->num_freqs = orig_params->num_freqs;
 
        } else
@@ -2584,6 +2601,8 @@ static void interface_create_callback(int result,
                                                        void *user_data)
 {
        struct wifi_data *wifi = user_data;
+       char *bgscan_range_max;
+       long value;
 
        DBG("result %d ifname %s, wifi %p", result,
                                g_supplicant_interface_get_ifname(interface),
@@ -2599,6 +2618,24 @@ static void interface_create_callback(int result,
                wifi->interface_ready = true;
                finalize_interface_creation(wifi);
        }
+
+       /*
+        * Set the BSS expiration age to match the long scanning
+        * interval to avoid the loss of unconnected networks between
+        * two scans.
+        */
+       bgscan_range_max = strrchr(BGSCAN_DEFAULT, ':');
+       if (!bgscan_range_max || strlen(bgscan_range_max) < 1)
+               return;
+
+       value = strtol(bgscan_range_max + 1, NULL, 10);
+       if (value <= 0 || errno == ERANGE)
+               return;
+
+       if (g_supplicant_interface_set_bss_expiration_age(interface,
+                                       value + SCAN_MAX_DURATION) < 0) {
+               connman_warn("Failed to set bss expiration age");
+       }
 }
 
 static int wifi_enable(struct connman_device *device)
@@ -2606,7 +2643,7 @@ static int wifi_enable(struct connman_device *device)
        struct wifi_data *wifi = connman_device_get_data(device);
        int index;
        char *interface;
-       const char *driver = connman_option_get_string("wifi");
+       const char *driver = connman_setting_get_string("wifi");
        int ret;
 
        DBG("device %p %p", device, wifi);
@@ -3937,11 +3974,13 @@ static int network_connect(struct connman_network *network)
 static void disconnect_callback(int result, GSupplicantInterface *interface,
                                                                void *user_data)
 {
+       struct disconnect_data *dd = user_data;
+       struct connman_network *network = dd->network;
 #if defined TIZEN_EXT
        GList *list;
        struct wifi_data *wifi;
-       struct connman_network *network = user_data;
 
+       g_free(dd);
        DBG("network %p result %d", network, result);
 
        for (list = iface_list; list; list = list->next) {
@@ -3959,11 +3998,13 @@ static void disconnect_callback(int result, GSupplicantInterface *interface,
 
 found:
 #else
-       struct wifi_data *wifi = user_data;
+       struct wifi_data *wifi = dd->wifi;
+       g_free(dd);
 #endif
 
-       DBG("result %d supplicant interface %p wifi %p",
-                       result, interface, wifi);
+       DBG("result %d supplicant interface %p wifi %p networks: current %p "
+               "pending %p disconnected %p", result, interface, wifi,
+               wifi->network, wifi->pending_network, network);
 
        if (result == -ECONNABORTED) {
                DBG("wifi interface no longer available");
@@ -3975,12 +4016,21 @@ found:
                        (wifi->network != wifi->pending_network ||
                        connman_network_get_bool(wifi->network, "WiFi.Roaming")))
 #else
-       if (wifi->network && wifi->network != wifi->pending_network)
+       if (g_slist_find(wifi->networks, network))
 #endif
-               connman_network_set_connected(wifi->network, false);
-       wifi->network = NULL;
+               connman_network_set_connected(network, false);
 
        wifi->disconnecting = false;
+
+       if (network != wifi->network) {
+               if (network == wifi->pending_network)
+                       wifi->pending_network = NULL;
+               DBG("current wifi network has changed since disconnection");
+               return;
+       }
+
+       wifi->network = NULL;
+
        wifi->connected = false;
 
        if (wifi->pending_network) {
@@ -3994,6 +4044,7 @@ found:
 static int network_disconnect(struct connman_network *network)
 {
        struct connman_device *device = connman_network_get_device(network);
+       struct disconnect_data *dd;
        struct wifi_data *wifi;
        int err;
 #if defined TIZEN_EXT
@@ -4036,16 +4087,16 @@ static int network_disconnect(struct connman_network *network)
 
        wifi->disconnecting = true;
 
-#if defined TIZEN_EXT
-       err = g_supplicant_interface_disconnect(wifi->interface,
-                                               disconnect_callback, network);
-#else
-       err = g_supplicant_interface_disconnect(wifi->interface,
-                                               disconnect_callback, wifi);
-#endif
+       dd = g_malloc0(sizeof(*dd));
+       dd->wifi = wifi;
+       dd->network = network;
 
-       if (err < 0)
+       err = g_supplicant_interface_disconnect(wifi->interface,
+                                               disconnect_callback, dd);
+       if (err < 0) {
                wifi->disconnecting = false;
+               g_free(dd);
+       }
 
        return err;
 }
@@ -4342,6 +4393,7 @@ static bool handle_wps_completion(GSupplicantInterface *interface,
        if (wps) {
                const unsigned char *ssid, *wps_ssid;
                unsigned int ssid_len, wps_ssid_len;
+               struct disconnect_data *dd;
                const char *wps_key;
 
                /* Checking if we got associated with requested
@@ -4354,16 +4406,16 @@ static bool handle_wps_completion(GSupplicantInterface *interface,
 
                if (!wps_ssid || wps_ssid_len != ssid_len ||
                                memcmp(ssid, wps_ssid, ssid_len) != 0) {
+                       dd = g_malloc0(sizeof(*dd));
+                       dd->wifi = wifi;
+                       dd->network = network;
+
                        connman_network_set_associating(network, false);
-#if defined TIZEN_EXT
                        g_supplicant_interface_disconnect(wifi->interface,
-                                               disconnect_callback, wifi->network);
-
+                                               disconnect_callback, dd);
+#if defined TIZEN_EXT
                        connman_network_set_bool(network, "WiFi.UseWPS", false);
                        connman_network_set_string(network, "WiFi.PinWPS", NULL);
-#else
-                       g_supplicant_interface_disconnect(wifi->interface,
-                                               disconnect_callback, wifi);
 #endif
                        return false;
                }
@@ -4424,10 +4476,10 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
                                        struct connman_network *network,
                                        struct wifi_data *wifi)
 {
-#if defined TIZEN_EXT
-       const char *security;
        struct connman_service *service;
 
+#if defined TIZEN_EXT
+       const char *security;
        if (wifi->connected)
                return false;
 
@@ -4444,9 +4496,9 @@ static bool handle_4way_handshake_failure(GSupplicantInterface *interface,
        if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
                return false;
 #else
-       struct connman_service *service;
-
-       if (wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE)
+       if ((wifi->state != G_SUPPLICANT_STATE_4WAY_HANDSHAKE) &&
+                       !((wifi->state == G_SUPPLICANT_STATE_ASSOCIATING) &&
+                               (wifi->assoc_code == ASSOC_STATUS_AUTH_TIMEOUT)))
                return false;
 
        if (wifi->connected)
@@ -4711,9 +4763,10 @@ static void interface_state(GSupplicantInterface *interface)
 
                /* See table 8-36 Reason codes in IEEE Std 802.11 */
                switch (wifi->disconnect_code) {
+#if defined TIZEN_EXT
                case 1: /* Unspecified reason */
                        /* Let's assume it's because we got blocked */
-
+#endif
                case 6: /* Class 2 frame received from nonauthenticated STA */
                        connman_network_set_error(network,
                                                CONNMAN_NETWORK_ERROR_BLOCKED);
@@ -6212,7 +6265,7 @@ static void sta_remove_callback(int result,
                                        void *user_data)
 {
        struct wifi_tethering_info *info = user_data;
-       const char *driver = connman_option_get_string("wifi");
+       const char *driver = connman_setting_get_string("wifi");
 
        DBG("ifname %s result %d ", info->ifname, result);
 
@@ -6410,7 +6463,7 @@ static void supp_ins_init(void)
        const char *string;
        GSupplicantINSPreferredFreq preferred_freq;
 
-       string = connman_option_get_string("INSPreferredFreqBSSID");
+       string = connman_setting_get_string("INSPreferredFreqBSSID");
        if (g_strcmp0(string, "5GHz") == 0)
                preferred_freq = G_SUPPLICANT_INS_PREFERRED_FREQ_5GHZ;
        else if (g_strcmp0(string, "2.4GHz") == 0)