+ GSList *vsie_list = NULL;
+
+ if (!network)
+ return NULL;
+
+ if (g_slist_length(network->vsie_list) > 0) {
+ GSList *list = NULL;
+ unsigned char *vsie = NULL;
+ for (list = network->vsie_list; list; list = list->next) {
+ unsigned char *ie = (unsigned char *)list->data;
+ if (ie == NULL)
+ continue;
+ vsie = (unsigned char *)g_try_malloc0(ie[1]+2); // tag number size(1), tag length size(1)
+
+ if (vsie) {
+ memcpy(vsie, ie, ie[1]+2);
+ vsie_list = g_slist_append(vsie_list, vsie);
+ } else
+ SUPPLICANT_DBG("Failed to allocate memory");
+ }
+ }
+
+ return vsie_list;
+}
+
+static bool compare_bssid(unsigned char *bssid_a, unsigned char *bssid_b)
+{
+ if (!memcmp(bssid_a, bssid_b, WIFI_BSSID_LEN_MAX))
+ return true;
+
+ return false;
+}
+
+static gchar *convert_bssid_to_str(unsigned char *bssid)
+{
+ GString *bssid_str;
+ unsigned int i;
+
+ bssid_str = g_string_sized_new(18);
+ if (!bssid_str)
+ return NULL;
+
+ for (i = 0; i < WIFI_BSSID_LEN_MAX; i++) {
+ g_string_append_printf(bssid_str, "%02x", bssid[i]);
+ if (i < WIFI_BSSID_LEN_MAX - 1)
+ g_string_append(bssid_str, ":");
+ }
+
+ return g_string_free(bssid_str, FALSE);
+}
+
+static void count_assoc_reject(gpointer data, gpointer user_data)
+{
+ time_t assoc_reject_time = GPOINTER_TO_INT(data);
+ struct assoc_count_data *assoc_count = user_data;
+
+ if (assoc_reject_time > assoc_count->ref_time)
+ assoc_count->assoc_count++;
+}
+
+static uint16_t get_assoc_reject_cnt(GHashTable *assoc_reject_table, unsigned char *bssid)
+{
+ gchar *bssid_str;
+ struct assoc_reject_data *assoc_data;
+ struct assoc_count_data assoc_count;
+ time_t curr_time;
+ struct tm* timeinfo;
+
+ if (g_hash_table_size(assoc_reject_table) < 1)
+ return 0;
+
+ if (!bssid)
+ return 0;
+
+ if (!memcmp(bssid, invalid_bssid, WIFI_BSSID_LEN_MAX))
+ return 0;
+
+ bssid_str = convert_bssid_to_str(bssid);
+ if (!bssid_str)
+ return 0;
+
+ assoc_data = g_hash_table_lookup(assoc_reject_table, bssid_str);
+ if (!assoc_data) {
+ g_free(bssid_str);
+ return 0;
+ }
+
+ if (g_slist_length(assoc_data->reject_time_list) < 1) {
+ g_free(bssid_str);
+ return 0;
+ }
+
+ /* Only events that occur within one hour are appened. */
+ curr_time = time(NULL);
+ timeinfo = localtime(&curr_time);
+ timeinfo->tm_hour -= 1;
+
+ assoc_count.ref_time = mktime(timeinfo);
+ assoc_count.assoc_count = 0;
+
+ g_slist_foreach(assoc_data->reject_time_list, count_assoc_reject, &assoc_count);
+
+ g_free(bssid_str);
+ return assoc_count.assoc_count;
+}
+
+static int calculate_score_last_connected_bssid(bool is_last_connected)
+{
+ int score = 0;
+
+ if (ins_settings.last_connected_bssid) {
+ if (is_last_connected)
+ score += ins_settings.last_connected_bssid_score;
+ }
+
+ return score;
+}
+
+static int calculate_score_assoc_reject(uint16_t assoc_reject_cnt)
+{
+ int score = 0;
+
+ if (ins_settings.assoc_reject)
+ score -= (assoc_reject_cnt * ins_settings.assoc_reject_score);
+
+ return score;
+}
+
+static int calculate_score_frequency(dbus_int16_t strength, dbus_uint16_t frequency)
+{
+ int score = 0;
+
+ switch (ins_settings.preferred_freq_bssid) {
+ case G_SUPPLICANT_INS_PREFERRED_FREQ_24GHZ:
+ if ((frequency >= FREQ_RANGE_24GHZ_CHANNEL_1 &&
+ frequency <= FREQ_RANGE_24GHZ_CHANNEL_14) &&
+ (strength > ins_settings.signal_level3_24ghz))
+ score += ins_settings.preferred_freq_bssid_score;
+
+ break;
+ case G_SUPPLICANT_INS_PREFERRED_FREQ_5GHZ:
+ if ((frequency >= FREQ_RANGE_5GHZ_CHANNEL_32 &&
+ frequency <= FREQ_RANGE_5GHZ_CHANNEL_165) &&
+ (strength > ins_settings.signal_level3_5ghz))
+ score += ins_settings.preferred_freq_bssid_score;
+
+ break;
+ default:
+ break;
+ }
+
+ return score;
+}
+
+static int calculate_score_strength(dbus_int16_t strength)
+{
+ int score = 0;
+
+ if (ins_settings.signal_bssid)
+ score += (((strength > -60) ? -60 : strength) + 85);
+
+ 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_uint16_t frequency, dbus_int16_t strength,
+ dbus_int16_t snr, dbus_uint32_t est_throughput)
+{
+ 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);
+ score += (int)snr;
+ score += calculate_score_est_throughput(est_throughput);
+
+ 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);
+ bssids->score_snr = (int)bss->snr;
+ bssids->score_est_throughput = calculate_score_est_throughput(bss->est_throughput);
+#endif
+
+ bssids->ins_score = calculate_score(bssids->is_last_connected,
+ bssids->assoc_reject_cnt, bssids->frequency, bss->signal,
+ bss->snr, bss->est_throughput);
+
+ 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;
+
+ if (entry_a->ins_score > entry_b->ins_score)
+ return -1;
+
+ if (entry_a->ins_score < entry_b->ins_score)
+ return 1;
+
+ return 0;
+}
+
+#if defined TIZEN_EXT_INS
+static void print_bssid_sort(gpointer data, gpointer user_data)
+{
+ struct g_connman_bssids *bssids = data;
+
+ 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
+
+void *g_supplicant_network_get_bssid_list(GSupplicantNetwork *network)
+{
+ struct update_bssid_data bssid_data;
+
+ if (g_hash_table_size(network->bss_table) < 1)
+ return NULL;
+
+ bssid_data.network = network;
+ memset(&bssid_data, 0, sizeof(bssid_data));
+ memcpy(bssid_data.last_connected_bssid, network->last_connected_bssid, WIFI_BSSID_LEN_MAX);
+ bssid_data.assoc_reject_table = network->assoc_reject_table;
+
+ g_hash_table_foreach(network->bss_table, update_bssid_list, &bssid_data);
+ bssid_data.bssid_list = g_slist_sort(bssid_data.bssid_list, cmp_bss);
+#if defined TIZEN_EXT_INS
+ g_slist_foreach(bssid_data.bssid_list, print_bssid_sort, NULL);
+#endif
+
+ return bssid_data.bssid_list;
+}
+
+void g_supplicant_network_set_last_connected_bssid(GSupplicantNetwork *network, const unsigned char *bssid)
+{
+ if (!bssid)
+ return;
+
+ if (!memcmp(bssid, invalid_bssid, WIFI_BSSID_LEN_MAX))
+ return;
+
+ memcpy(network->last_connected_bssid, bssid, WIFI_BSSID_LEN_MAX);
+
+ SUPPLICANT_DBG("last connected bssid [" MACSTR "]", MAC2STR(bssid));
+}
+
+const unsigned char *g_supplicant_network_get_last_connected_bssid(GSupplicantNetwork *network)
+{
+ if (network == NULL)