Handle the case that best_bss is NULL
[platform/upstream/connman.git] / gsupplicant / supplicant.c
index 957312c..36625d0 100755 (executable)
 #define FREQ_RANGE_24GHZ_CHANNEL_14  2484
 #define FREQ_RANGE_5GHZ_CHANNEL_32   5160
 #define FREQ_RANGE_5GHZ_CHANNEL_165  5825
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 #endif
 
 #define BSS_UNKNOWN_STRENGTH    -90
 
 static DBusConnection *connection;
 
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+static GSupplicantCallbacks *callbacks_pointer;
+#else /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
 static const GSupplicantCallbacks *callbacks_pointer;
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
 
 static dbus_bool_t system_available = FALSE;
 static dbus_bool_t system_ready = FALSE;
@@ -416,6 +423,12 @@ struct g_connman_bssids {
        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;
 };
 
@@ -439,6 +452,10 @@ struct assoc_count_data {
 static unsigned int last_connected_bss_timeout = 0;
 #endif
 
+static void interface_get_params(DBusMessageIter *iter, void *user_data);
+static void interface_get_result(const char *error,
+                               DBusMessageIter *iter, void *user_data);
+
 static int network_remove(struct interface_data *data);
 
 #if defined TIZEN_EXT_WIFI_MESH
@@ -897,6 +914,19 @@ static void callback_sta_deauthorized(GSupplicantInterface *interface,
        callbacks_pointer->sta_deauthorized(interface, addr);
 }
 
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+static void callback_eap(GSupplicantInterface *interface, bool status)
+{
+       if (!callbacks_pointer)
+               return;
+
+       if (!callbacks_pointer->eap)
+               return;
+
+       callbacks_pointer->eap(interface, status);
+}
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+
 static void callback_peer_found(GSupplicantPeer *peer)
 {
        if (!callbacks_pointer)
@@ -1962,40 +1992,32 @@ static uint16_t get_assoc_reject_cnt(GHashTable *assoc_reject_table, unsigned ch
        return assoc_count.assoc_count;
 }
 
-static void update_bssid_list(gpointer key, gpointer value, gpointer user_data)
+static int calculate_score_last_connected_bssid(bool is_last_connected)
 {
-       struct g_supplicant_bss *bss = value;
-       struct g_connman_bssids *bssids = NULL;
-       struct update_bssid_data *bssid_data = (struct update_bssid_data *)user_data;
-
-       bssids = (struct g_connman_bssids *)g_try_malloc0(sizeof(struct g_connman_bssids));
-
-       if (bssids) {
-               memcpy(bssids->bssid, bss->bssid, WIFI_BSSID_LEN_MAX);
-
-               bssids->strength = bss->signal;
-               bssids->strength += 120;
+       int score = 0;
 
-               if (bssids->strength > 100)
-                       bssids->strength = 100;
+       if (ins_settings.last_connected_bssid) {
+               if (is_last_connected)
+                       score += ins_settings.last_connected_bssid_score;
+       }
 
-               bssids->frequency = bss->frequency;
+       return score;
+}
 
-               bssids->assoc_reject_cnt = get_assoc_reject_cnt(bssid_data->assoc_reject_table, bssids->bssid);
+static int calculate_score_assoc_reject(uint16_t assoc_reject_cnt)
+{
+       int score = 0;
 
-               bssids->is_last_connected = compare_bssid(bssids->bssid, bssid_data->last_connected_bssid);
+       if (ins_settings.assoc_reject)
+               score -= (assoc_reject_cnt * ins_settings.assoc_reject_score);
 
-               bssid_data->bssid_list = g_slist_append(bssid_data->bssid_list, bssids);
-       } else
-               SUPPLICANT_DBG("Failed to allocate memory");
+       return score;
 }
 
-static int calculate_score(dbus_int16_t strength, dbus_uint16_t frequency,
-               uint16_t assoc_reject_cnt, bool is_last_connected)
+static int calculate_score_frequency(dbus_int16_t strength, dbus_uint16_t frequency)
 {
        int score = 0;
 
-       /* 5GHz & Signal >= RSSI Level 3 */
        switch (ins_settings.preferred_freq_bssid) {
        case G_SUPPLICANT_INS_PREFERRED_FREQ_24GHZ:
                if ((frequency >= FREQ_RANGE_24GHZ_CHANNEL_1 &&
@@ -2015,39 +2037,79 @@ static int calculate_score(dbus_int16_t strength, dbus_uint16_t frequency,
                break;
        }
 
-       /* Last connected BSSID */
-       if (ins_settings.last_connected_bssid) {
-               if (is_last_connected)
-                       score += ins_settings.last_connected_bssid_score;
-       }
+       return score;
+}
 
-       /* Assoc reject */
-       if (ins_settings.assoc_reject)
-               score -= (assoc_reject_cnt * ins_settings.assoc_reject_score);
+static int calculate_score_strength(dbus_int16_t strength)
+{
+       int score = 0;
 
-       /* Signal */
        if (ins_settings.signal_bssid)
                score += (((strength > -60) ? -60 : strength) + 85);
 
        return score;
 }
 
+static int calculate_score(bool is_last_connected, uint16_t assoc_reject_cnt,
+               dbus_int16_t strength, dbus_uint16_t frequency)
+{
+       int score = 0;
+
+       score += calculate_score_last_connected_bssid(is_last_connected);
+       score += calculate_score_assoc_reject(assoc_reject_cnt);
+       score += calculate_score_frequency(strength, frequency);
+       score += calculate_score_strength(strength);
+
+       return score;
+}
+
+static void update_bssid_list(gpointer key, gpointer value, gpointer user_data)
+{
+       struct g_supplicant_bss *bss = value;
+       struct g_connman_bssids *bssids = NULL;
+       struct update_bssid_data *bssid_data = (struct update_bssid_data *)user_data;
+
+       bssids = (struct g_connman_bssids *)g_try_malloc0(sizeof(struct g_connman_bssids));
+
+       if (bssids) {
+               memcpy(bssids->bssid, bss->bssid, WIFI_BSSID_LEN_MAX);
+
+               bssids->strength = bss->signal;
+               bssids->strength += 120;
+
+               if (bssids->strength > 100)
+                       bssids->strength = 100;
+
+               bssids->frequency = bss->frequency;
+
+               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->ins_score = calculate_score(bssids->is_last_connected,
+                       bssids->assoc_reject_cnt, bssids->frequency, bss->signal);
+
+               bssid_data->bssid_list = g_slist_append(bssid_data->bssid_list, bssids);
+       } else
+               SUPPLICANT_DBG("Failed to allocate memory");
+}
+
 static gint cmp_bss(gconstpointer a, gconstpointer b)
 {
        struct g_connman_bssids *entry_a = (struct g_connman_bssids *)a;
        struct g_connman_bssids *entry_b = (struct g_connman_bssids *)b;
-       int score_a = calculate_score(entry_a->strength - 120, entry_a->frequency,
-                       entry_a->assoc_reject_cnt, entry_a->is_last_connected);
-       int score_b = calculate_score(entry_b->strength - 120, entry_b->frequency,
-                       entry_b->assoc_reject_cnt, entry_b->is_last_connected);
 
-       entry_a->ins_score = score_a;
-       entry_b->ins_score = score_b;
-
-       if (score_a > score_b)
+       if (entry_a->ins_score > entry_b->ins_score)
                return -1;
 
-       if (score_a < score_b)
+       if (entry_a->ins_score < entry_b->ins_score)
                return 1;
 
        return 0;
@@ -2058,12 +2120,11 @@ static void print_bssid_sort(gpointer data, gpointer user_data)
 {
        struct g_connman_bssids *bssids = data;
 
-       SUPPLICANT_DBG("bssid[%02x:%02x:%02x:%02x:%02x:%02x] score[%d] "
-                       "strength[%d] freq[%d] assoc_reject[%d] last_conn[%d]",
-                       bssids->bssid[0], bssids->bssid[1], bssids->bssid[2],
-                       bssids->bssid[3], bssids->bssid[4], bssids->bssid[5],
-                       bssids->ins_score, bssids->strength, bssids->frequency,
-                       bssids->assoc_reject_cnt, bssids->is_last_connected);
+       SUPPLICANT_DBG("bssid[" MACSTR "] total[%2d] freq[%2d] "
+                       "last_conn[%2d] assoc_reject[%2d] strength[%2d]",
+                       MAC2STR(bssids->bssid), bssids->ins_score,
+                       bssids->score_frequency, bssids->score_last_connected_bssid,
+                       bssids->score_assoc_reject, bssids->score_strength);
 }
 #endif
 
@@ -2098,8 +2159,7 @@ void g_supplicant_network_set_last_connected_bssid(GSupplicantNetwork *network,
 
        memcpy(network->last_connected_bssid, bssid, WIFI_BSSID_LEN_MAX);
 
-       SUPPLICANT_DBG("last connected bssid [%02x:%02x:%02x:%02x:%02x:%02x]",
-                       bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
+       SUPPLICANT_DBG("last connected bssid [" MACSTR "]", MAC2STR(bssid));
 }
 
 const unsigned char *g_supplicant_network_get_last_connected_bssid(GSupplicantNetwork *network)
@@ -2399,33 +2459,41 @@ static char *create_group(struct g_supplicant_bss *bss)
        return g_string_free(str, FALSE);
 }
 
+static void update_network_with_best_bss(GSupplicantNetwork *network,
+               struct g_supplicant_bss *best_bss)
+{
+       network->signal = best_bss->signal;
+       network->frequency = best_bss->frequency;
+       network->best_bss = best_bss;
+}
+
 static bool update_best_bss(GSupplicantNetwork *network,
                struct g_supplicant_bss *bss, struct g_supplicant_bss *best_bss)
 {
        int score_new;
        int score_best;
 
-       score_new = calculate_score(bss->signal, bss->frequency,
+       if (network->best_bss == NULL) {
+               update_network_with_best_bss(network, bss);
+               return true;
+       }
+
+       score_new = calculate_score(
+               compare_bssid(bss->bssid, network->last_connected_bssid),
                get_assoc_reject_cnt(network->assoc_reject_table, bss->bssid),
-               compare_bssid(bss->bssid, network->last_connected_bssid));
-       score_best = calculate_score(network->best_bss->signal, network->best_bss->frequency,
+               bss->frequency, bss->signal);
+
+       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),
-               compare_bssid(network->best_bss->bssid, network->last_connected_bssid));
+               network->best_bss->frequency, network->best_bss->signal);
 
        if (score_new > score_best) {
-               SUPPLICANT_DBG("new[%02x:%02x:%02x:%02x:%02x:%02x][%u] : "
-                       "best[%02x:%02x:%02x:%02x:%02x:%02x][%u]",
-                       bss->bssid[0], bss->bssid[1], bss->bssid[2],
-                       bss->bssid[3], bss->bssid[4], bss->bssid[5],
-                       score_new,
-                       network->best_bss->bssid[0], network->best_bss->bssid[1],
-                       network->best_bss->bssid[2], network->best_bss->bssid[3],
-                       network->best_bss->bssid[4], network->best_bss->bssid[5],
-                       score_best);
+               SUPPLICANT_DBG("new[" MACSTR "][%u] : best[" MACSTR "][%u]",
+                       MAC2STR(bss->bssid), score_new,
+                       MAC2STR(network->best_bss->bssid), score_best);
 
-               network->signal = bss->signal;
-               network->frequency = bss->frequency;
-               network->best_bss = bss;
+               update_network_with_best_bss(network, bss);
 
                SUPPLICANT_DBG("Update best BSS for %s", network->name);
 
@@ -3236,10 +3304,8 @@ static void add_timer_for_last_connected(GSupplicantInterface *interface)
                        last_connected_bss_timeout = g_timeout_add_seconds(LAST_CONNECTED_TIMEOUT,
                                last_connected_timeout, interface);
 
-                       SUPPLICANT_DBG("Add timer for last connected bssid "
-                               "[%02x:%02x:%02x:%02x:%02x:%02x]",
-                               best_bss->bssid[0], best_bss->bssid[1], best_bss->bssid[2],
-                               best_bss->bssid[3], best_bss->bssid[4], best_bss->bssid[5]);
+                       SUPPLICANT_DBG("Add timer for last connected bssid [" MACSTR "]",
+                                       MAC2STR(best_bss->bssid));
                }
        }
 }
@@ -3408,6 +3474,21 @@ static void wps_property(const char *key, DBusMessageIter *iter,
 
 }
 
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+void g_supplicant_replace_config_file(const char *ifname, const char *config_file)
+{
+       if (!ifname)
+              return;
+
+       if (!config_file)
+               return;
+
+       SUPPLICANT_DBG("New {%s, %s}", ifname, config_file);
+       g_hash_table_replace(config_file_table,
+                       g_strdup(ifname), g_strdup(config_file));
+}
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+
 static void interface_property(const char *key, DBusMessageIter *iter,
                                                        void *user_data)
 {
@@ -3982,6 +4063,40 @@ static void signal_sta_deauthorized(const char *path, DBusMessageIter *iter)
        callback_sta_deauthorized(interface, addr);
 }
 
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+static void signal_eap(const char *path, DBusMessageIter *iter)
+{
+       GSupplicantInterface *interface;
+       const char *str = NULL;
+
+       SUPPLICANT_DBG("EAPOL_DEBUG callback eap signal");
+
+       interface = g_hash_table_lookup(interface_table, path);
+       if (!interface)
+               return;
+
+       // TODO: Identify EAP fail condition, currently timeout is used for failure.
+
+       dbus_message_iter_get_basic(iter, &str);
+       if (!str)
+               return;
+
+       if (g_strcmp0("completion", str))
+               return;
+
+       dbus_message_iter_next(iter);
+
+       dbus_message_iter_get_basic(iter, &str);
+       if (!str)
+               return;
+
+       if (!g_strcmp0("success", str))
+               callback_eap(interface, true);
+       else
+               callback_eap(interface, false);
+}
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+
 static void signal_bss_changed(const char *path, DBusMessageIter *iter)
 {
        GSupplicantInterface *interface;
@@ -5057,6 +5172,10 @@ static struct {
                signal_mesh_peer_disconnected },
 #endif
 
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+       { SUPPLICANT_INTERFACE ".Interface", "EAP", signal_eap },
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+
        { }
 };
 
@@ -5381,11 +5500,29 @@ static void interface_create_result(const char *error,
        struct interface_create_data *data = user_data;
        const char *path = NULL;
        int err;
+#if defined TIZEN_EXT
+       int ret;
+#endif
 
        SUPPLICANT_DBG("");
 
        if (error) {
                g_message("error %s", error);
+#if defined TIZEN_EXT
+               SUPPLICANT_DBG("error %s", error);
+               if (strcmp(error, "fi.w1.wpa_supplicant1.InterfaceExists") == 0) {
+                       SUPPLICANT_DBG("Send method: GetInterface");
+                       ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
+                                       SUPPLICANT_INTERFACE,
+                                       "GetInterface",
+                                       interface_get_params,
+                                       interface_get_result, user_data,
+                                       NULL);
+                       if (ret < 0)
+                               interface_create_data_free(data);
+                       return;
+               }
+#endif
                err = -EIO;
                goto done;
        }
@@ -5467,6 +5604,53 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data)
        supplicant_dbus_dict_close(iter, &dict);
 }
 
+#if defined TIZEN_EXT
+static void interface_get_state(const char *key, DBusMessageIter *iter,
+               void *user_data)
+{
+       struct interface_create_data *data = user_data;
+       GSupplicantInterface *interface = NULL;
+       const char *str = NULL;
+
+       SUPPLICANT_DBG("key[%s]", key);
+
+       if (!data) {
+               SUPPLICANT_DBG("data is NULL");
+               return;
+       }
+
+       interface = data->interface;
+       if (!interface) {
+               SUPPLICANT_DBG("interface is NULL");
+               return;
+       }
+
+       if (iter)
+               dbus_message_iter_get_basic(iter, &str);
+
+       if (str) {
+               if (string2state(str) != interface->state)
+                       interface->state = string2state(str);
+       }
+
+       if (interface->state == G_SUPPLICANT_STATE_DISABLED)
+               interface->ready = FALSE;
+       else
+               interface->ready = TRUE;
+
+       SUPPLICANT_DBG("state %s (%d)", str, interface->state);
+
+       if (data->callback) {
+               data->callback(0, interface, data->user_data);
+#if defined TIZEN_EXT_WIFI_MESH
+               callback_mesh_support(interface);
+#endif
+       }
+
+       interface_create_data_free(data);
+}
+#endif
+
 static void interface_get_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
@@ -5494,6 +5678,16 @@ static void interface_get_result(const char *error,
                goto done;
        }
 
+#if defined TIZEN_EXT
+       data->interface = interface;
+       err = supplicant_dbus_property_get(path,
+                       SUPPLICANT_INTERFACE ".Interface",
+                       "State", interface_get_state, data, NULL);
+
+       if (err == 0)
+               return;
+#endif
+
        if (data->callback) {
                data->callback(0, interface, data->user_data);
 #if !defined TIZEN_EXT
@@ -5678,6 +5872,7 @@ int g_supplicant_interface_create(const char *ifname, const char *driver,
        data->callback = callback;
        data->user_data = user_data;
 
+#if !defined TIZEN_EXT
        ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
                                                SUPPLICANT_INTERFACE,
                                                "GetInterface",
@@ -5686,6 +5881,16 @@ int g_supplicant_interface_create(const char *ifname, const char *driver,
                                                NULL);
        if (ret < 0)
                interface_create_data_free(data);
+#else
+       ret = supplicant_dbus_method_call(SUPPLICANT_PATH,
+                                               SUPPLICANT_INTERFACE,
+                                               "CreateInterface",
+                                               interface_create_params,
+                                               interface_create_result, data,
+                                               NULL);
+       if (ret < 0)
+               interface_create_data_free(data);
+#endif
 
        return ret;
 }
@@ -5731,7 +5936,6 @@ static void interface_remove_params(DBusMessageIter *iter, void *user_data)
                                                        &data->interface->path);
 }
 
