Merge tag 'upstream/1.40' into tizen.
[platform/upstream/connman.git] / gsupplicant / supplicant.c
index 0f01e95..c76c142 100755 (executable)
@@ -54,7 +54,6 @@
 #define WLAN_EID_SUPP_RATES 1
 #define WLAN_EID_EXT_SUPP_RATES 50
 #define COUNTRY_CODE_LENGTH    2
-#define WIFI_BSSID_LEN_MAX 6
 #endif
 
 #if defined TIZEN_EXT
@@ -175,7 +174,7 @@ static struct strvalmap mode_capa_map[] = {
        { }
 };
 
-#if defined TIZEN_EXT
+#if defined TIZEN_EXT && defined TIZEN_EXT_INS
 struct _GSupplicantINSSettings {
        GSupplicantINSPreferredFreq preferred_freq_bssid;
        unsigned int preferred_freq_bssid_score;
@@ -189,7 +188,9 @@ struct _GSupplicantINSSettings {
 };
 
 static struct _GSupplicantINSSettings ins_settings;
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
 
+#if defined TIZEN_EXT
 static unsigned char invalid_bssid[WIFI_BSSID_LEN_MAX] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
@@ -304,6 +305,8 @@ struct g_supplicant_bss {
        dbus_bool_t hs20;
        unsigned char country_code[COUNTRY_CODE_LENGTH];
        GSupplicantPhy_mode phy_mode;
+       dbus_int16_t snr;
+       dbus_uint32_t est_throughput;
 #endif
        unsigned int wps_capabilities;
 #if defined TIZEN_EXT
@@ -314,6 +317,7 @@ struct g_supplicant_bss {
        unsigned int transition_mode_ssid_len;
        unsigned char transition_mode_bssid[6];
        unsigned char transition_mode_ssid[32];
+       dbus_bool_t pmf_required;
 #endif
 };
 
@@ -343,6 +347,7 @@ struct _GSupplicantNetwork {
        unsigned char country_code[COUNTRY_CODE_LENGTH];
        GSupplicantPhy_mode phy_mode;
        dbus_bool_t owe_transition_mode;
+       dbus_bool_t privacy;
        unsigned int transition_mode_ssid_len;
        unsigned char transition_mode_bssid[6];
        unsigned char transition_mode_ssid[32];
@@ -432,21 +437,6 @@ struct interface_scan_data {
 };
 
 #if defined TIZEN_EXT
-struct g_connman_bssids {
-       unsigned char bssid[WIFI_BSSID_LEN_MAX];
-       uint16_t strength;
-       uint16_t frequency;
-       uint16_t assoc_reject_cnt;
-       bool is_last_connected;
-#if defined TIZEN_EXT_INS
-       int score_last_connected_bssid;
-       int score_assoc_reject;
-       int score_frequency;
-       int score_strength;
-#endif
-       int ins_score;
-};
-
 struct update_bssid_data {
        GSupplicantNetwork *network;
        unsigned char last_connected_bssid[WIFI_BSSID_LEN_MAX];
@@ -677,6 +667,9 @@ static int store_network_information(GSupplicantInterface * interface,
 
        if ((ssid->security == G_SUPPLICANT_SECURITY_WEP ||
                ssid->security == G_SUPPLICANT_SECURITY_PSK ||
+#if defined TIZEN_EXT
+               ssid->security == G_SUPPLICANT_SECURITY_SAE ||
+#endif
                ssid->security == G_SUPPLICANT_SECURITY_NONE) &&
                ssid->passphrase) {
                interface->network_info.passphrase = g_strdup(ssid->passphrase);
@@ -1429,6 +1422,14 @@ bool g_supplicant_interface_get_is_5_0_ghz_supported(GSupplicantInterface *inter
 
        return interface->is_5_0_Ghz_supported;
 }
+
+unsigned char *g_supplicant_interface_get_add_network_bssid(GSupplicantInterface *interface)
+{
+       if (!interface)
+               return NULL;
+
+       return (unsigned char *)interface->add_network_bssid;
+}
 #endif
 
 const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface)
@@ -1742,12 +1743,20 @@ const char *g_supplicant_network_get_phase2(GSupplicantNetwork *network)
 
 unsigned int g_supplicant_network_get_keymgmt(GSupplicantNetwork *network)
 {
-       if (network == NULL)
+       if (!network)
                return 0;
 
        return network->keymgmt;
 }
 
+dbus_bool_t g_supplicant_network_get_privacy(GSupplicantNetwork *network)
+{
+       if (!network)
+               return FALSE;
+
+       return network->privacy;
+}
+
 const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork
                                                          *network)
 {
@@ -1756,6 +1765,14 @@ const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork
 
        return network->country_code;
 }
+
+dbus_bool_t g_supplicant_network_is_pmf_required(GSupplicantNetwork *network)
+{
+       if (!network)
+               return 0;
+
+       return network->best_bss->pmf_required;
+}
 #endif
 
 const unsigned char *g_supplicant_peer_get_widi_ies(GSupplicantPeer *peer,
@@ -1851,6 +1868,7 @@ const unsigned char *g_supplicant_network_get_bssid(GSupplicantNetwork *network)
 
        return (const unsigned char *)network->best_bss->bssid;
 }
+
 dbus_bool_t g_supplicant_network_get_transition_mode(GSupplicantNetwork *network)
 {
        if (network == NULL)
@@ -1859,7 +1877,6 @@ dbus_bool_t g_supplicant_network_get_transition_mode(GSupplicantNetwork *network
        return network->owe_transition_mode;
 }
 
-
 const unsigned char *g_supplicant_network_get_transition_mode_bssid(GSupplicantNetwork *network)
 {
        if (network == NULL)
@@ -1894,12 +1911,10 @@ const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network)
                return NULL;
 
        if (network->best_bss->security == G_SUPPLICANT_SECURITY_PSK ||
-#if defined TIZEN_EXT
-           network->best_bss->security == G_SUPPLICANT_SECURITY_SAE ||
-           network->best_bss->security == G_SUPPLICANT_SECURITY_OWE ||
-           network->best_bss->security == G_SUPPLICANT_SECURITY_DPP ||
-#endif /* TIZEN_EXT */
-           network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) {
+                       network->best_bss->security == G_SUPPLICANT_SECURITY_SAE ||
+                       network->best_bss->security == G_SUPPLICANT_SECURITY_OWE ||
+                       network->best_bss->security == G_SUPPLICANT_SECURITY_DPP ||
+                       network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) {
                unsigned int pairwise;
 
                pairwise = network->best_bss->rsn_pairwise |
@@ -1926,12 +1941,9 @@ bool g_supplicant_network_get_rsn_mode(GSupplicantNetwork *network)
        if (network == NULL || network->best_bss == NULL)
                return 0;
 
-#if defined TIZEN_EXT
-       if (network->best_bss->security == G_SUPPLICANT_SECURITY_SAE ||
-                       network->best_bss->security == G_SUPPLICANT_SECURITY_OWE ||
+       if (network->best_bss->security == G_SUPPLICANT_SECURITY_OWE ||
                        network->best_bss->security == G_SUPPLICANT_SECURITY_DPP)
                return false;
-#endif /* TIZEN_EXT */
 
        if (network->best_bss->rsn_selected) {
                const char *mode = g_supplicant_network_get_enc_mode(network);
@@ -1997,6 +2009,7 @@ static gchar *convert_bssid_to_str(unsigned char *bssid)
        return g_string_free(bssid_str, FALSE);
 }
 
+#if defined TIZEN_EXT_INS
 static void count_assoc_reject(gpointer data, gpointer user_data)
 {
        time_t assoc_reject_time = GPOINTER_TO_INT(data);
@@ -2110,8 +2123,22 @@ static int calculate_score_strength(dbus_int16_t strength)
        return score;
 }
 
+static int calculate_score_est_throughput(dbus_uint32_t est_throughput)
+{
+       int score = 0;
+
+       if (est_throughput >= 10000)
+               score = est_throughput / 10000;
+
+       if (score > 40)
+               score = 40;
+
+       return score;
+}
+
 static int calculate_score(bool is_last_connected, uint16_t assoc_reject_cnt,
-               dbus_int16_t strength, dbus_uint16_t frequency)
+               dbus_uint16_t frequency, dbus_int16_t strength,
+               dbus_int16_t snr, dbus_uint32_t est_throughput)
 {
        int score = 0;
 
@@ -2119,9 +2146,12 @@ static int calculate_score(bool is_last_connected, uint16_t assoc_reject_cnt,
        score += calculate_score_assoc_reject(assoc_reject_cnt);
        score += calculate_score_frequency(strength, frequency);
        score += calculate_score_strength(strength);
+       score += (int)snr;
+       score += calculate_score_est_throughput(est_throughput);
 
        return score;
 }
+#endif
 
 static void update_bssid_list(gpointer key, gpointer value, gpointer user_data)
 {
@@ -2141,21 +2171,24 @@ static void update_bssid_list(gpointer key, gpointer value, gpointer user_data)
                        bssids->strength = 100;
 
                bssids->frequency = bss->frequency;
+               bssids->score_snr = (int)bss->snr;
 
+#if defined TIZEN_EXT_INS
                bssids->assoc_reject_cnt = get_assoc_reject_cnt(bssid_data->assoc_reject_table, bssids->bssid);
-
                bssids->is_last_connected = compare_bssid(bssids->bssid, bssid_data->last_connected_bssid);
 
-#if defined TIZEN_EXT_INS
                bssids->score_last_connected_bssid = calculate_score_last_connected_bssid(bssids->is_last_connected);
                bssids->score_assoc_reject = calculate_score_assoc_reject(bssids->assoc_reject_cnt);
                bssids->score_frequency = calculate_score_frequency(bss->signal, bssids->frequency);
-               bssids->score_strength = calculate_score_strength(bssids->strength);
-#endif
+               bssids->score_strength = calculate_score_strength(bss->signal);
+               bssids->score_est_throughput = calculate_score_est_throughput(bss->est_throughput);
 
                bssids->ins_score = calculate_score(bssids->is_last_connected,
-                       bssids->assoc_reject_cnt, bssids->frequency, bss->signal);
-
+                       bssids->assoc_reject_cnt, bssids->frequency, bss->signal,
+                       bss->snr, bss->est_throughput);
+#else
+               bssids->ins_score = bss->signal;
+#endif
                bssid_data->bssid_list = g_slist_append(bssid_data->bssid_list, bssids);
        } else
                SUPPLICANT_DBG("Failed to allocate memory");
@@ -2522,6 +2555,12 @@ static char *create_group(struct g_supplicant_bss *bss)
 static void update_network_with_best_bss(GSupplicantNetwork *network,
                struct g_supplicant_bss *best_bss)
 {
+       /*
+        * Do not change best BSS if we are connected.
+        */
+       if (network->interface->state == G_SUPPLICANT_STATE_COMPLETED)
+               return;
+
        network->signal = best_bss->signal;
        network->frequency = best_bss->frequency;
        network->best_bss = best_bss;
@@ -2538,15 +2577,21 @@ static bool update_best_bss(GSupplicantNetwork *network,
                return true;
        }
 
+#if defined TIZEN_EXT_INS
        score_new = calculate_score(
                compare_bssid(bss->bssid, network->last_connected_bssid),
                get_assoc_reject_cnt(network->assoc_reject_table, bss->bssid),
-               bss->frequency, bss->signal);
+               bss->frequency, bss->signal, bss->snr, bss->est_throughput);
 
        score_best = calculate_score(
                compare_bssid(network->best_bss->bssid, network->last_connected_bssid),
                get_assoc_reject_cnt(network->assoc_reject_table, network->best_bss->bssid),
-               network->best_bss->frequency, network->best_bss->signal);
+               network->best_bss->frequency, network->best_bss->signal,
+               network->best_bss->snr, network->best_bss->est_throughput);
+#else
+       score_new = bss->signal;
+       score_best = network->best_bss->signal;
+#endif
 
        if (score_new > score_best) {
                SUPPLICANT_DBG("new[" MACSTR "][%u] : best[" MACSTR "][%u]",
@@ -2613,6 +2658,7 @@ static int add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
 
 #if defined TIZEN_EXT
        network->owe_transition_mode = bss->owe_transition_mode;
+       network->privacy = bss->privacy;
        memcpy(network->transition_mode_ssid, bss->transition_mode_ssid, bss->transition_mode_ssid_len);
        memcpy(network->transition_mode_bssid, bss->transition_mode_bssid, WIFI_BSSID_LEN_MAX);
 
@@ -2892,6 +2938,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
        unsigned char *ext_rates = NULL;
        unsigned int max_rate = 0;
        unsigned int max_ext_rate = 0;
+       unsigned int offset = 0;
        bool ht = false;
        bool vht = false;
 #endif
@@ -2909,6 +2956,8 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
 #if defined TIZEN_EXT
 #define VENDOR_SPECIFIC_INFO 0xDD
 #define WLAN_EID_COUNTRY 7
+#define WLAN_EID_RSN_INFO 48
+#define RSN_CAPABILITY_MFP_REQ (1 << 6)
 #endif
 
        dbus_message_iter_recurse(iter, &array);
@@ -2926,7 +2975,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
                unsigned char *vsie;
                int vsie_len = 0;
 
-               if(ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, OWE_WFA_OUI, sizeof(OWE_WFA_OUI)) == 0) {
+               if (ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, OWE_WFA_OUI, sizeof(OWE_WFA_OUI)) == 0) {
                        SUPPLICANT_DBG("IE: match vendor specific data : OWE Transition Mode");
 
 /*
@@ -2956,7 +3005,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
                        continue;
                }
 
-               if(ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) {
+               if (ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) {
 
                        if (!simplified_log)
                                SUPPLICANT_DBG("IE: match vendor specific data");
@@ -2972,7 +3021,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
                        continue;
                }
 
-               if(ie[0] == WLAN_EID_COUNTRY && ie[1] >= 2) {
+               if (ie[0] == WLAN_EID_COUNTRY && ie[1] >= 2) {
                        /* Add country code only if it is a valid alphabet */
                        if (ie[2] >= 65 && ie[2] <= 90 && ie[3] >= 65 && ie[3] <= 90) {
                                memcpy(bss->country_code, ie+2, COUNTRY_CODE_LENGTH);
@@ -3017,6 +3066,18 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
                        }
                        continue;
                }
+
+               if (ie[0] == WLAN_EID_RSN_INFO && ie[1] >= 20) {
+                       r_len = ie[1];
+                       offset = 10 + ie[8] * 4;
+                       offset += ie[offset] * 4 + 2;
+
+                       if (offset <= r_len + 1 &&
+                                       (ie[offset] & RSN_CAPABILITY_MFP_REQ) != 0)
+                               bss->pmf_required = TRUE;
+
+                       continue;
+               }
 #endif
                if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
                        memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
@@ -3116,15 +3177,17 @@ static void bss_compute_security(struct g_supplicant_bss *bss)
 
        if (bss->ieee8021x)
                bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
+#if defined TIZEN_EXT
+       else if (bss->ft_ieee8021x)
+               bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
+       else if (bss->sae)
+               bss->security = G_SUPPLICANT_SECURITY_SAE;
+#endif
        else if (bss->psk)
                bss->security = G_SUPPLICANT_SECURITY_PSK;
 #if defined TIZEN_EXT
        else if (bss->ft_psk)
                bss->security = G_SUPPLICANT_SECURITY_FT_PSK;
-       else if (bss->ft_ieee8021x == TRUE)
-               bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
-       else if (bss->sae)
-               bss->security = G_SUPPLICANT_SECURITY_SAE;
        else if (bss->owe || bss->owe_transition_mode)
                bss->security = G_SUPPLICANT_SECURITY_OWE;
        else if (bss->dpp)
@@ -3238,6 +3301,17 @@ static void bss_property(const char *key, DBusMessageIter *iter,
                dbus_bool_t hs20 = FALSE;
                dbus_message_iter_get_basic(iter, &hs20);
                bss->hs20 = hs20;
+       } else if (g_strcmp0(key, "SNR") == 0) {
+               dbus_int16_t snr = 0;
+
+               dbus_message_iter_get_basic(iter, &snr);
+               bss->snr = snr;
+       } else if (g_strcmp0(key, "EstThroughput") == 0) {
+               dbus_uint32_t est_throughput = 0;
+
+               dbus_message_iter_get_basic(iter, &est_throughput);
+               if (est_throughput != 0)
+                       bss->est_throughput = est_throughput;
 #endif
        } else if (g_strcmp0(key, "IEs") == 0)
                bss_process_ies(iter, bss);
@@ -3468,6 +3542,11 @@ static void interface_current_bss(GSupplicantInterface *interface,
 
                network->best_bss = bss;
 
+#if defined TIZEN_EXT
+               if (network->frequency != bss->frequency)
+                       network->frequency = bss->frequency;
+#endif
+
                if (network->signal != bss->signal) {
                        SUPPLICANT_DBG("New network signal %d dBm",
                                                bss->signal);
@@ -3475,6 +3554,10 @@ static void interface_current_bss(GSupplicantInterface *interface,
                        network->signal = bss->signal;
                        callback_network_changed(network, "Signal");
                }
+#if defined TIZEN_EXT
+               else
+                       callback_network_changed(network, "");
+#endif
        }
 
        /*
@@ -4241,8 +4324,10 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter)
        supplicant_dbus_property_foreach(iter, bss_property, bss);
 
 #if defined TIZEN_EXT
-       network->frequency = bss->frequency;
-       network->phy_mode = bss->phy_mode;
+       if (network->interface->state != G_SUPPLICANT_STATE_COMPLETED) {
+               network->frequency = bss->frequency;
+               network->phy_mode = bss->phy_mode;
+       }
 #endif
        old_security = network->security;
        bss_compute_security(bss);
@@ -5359,7 +5444,7 @@ static void country_result(const char *error,
                regdom->callback(result, regdom->alpha2,
                                        (void *) regdom->user_data);
 
-       dbus_free(regdom);
+       g_free(regdom);
 }
 
 static void country_params(DBusMessageIter *iter, void *user_data)
@@ -5623,7 +5708,7 @@ static void interface_create_result(const char *error,
        SUPPLICANT_DBG("");
 
        if (error) {
-               g_message("error %s", error);
+               g_warning("error %s", error);
                err = -EIO;
                goto done;
        }
@@ -6388,6 +6473,7 @@ static void interface_signalpoll_result(const char *error,
        int err = 0;
        dbus_int32_t maxspeed = 0;
        dbus_int32_t strength = 0;
+       dbus_int32_t snr = 0;
        DBusMessageIter sub_iter, dict;
 
        if (error) {
@@ -6396,7 +6482,12 @@ static void interface_signalpoll_result(const char *error,
                goto out;
        }
 
-       dbus_message_iter_get_arg_type(iter);
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
+               err = -EINVAL;
+               SUPPLICANT_DBG("invalid reply");
+               goto out;
+       }
+
        dbus_message_iter_recurse(iter, &sub_iter);
        dbus_message_iter_recurse(&sub_iter, &dict);
 
@@ -6419,6 +6510,10 @@ static void interface_signalpoll_result(const char *error,
                                dbus_message_iter_get_basic(&value, &strength);
                                SUPPLICANT_DBG("Strength = %d", strength);
                                break;
+                       } else if (g_strcmp0(key, "SNR") == 0) {
+                               dbus_message_iter_get_basic(&value, &snr);
+                               SUPPLICANT_DBG("SNR = %d", snr);
+                               break;
                        }
                }
                dbus_message_iter_next(&dict);
@@ -6426,7 +6521,7 @@ static void interface_signalpoll_result(const char *error,
 
 out:
        if(data->callback)
-               data->callback(err, maxspeed, strength, data->user_data);
+               data->callback(err, maxspeed, strength, snr, data->user_data);
 
        g_free(data->path);
        dbus_free(data);
@@ -7793,7 +7888,7 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
                                        interface_add_network_result, data,
                                        interface);
                }
-        }
+       }
 
        if (ret < 0) {
                g_free(data->path);
@@ -8497,7 +8592,7 @@ static void invoke_introspect_method(void)
        dbus_message_unref(message);
 }
 
-#if defined TIZEN_EXT
+#if defined TIZEN_EXT && defined TIZEN_EXT_INS
 void g_supplicant_set_ins_settings(GSupplicantINSPreferredFreq preferred_freq_bssid,
                bool last_connected_bssid, bool assoc_reject, bool signal_bssid,
                unsigned int preferred_freq_bssid_score, unsigned int last_connected_bssid_score,
@@ -8523,7 +8618,7 @@ void g_supplicant_set_ins_settings(GSupplicantINSPreferredFreq preferred_freq_bs
        SUPPLICANT_DBG("signal_level3_5ghz [%d]", signal_level3_5ghz);
        SUPPLICANT_DBG("signal_level3_24ghz [%d]", signal_level3_24ghz);
 }
-#endif
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_INS */
 
 #if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
 void g_supplicant_register_eap_callback(g_supplicant_eap_callback cb)