Maintain connection status when wifi roaming
[platform/upstream/connman.git] / plugins / wifi.c
index 9bd11cb..4280c47 100755 (executable)
 #define RSSI_LEVEL_2_24G -75
 #define RSSI_LEVEL_3_5G  -68
 #define RSSI_LEVEL_3_24G -64
-#define WIFI_BSSID_STR_LEN 18
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 #define ROAM_SCAN_INTERVAL 60 /* 60 seconds */
 #endif
 
@@ -2177,6 +2174,59 @@ static void scan_callback_hidden(int result,
                        GSupplicantInterface *interface, void *user_data);
 
 static int network_disconnect(struct connman_network *network);
+
+static void start_roaming(struct wifi_data *wifi)
+{
+       bool roaming_ap_found = false;
+       GSList *bssid_list = NULL;
+
+       if (!wifi || !wifi->network)
+               return;
+
+       if (connman_setting_get_bool("WifiRoaming")) {
+               struct connman_network *network = wifi->network;
+               bssid_list = connman_network_get_bssid_list(network);
+
+               if (g_slist_length(bssid_list) <= 1)
+                       return;
+
+               if (!connman_network_get_connected(network))
+                       return;
+
+               if (connman_network_get_bool(network, "WiFi.Roaming"))
+                       return;
+
+               if (!need_bss_transition(
+                               connman_network_get_frequency(network),
+                               connman_network_get_snr(network),
+                               connman_network_get_strength(network)))
+                       return;
+
+               for (bssid_list; bssid_list; bssid_list = bssid_list->next) {
+                       struct g_connman_bssids *bssid = bssid_list->data;
+
+                       if (check_bss_condition(bssid->frequency,
+                                       bssid->score_snr, bssid->strength))
+                               roaming_ap_found = true;
+               }
+
+               if (roaming_ap_found) {
+                       char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
+                       char *bssid_str = bssid_buff;
+                       unsigned char *bssid;
+
+                       bssid = connman_network_get_bssid(network);
+                       snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
+                       connman_network_set_string(network,
+                                       "WiFi.RoamingCurBSSID", bssid_str);
+
+                       network_disconnect(network);
+                       wifi->pending_network = network;
+                       connman_network_set_bool(network, "WiFi.Roaming", true);
+               }
+       }
+}
+
 #endif
 
 static void scan_callback(int result, GSupplicantInterface *interface,
@@ -2186,10 +2236,7 @@ static void scan_callback(int result, GSupplicantInterface *interface,
        struct wifi_data *wifi = connman_device_get_data(device);
        bool scanning;
 #if defined TIZEN_EXT
-       bool roaming_needed = false;
-       bool roaming_ap_found = false;
        GSList *list = NULL;
-       GSList *bssid_list = NULL;
        bool favorite_exists = false;
        struct connman_network *network = NULL;
        struct connman_service *service = NULL;
@@ -2306,46 +2353,8 @@ static void scan_callback(int result, GSupplicantInterface *interface,
                network_connect(wifi->scan_pending_network);
                wifi->scan_pending_network = NULL;
                connman_network_set_connecting(wifi->network);
-       } else if (connman_setting_get_bool("WifiRoaming") && wifi->network) {
-               bssid_list = connman_network_get_bssid_list(wifi->network);
-
-               if (g_slist_length(bssid_list) <= 1)
-                       goto done;
-
-               if (!connman_network_get_connected(wifi->network))
-                       goto done;
-
-               if (connman_network_get_bool(wifi->network, "WiFi.Roaming"))
-                       goto done;
-
-               if (!need_bss_transition(
-                               connman_network_get_frequency(wifi->network),
-                               connman_network_get_snr(wifi->network),
-                               connman_network_get_strength(wifi->network)))
-                       goto done;
-
-               for (bssid_list; bssid_list; bssid_list = bssid_list->next) {
-                       struct g_connman_bssids *bssid = bssid_list->data;
-
-                       if (check_bss_condition(bssid->frequency,
-                                       bssid->score_snr, bssid->strength))
-                               roaming_ap_found = true;
-               }
-
-               if (roaming_ap_found) {
-                       char bssid_buff[WIFI_BSSID_STR_LEN] = {0,};
-                       char *bssid_str = bssid_buff;
-                       unsigned char *bssid;
-
-                       bssid = connman_network_get_bssid(wifi->network);
-                       snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
-                       connman_network_set_string(wifi->network,
-                                       "WiFi.RoamingCurBSSID", bssid_str);
-
-                       network_disconnect(wifi->network);
-                       wifi->pending_network = wifi->network;
-                       connman_network_set_bool(wifi->network, "WiFi.Roaming", true);
-               }
+       } else {
+               start_roaming(wifi);
        }
 
 done:
@@ -2957,7 +2966,7 @@ static void specific_scan_callback(int result, GSupplicantInterface *interface,
        struct wifi_data *wifi = connman_device_get_data(device);
        bool scanning;
 
-       DBG("result %d wifi %p", result, wifi);
+       DBG("result %d device %p wifi %p", result, device, wifi);
 
        if (wifi && wifi->scan_params) {
                g_supplicant_free_scan_params(wifi->scan_params);
@@ -2971,6 +2980,8 @@ static void specific_scan_callback(int result, GSupplicantInterface *interface,
                                CONNMAN_SERVICE_TYPE_WIFI, false);
                connman_device_unref(device);
        }
+
+       start_roaming(wifi);
 }
 
 static int wifi_specific_scan(enum connman_service_type type,
@@ -3917,7 +3928,7 @@ done:
                        connman_network_get_string(network, "WiFi.KeymgmtType"));
        ssid->phase1 = connman_network_get_string(network, "WiFi.Phase1");
 
-       if(g_strcmp0(ssid->eap, "fast") == 0)
+       if (g_strcmp0(ssid->eap, "fast") == 0)
                ssid->pac_file = g_strdup(WIFI_EAP_FAST_PAC_FILE);
 
        ssid->keymgmt = connman_network_get_keymgmt(network);
@@ -3993,6 +4004,12 @@ static void disconnect_callback(int result, GSupplicantInterface *interface,
                        goto found;
        }
 
+       if (connman_network_get_bool(wifi->network, "WiFi.Roaming"))
+               connman_network_set_bool(wifi->network, "WiFi.Roaming", false);
+
+       if (network == wifi->pending_network)
+               wifi->pending_network = NULL;
+
        /* wifi_data may be invalid because wifi is already disabled */
        return;
 
@@ -4012,9 +4029,8 @@ found:
        }
 
 #if defined TIZEN_EXT
-       if (wifi->network &&
-                       (wifi->network != wifi->pending_network ||
-                       connman_network_get_bool(wifi->network, "WiFi.Roaming")))
+       if (g_slist_find(wifi->networks, network) &&
+                       wifi->network != wifi->pending_network)
 #else
        if (g_slist_find(wifi->networks, network))
 #endif
@@ -4184,7 +4200,10 @@ static void signalpoll_callback(int result, int maxspeed, int strength,
        const char *interface = NULL;
        struct connman_device *device;
        struct connman_network *network = user_data;
+       GSupplicantNetwork *supplicant_network;
+       struct wifi_data *wifi;
        uint16_t freq = connman_network_get_frequency(network);
+       const char *group = connman_network_get_group(network);
 
        if (result != 0) {
                DBG("Failed to get maxspeed from signalpoll !");
@@ -4192,30 +4211,44 @@ static void signalpoll_callback(int result, int maxspeed, int strength,
                return;
        }
 
+       device = connman_network_get_device(network);
+       if (device)
+               wifi = connman_device_get_data(device);
+
+       if (group) {
+               supplicant_network = g_supplicant_interface_get_network(wifi->interface, group);
+               if (supplicant_network) {
+                       g_supplicant_network_set_signal(supplicant_network, strength);
+                       g_supplicant_network_set_bss_signal(supplicant_network, strength, snr);
+               }
+       }
+
        strength += 120;
        if (strength > 100)
                strength = 100;
 
-       DBG("freq = %u, maxspeed = %d, strength = %d, snr = %d", freq, maxspeed, strength, snr);
+       bssid = connman_network_get_bssid(network);
+       snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
+
+       DBG("network %p, bssid %s, freq %u, maxspeed %d, strength %d, snr %d",
+                       network, bssid_str, freq, maxspeed, strength, snr);
 
        connman_network_set_strength(network, (uint8_t)strength);
        connman_network_set_snr(network, snr);
        connman_network_set_maxspeed(network, maxspeed);
        set_connection_mode(network, maxspeed);
 
+       if (connman_network_get_max_bssid_count(network) <= 1)
+               goto done;
+
        clock_gettime(CLOCK_MONOTONIC, &curr_time);
        roam_scan_time = connman_network_get_roam_scan_time(network);
        if (curr_time.tv_sec <= roam_scan_time + ROAM_SCAN_INTERVAL)
                goto done;
 
-       if (need_bss_transition(freq, snr, strength)) {
-               device = connman_network_get_device(network);
-               if (!device)
-                       goto done;
+       if (device && need_bss_transition(freq, snr, strength)) {
 
                interface = connman_device_get_string(device, "Interface");
-               bssid = connman_network_get_bssid(network);
-               snprintf(bssid_str, WIFI_BSSID_STR_LEN, MACSTR, MAC2STR(bssid));
                __connman_technology_notify_roaming_state(interface, "required", bssid_str, NULL);
 
                if (connman_setting_get_bool("WifiRoamingScan") == false)
@@ -4574,6 +4607,65 @@ static bool handle_wifi_assoc_retry(struct connman_network *network,
 
        return true;
 }
+
+static void handle_wifi_roaming_complete(struct connman_network *network)
+{
+       const char *cur_bssid;
+       const char *dst_bssid;
+       const char *ifname;
+       struct connman_device *device;
+       struct connman_service *service;
+       struct connman_ipconfig *ipconfig_ipv4;
+       enum connman_ipconfig_type type;
+       enum connman_ipconfig_method method;
+
+       if (!connman_setting_get_bool("WifiRoaming") ||
+                       !connman_network_get_bool(network, "WiFi.Roaming"))
+               return;
+
+       device = connman_network_get_device(network);
+       if (device) {
+               ifname = connman_device_get_string(device, "Interface");
+               cur_bssid = connman_network_get_string(network,
+                               "WiFi.RoamingCurBSSID");
+               dst_bssid = connman_network_get_string(network,
+                               "WiFi.RoamingDstBSSID");
+       }
+
+       if (device && ifname && cur_bssid && dst_bssid) {
+               __connman_technology_notify_roaming_state(ifname,
+                               "success", cur_bssid, dst_bssid);
+               connman_network_set_bool(network,
+                               "WiFi.Roaming", false);
+               connman_network_set_string(network,
+                               "WiFi.RoamingCurBSSID", NULL);
+               connman_network_set_string(network,
+                               "WiFi.RoamingDstBSSID", NULL);
+
+               service = connman_service_lookup_from_network(network);
+               if (!service)
+                       return;
+
+               ipconfig_ipv4 = __connman_service_get_ip4config(service);
+               if (!ipconfig_ipv4) {
+                       connman_error("Service has no IPv4 configuration");
+                       return;
+               }
+
+               type = __connman_ipconfig_get_config_type(ipconfig_ipv4);
+               if (type != CONNMAN_IPCONFIG_TYPE_IPV4)
+                       return;
+
+               method = __connman_ipconfig_get_method(ipconfig_ipv4);
+               if (method != CONNMAN_IPCONFIG_METHOD_DHCP)
+                       return;
+
+               connman_network_set_bool(network, "WiFi.RoamingDHCP", true);
+
+               if (set_connected_dhcp(network) != 0)
+                       connman_network_set_bool(network, "WiFi.RoamingDHCP", false);
+       }
+}
 #endif
 
 static void interface_state(GSupplicantInterface *interface)
@@ -4634,6 +4726,8 @@ static void interface_state(GSupplicantInterface *interface)
                        wifi->automaxspeed_timeout = 0;
                        DBG("Remove signalpoll timer!!");
                }
+
+               if (!connman_network_get_bool(wifi->network, "WiFi.Roaming"))
 #endif
                if (wifi->connected)
                        connman_network_set_connected(network, false);
@@ -4647,7 +4741,9 @@ static void interface_state(GSupplicantInterface *interface)
 #else
                stop_autoscan(device);
 #endif
-
+#if defined TIZEN_EXT
+               if (!connman_network_get_bool(wifi->network, "WiFi.Roaming"))
+#endif
                if (!wifi->connected)
                        connman_network_set_associating(network, true);
 
@@ -4681,6 +4777,7 @@ static void interface_state(GSupplicantInterface *interface)
                }
 
                g_hash_table_remove_all(failed_bssids);
+               handle_wifi_roaming_complete(network);
 #else
                /* though it should be already stopped: */
                stop_autoscan(device);
@@ -4722,7 +4819,7 @@ static void interface_state(GSupplicantInterface *interface)
                        break;
 
 #if defined TIZEN_EXT
-               if (handle_assoc_status_code(interface, wifi)) {
+               if (!wifi->connected && handle_assoc_status_code(interface, wifi)) {
                        const char *group = connman_network_get_group(network);
                        GSupplicantNetwork *supplicant_network;
                        GSList *bssid_list = NULL;
@@ -4787,7 +4884,7 @@ static void interface_state(GSupplicantInterface *interface)
                        break;
                }
 
-               if(wifi->disconnect_code > 0){
+               if (wifi->disconnect_code > 0){
                        DBG("Set disconnect reason code(%d)", wifi->disconnect_code);
                        connman_network_set_disconnect_reason(network, wifi->disconnect_code);
                }