-
 int g_supplicant_interface_remove(GSupplicantInterface *interface,
                        GSupplicantInterfaceCallback callback,
                                                        void *user_data)
@@ -6965,21 +7169,14 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
                }
 
                if (ssid->bssid_for_connect_len) {
-                       snprintf(bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
-                                       ssid->bssid_for_connect[0], ssid->bssid_for_connect[1], ssid->bssid_for_connect[2],
-                                       ssid->bssid_for_connect[3], ssid->bssid_for_connect[4], ssid->bssid_for_connect[5]);
+                       snprintf(bssid, 18, MACSTR, MAC2STR(ssid->bssid_for_connect));
                        memcpy(interface->add_network_bssid, ssid->bssid_for_connect, WIFI_BSSID_LEN_MAX);
                } else {
-                       snprintf(bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
-                                       ssid->bssid[0], ssid->bssid[1], ssid->bssid[2],
-                                       ssid->bssid[3], ssid->bssid[4], ssid->bssid[5]);
+                       snprintf(bssid, 18, MACSTR, MAC2STR(ssid->bssid));
                        memcpy(interface->add_network_bssid, ssid->bssid, WIFI_BSSID_LEN_MAX);
                }
 
-               SUPPLICANT_DBG("bssid [%02x:%02x:%02x:%02x:%02x:%02x]",
-                       interface->add_network_bssid[0], interface->add_network_bssid[1],
-                       interface->add_network_bssid[2], interface->add_network_bssid[3],
-                       interface->add_network_bssid[4], interface->add_network_bssid[5]);
+               SUPPLICANT_DBG("bssid [" MACSTR "]", MAC2STR(interface->add_network_bssid));
 
                supplicant_dbus_dict_append_basic(&dict, "bssid",
                                        DBUS_TYPE_STRING, &bssid);
@@ -8195,7 +8392,37 @@ void g_supplicant_set_ins_settings(GSupplicantINSPreferredFreq preferred_freq_bs
 }
 #endif
 
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+void g_supplicant_register_eap_callback(g_supplicant_eap_callback cb)
+{
+       SUPPLICANT_DBG("g_supplicant_register_eap_callback %p", cb);
+
+       if (!callbacks_pointer) {
+               SUPPLICANT_DBG("callbacks_pointer is NULL");
+               return;
+       }
+
+       callbacks_pointer->eap = cb;
+}
+
+void g_supplicant_unregister_eap_callback(void)
+{
+       SUPPLICANT_DBG("g_supplicant_unregister_eap_callback");
+
+       if (!callbacks_pointer) {
+               SUPPLICANT_DBG("callbacks_pointer is NULL");
+               return;
+       }
+
+       callbacks_pointer->eap = NULL;
+}
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
+
+#if defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET
+int g_supplicant_register(GSupplicantCallbacks *callbacks)
+#else /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
+#endif /* defined TIZEN_EXT && defined TIZEN_EXT_EAP_ON_ETHERNET */
 {
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
        if (!connection)
@@ -8257,6 +8484,7 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks)
        } else
                invoke_introspect_method();
 
+       SUPPLICANT_DBG("supplicant dbus setup completed");
        return 0;
 }