X-Git-Url: http://review.tizen.org/git/?p=platform%2Fupstream%2Fconnman.git;a=blobdiff_plain;f=gsupplicant%2Fsupplicant.c;h=a7a7bd03df15f33e7f3b53e949e99a22e97b8164;hp=b1232a5de68df986a7719f7562e4cf129f737504;hb=a48fa9fdffe415e9a6f703776b5db795e242ac23;hpb=f25b931309afd533acdd28a74efd9f34edc154ab diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c old mode 100755 new mode 100644 index b1232a5..a7a7bd0 --- a/gsupplicant/supplicant.c +++ b/gsupplicant/supplicant.c @@ -44,6 +44,15 @@ #define IEEE80211_CAP_IBSS 0x0002 #define IEEE80211_CAP_PRIVACY 0x0010 +#if defined TIZEN_EXT +#define WLAN_EID_HT_CAP 45 +#define WLAN_EID_VHT_CAP 191 +#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 + #define BSS_UNKNOWN_STRENGTH -90 static DBusConnection *connection; @@ -92,6 +101,9 @@ static struct strvalmap keymgmt_map[] = { { "wpa-eap", G_SUPPLICANT_KEYMGMT_WPA_EAP }, { "wpa-eap-sha256", G_SUPPLICANT_KEYMGMT_WPA_EAP_256 }, { "wps", G_SUPPLICANT_KEYMGMT_WPS }, +#if defined TIZEN_EXT + { "sae", G_SUPPLICANT_KEYMGMT_SAE }, +#endif { } }; @@ -135,6 +147,9 @@ static struct strvalmap mode_capa_map[] = { { "ad-hoc", G_SUPPLICANT_CAPABILITY_MODE_IBSS }, { "ap", G_SUPPLICANT_CAPABILITY_MODE_AP }, { "p2p", G_SUPPLICANT_CAPABILITY_MODE_P2P }, +#if defined TIZEN_EXT_WIFI_MESH + { "mesh", G_SUPPLICANT_CAPABILITY_MODE_MESH }, +#endif { } }; @@ -143,6 +158,7 @@ static GHashTable *bss_mapping; static GHashTable *peer_mapping; static GHashTable *group_mapping; static GHashTable *pending_peer_connection; +static GHashTable *config_file_table; struct _GSupplicantWpsCredentials { unsigned char ssid[32]; @@ -150,6 +166,21 @@ struct _GSupplicantWpsCredentials { char *key; }; +struct added_network_information { + char * ssid; + GSupplicantSecurity security; + char * passphrase; + char * private_passphrase; +}; + +#if defined TIZEN_EXT_WIFI_MESH +struct _GSupplicantMeshGroupInfo { + unsigned char ssid[32]; + unsigned int ssid_len; + int disconnect_reason; +}; +#endif + struct _GSupplicantInterface { char *path; char *network_path; @@ -163,6 +194,7 @@ struct _GSupplicantInterface { unsigned int max_scan_ssids; bool p2p_support; bool p2p_finding; + bool ap_create_in_progress; dbus_bool_t ready; GSupplicantState state; dbus_bool_t scanning; @@ -177,13 +209,19 @@ struct _GSupplicantInterface { GHashTable *network_table; GHashTable *peer_table; GHashTable *group_table; - GHashTable *net_mapping; GHashTable *bss_mapping; void *data; const char *pending_peer_path; + GSupplicantNetwork *current_network; + struct added_network_information network_info; #if defined TIZEN_EXT + dbus_bool_t is_5_0_Ghz_supported; int disconnect_reason; #endif +#if defined TIZEN_EXT_WIFI_MESH + bool mesh_support; + struct _GSupplicantMeshGroupInfo group_info; +#endif }; struct g_supplicant_bss { @@ -211,10 +249,15 @@ struct g_supplicant_bss { #if defined TIZEN_EXT dbus_bool_t ft_psk; dbus_bool_t ft_ieee8021x; - char *wifi_vsie; - unsigned int wifi_vsie_len; + GSList *vsie_list; + dbus_bool_t hs20; + unsigned char country_code[COUNTRY_CODE_LENGTH]; + GSupplicantPhy_mode phy_mode; #endif unsigned int wps_capabilities; +#if defined TIZEN_EXT + dbus_bool_t sae; +#endif }; struct _GSupplicantNetwork { @@ -234,13 +277,14 @@ struct _GSupplicantNetwork { GHashTable *bss_table; GHashTable *config_table; #if defined TIZEN_EXT - unsigned int isHS20AP; + bool isHS20AP; char *eap; char *identity; char *phase2; unsigned int keymgmt; - char *wifi_vsie; - unsigned int wifi_vsie_len; + GSList *vsie_list; + unsigned char country_code[COUNTRY_CODE_LENGTH]; + GSupplicantPhy_mode phy_mode; #endif }; @@ -267,12 +311,82 @@ struct _GSupplicantGroup { GSList *members; }; +struct interface_data { + GSupplicantInterface *interface; + char *path; /* Interface path cannot be taken from interface (above) as + * it might have been freed already. + */ + GSupplicantInterfaceCallback callback; + void *user_data; + bool network_remove_in_progress; + GSupplicantSSID *ssid; +}; + +#if defined TIZEN_EXT +struct interface_signalpoll_data { + GSupplicantInterface *interface; + char *path; + GSupplicantMaxSpeedCallback callback; + void *user_data; +}; +#endif + +struct interface_create_data { + char *ifname; + char *driver; + char *bridge; +#if defined TIZEN_EXT_WIFI_MESH + char *parent_ifname; + bool is_mesh_interface; +#endif + GSupplicantInterface *interface; + GSupplicantInterfaceCallback callback; + void *user_data; +}; + +struct interface_connect_data { + GSupplicantInterface *interface; + char *path; + GSupplicantInterfaceCallback callback; + void *user_data; + union { + GSupplicantSSID *ssid; + GSupplicantPeerParams *peer; + }; +}; + +struct interface_scan_data { + GSupplicantInterface *interface; + char *path; + GSupplicantInterfaceCallback callback; + GSupplicantScanParams *scan_params; + void *user_data; +}; + +#if defined TIZEN_EXT +struct g_connman_bssids { + unsigned char bssid[WIFI_BSSID_LEN_MAX]; + uint16_t strength; + uint16_t frequency; +}; +#endif + +static int network_remove(struct interface_data *data); + +#if defined TIZEN_EXT_WIFI_MESH +struct _GSupplicantMeshPeer { + GSupplicantInterface *interface; + char *peer_address; + int disconnect_reason; +}; +#endif + static inline void debug(const char *format, ...) { char str[256]; va_list ap; - if (!callbacks_pointer->debug) + if (!callbacks_pointer || !callbacks_pointer->debug) return; va_start(ap, format); @@ -295,6 +409,10 @@ static GSupplicantMode string2mode(const char *mode) return G_SUPPLICANT_MODE_INFRA; else if (g_str_equal(mode, "ad-hoc")) return G_SUPPLICANT_MODE_IBSS; +#if defined TIZEN_EXT_WIFI_MESH + else if (g_str_equal(mode, "mesh")) + return G_SUPPLICANT_MODE_MESH; +#endif return G_SUPPLICANT_MODE_UNKNOWN; } @@ -310,6 +428,10 @@ static const char *mode2string(GSupplicantMode mode) return "adhoc"; case G_SUPPLICANT_MODE_MASTER: return "ap"; +#if defined TIZEN_EXT_WIFI_MESH + case G_SUPPLICANT_MODE_MESH: + return "mesh"; +#endif } return NULL; @@ -333,6 +455,8 @@ static const char *security2string(GSupplicantSecurity security) return "ft_psk"; case G_SUPPLICANT_SECURITY_FT_IEEE8021X: return "ft_ieee8021x"; + case G_SUPPLICANT_SECURITY_SAE: + return "sae"; #endif } @@ -370,6 +494,75 @@ static GSupplicantState string2state(const char *state) return G_SUPPLICANT_STATE_UNKNOWN; } +static bool compare_network_parameters(GSupplicantInterface *interface, + GSupplicantSSID *ssid) +{ +#if defined TIZEN_EXT + if (!interface->network_info.ssid) + return FALSE; +#endif + + if (memcmp(interface->network_info.ssid, ssid->ssid, ssid->ssid_len)) + return FALSE; + + if (interface->network_info.security != ssid->security) + return FALSE; + + if (interface->network_info.passphrase && + g_strcmp0(interface->network_info.passphrase, + ssid->passphrase) != 0) { + return FALSE; + } + + if (interface->network_info.private_passphrase && + g_strcmp0(interface->network_info.private_passphrase, + ssid->private_key_passphrase) != 0) { + return FALSE; + } + + return TRUE; +} + +static void remove_network_information(GSupplicantInterface * interface) +{ + g_free(interface->network_info.ssid); + g_free(interface->network_info.passphrase); + g_free(interface->network_info.private_passphrase); + interface->network_info.ssid = NULL; + interface->network_info.passphrase = NULL; + interface->network_info.private_passphrase = NULL; +} + +static int store_network_information(GSupplicantInterface * interface, + GSupplicantSSID *ssid) +{ + interface->network_info.ssid = g_malloc(ssid->ssid_len + 1); + if (interface->network_info.ssid != NULL) { + memcpy(interface->network_info.ssid, ssid->ssid, + ssid->ssid_len); + interface->network_info.ssid[ssid->ssid_len] = '\0'; + } else { + return -ENOMEM; + } + + interface->network_info.security = ssid->security; + + if ((ssid->security == G_SUPPLICANT_SECURITY_WEP || + ssid->security == G_SUPPLICANT_SECURITY_PSK || + ssid->security == G_SUPPLICANT_SECURITY_NONE) && + ssid->passphrase) { + interface->network_info.passphrase = g_strdup(ssid->passphrase); + } + + if (ssid->security == G_SUPPLICANT_SECURITY_IEEE8021X && + ssid->private_key_passphrase) { + interface->network_info.private_passphrase = + g_strdup(ssid->private_key_passphrase); + } + + return 0; +} + static void callback_system_ready(void) { if (system_ready) @@ -447,6 +640,27 @@ static void callback_p2p_support(GSupplicantInterface *interface) } #endif +#if defined TIZEN_EXT_WIFI_MESH +static void callback_mesh_support(GSupplicantInterface *interface) +{ + SUPPLICANT_DBG(""); + + if (!interface->mesh_support) + return; + + if (callbacks_pointer && callbacks_pointer->mesh_support) + callbacks_pointer->mesh_support(interface); +} + +bool g_supplicant_interface_has_mesh(GSupplicantInterface *interface) +{ + if (!interface) + return false; + + return interface->mesh_support; +} +#endif + static void callback_scan_started(GSupplicantInterface *interface) { if (!callbacks_pointer) @@ -458,6 +672,17 @@ static void callback_scan_started(GSupplicantInterface *interface) callbacks_pointer->scan_started(interface); } +static void callback_ap_create_fail(GSupplicantInterface *interface) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->ap_create_fail) + return; + + callbacks_pointer->ap_create_fail(interface); +} + static void callback_scan_finished(GSupplicantInterface *interface) { if (!callbacks_pointer) @@ -502,6 +727,17 @@ static void callback_network_merged(GSupplicantNetwork *network) callbacks_pointer->network_merged(network); } + +static void callback_assoc_failed(void *user_data) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->assoc_failed) + return; + + callbacks_pointer->assoc_failed(user_data); +} #endif static void callback_network_changed(GSupplicantNetwork *network, @@ -516,6 +752,17 @@ static void callback_network_changed(GSupplicantNetwork *network, callbacks_pointer->network_changed(network, property); } +static void callback_network_associated(GSupplicantNetwork *network) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->network_associated) + return; + + callbacks_pointer->network_associated(network); +} + static void callback_peer_found(GSupplicantPeer *peer) { if (!callbacks_pointer) @@ -606,7 +853,6 @@ static void remove_interface(gpointer data) GSupplicantInterface *interface = data; g_hash_table_destroy(interface->bss_mapping); - g_hash_table_destroy(interface->net_mapping); g_hash_table_destroy(interface->network_table); g_hash_table_destroy(interface->peer_table); g_hash_table_destroy(interface->group_table); @@ -637,6 +883,7 @@ static void remove_interface(gpointer data) g_free(interface->ifname); g_free(interface->driver); g_free(interface->bridge); + remove_network_information(interface); g_free(interface); } @@ -659,7 +906,7 @@ static void remove_network(gpointer data) g_free(network->phase2); #endif #if defined TIZEN_EXT - g_free(network->wifi_vsie); + g_slist_free_full(network->vsie_list, g_free); #endif g_free(network); @@ -671,7 +918,7 @@ static void remove_bss(gpointer data) g_free(bss->path); #if defined TIZEN_EXT - g_free(bss->wifi_vsie); + g_slist_free_full(bss->vsie_list, g_free); #endif g_free(bss); } @@ -694,6 +941,7 @@ static void remove_peer(gpointer data) g_free(peer->path); g_free(peer->name); g_free(peer->identifier); + g_free(peer->widi_ies); g_free(peer); } @@ -865,26 +1113,71 @@ static void interface_capability(const char *key, DBusMessageIter *iter, if (max_scan_ssid < 2) max_scan_ssid = 0; interface->max_scan_ssids = max_scan_ssid; +#if defined TIZEN_EXT + } else if (g_strcmp0(key, "Is5GhzSupported") == 0) { + dbus_bool_t is_5_0_Ghz_supported; + dbus_message_iter_get_basic(iter, &is_5_0_Ghz_supported); + interface->is_5_0_Ghz_supported = is_5_0_Ghz_supported; +#endif } else SUPPLICANT_DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter)); } +struct set_apscan_data +{ + unsigned int ap_scan; + GSupplicantInterface *interface; +}; + static void set_apscan(DBusMessageIter *iter, void *user_data) { - unsigned int ap_scan = *(unsigned int *)user_data; + struct set_apscan_data *data = user_data; + unsigned int ap_scan = data->ap_scan; dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ap_scan); } +static void set_apscan_complete(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct set_apscan_data *data = user_data; + GSupplicantInterface *interface = data->interface; + + if (error) { + interface->ap_create_in_progress = false; + SUPPLICANT_DBG("Set AP scan error %s", error); + goto error; + } + + interface->ap_create_in_progress = true; +error: + dbus_free(data); +} + int g_supplicant_interface_set_apscan(GSupplicantInterface *interface, unsigned int ap_scan) { - return supplicant_dbus_property_set(interface->path, + struct set_apscan_data *data; + int ret; + + data = dbus_malloc0(sizeof(*data)); + + if (!data) + return -ENOMEM; + + data->ap_scan = ap_scan; + data->interface = interface; + + ret = supplicant_dbus_property_set(interface->path, SUPPLICANT_INTERFACE ".Interface", - "ApScan", DBUS_TYPE_UINT32_AS_STRING, - set_apscan, NULL, &ap_scan, NULL); + "ApScan", DBUS_TYPE_UINT32_AS_STRING, + set_apscan, set_apscan_complete, data, NULL); + if (ret < 0) + dbus_free(data); + + return ret; } void g_supplicant_interface_set_data(GSupplicantInterface *interface, @@ -915,6 +1208,16 @@ const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface) return interface->ifname; } +#if defined TIZEN_EXT +bool g_supplicant_interface_get_is_5_0_ghz_supported(GSupplicantInterface *interface) +{ + if (!interface) + return NULL; + + return interface->is_5_0_Ghz_supported; +} +#endif + const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface) { if (!interface) @@ -1133,6 +1436,16 @@ dbus_bool_t g_supplicant_network_is_wps_advertizing(GSupplicantNetwork *network) return FALSE; } +#ifdef TIZEN_EXT +GSupplicantPhy_mode g_supplicant_network_get_phy_mode(GSupplicantNetwork *network) +{ + if (!network) + return G_SUPPLICANT_MODE_IEEE80211_UNKNOWN; + + return network->phy_mode; +} +#endif + GSupplicantInterface *g_supplicant_peer_get_interface(GSupplicantPeer *peer) { if (!peer) @@ -1182,7 +1495,7 @@ const char *g_supplicant_peer_get_name(GSupplicantPeer *peer) } #if defined TIZEN_EXT -unsigned int g_supplicant_network_is_hs20AP(GSupplicantNetwork *network) +bool g_supplicant_network_is_hs20AP(GSupplicantNetwork *network) { if (!network) return 0; @@ -1221,6 +1534,15 @@ unsigned int g_supplicant_network_get_keymgmt(GSupplicantNetwork *network) return network->keymgmt; } + +const unsigned char *g_supplicant_network_get_countrycode(GSupplicantNetwork + *network) +{ + if (!network) + return NULL; + + return network->country_code; +} #endif const unsigned char *g_supplicant_peer_get_widi_ies(GSupplicantPeer *peer, @@ -1331,6 +1653,9 @@ 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 || +#endif /* TIZEN_EXT */ network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) { unsigned int pairwise; @@ -1358,6 +1683,11 @@ 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) + return false; +#endif /* TIZEN_EXT */ + if (network->best_bss->rsn_selected) { const char *mode = g_supplicant_network_get_enc_mode(network); if (g_strcmp0(mode, "aes") == 0 || @@ -1369,16 +1699,81 @@ bool g_supplicant_network_get_rsn_mode(GSupplicantNetwork *network) return false; } -const void *g_supplicant_network_get_wifi_vsie(GSupplicantNetwork *network, - unsigned int *wifi_vsie_len) +void *g_supplicant_network_get_wifi_vsie(GSupplicantNetwork *network) { - if (!network) { - *wifi_vsie_len = 0; + 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"); + } } - *wifi_vsie_len = network->wifi_vsie_len; - return network->wifi_vsie; + return vsie_list; +} + +static void update_bssid_list(gpointer key, gpointer value, gpointer user_data) +{ + struct g_supplicant_bss *bss = value; + struct g_connman_bssids *bssids = NULL; + GSList **list = (GSList **)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; + *list = g_slist_append(*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->strength > entry_b->strength) + return -1; + + if (entry_a->strength < entry_b->strength) + return 1; + + return 0; +} + +void *g_supplicant_network_get_bssid_list(GSupplicantNetwork *network) +{ + GSList *bssid_list = NULL; + + if (g_hash_table_size(network->bss_table) < 1) + return NULL; + + g_hash_table_foreach(network->bss_table, update_bssid_list, &bssid_list); + bssid_list = g_slist_sort(bssid_list, cmp_bss); + + return bssid_list; } #endif @@ -1387,7 +1782,6 @@ static void merge_network(GSupplicantNetwork *network) GString *str; const char *ssid, *mode, *key_mgmt; #if defined TIZEN_EXT - GSupplicantInterface *interface; const char *isHS20AP; const char *eap, *identity, *phase2; #endif @@ -1402,7 +1796,6 @@ static void merge_network(GSupplicantNetwork *network) eap = g_hash_table_lookup(network->config_table, "eap"); identity = g_hash_table_lookup(network->config_table, "identity"); phase2 = g_hash_table_lookup(network->config_table, "phase2"); - interface = network->interface; #endif SUPPLICANT_DBG("ssid %s mode %s", ssid, mode); @@ -1430,6 +1823,10 @@ static void merge_network(GSupplicantNetwork *network) g_string_append_printf(str, "_managed"); else if (g_strcmp0(mode, "1") == 0) g_string_append_printf(str, "_adhoc"); +#if defined TIZEN_EXT_WIFI_MESH + else if (g_strcmp0(mode, "5") == 0) + g_string_append_printf(str, "_mesh"); +#endif if (g_strcmp0(key_mgmt, "WPA-PSK") == 0) g_string_append_printf(str, "_psk"); @@ -1461,11 +1858,9 @@ static void merge_network(GSupplicantNetwork *network) } else network->isHS20AP = 0; - if (interface) - interface->network_path = g_strdup(network->path); - network->group = g_strdup(group); callback_network_merged(network); + g_free(network->group); #endif g_free(group); @@ -1521,10 +1916,6 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data) if (g_strcmp0(path, "/") == 0) return; - network = g_hash_table_lookup(interface->net_mapping, path); - if (network) - return; - network = g_try_new0(GSupplicantNetwork, 1); if (!network) return; @@ -1550,19 +1941,8 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data) static void interface_network_removed(DBusMessageIter *iter, void *user_data) { - GSupplicantInterface *interface = user_data; - GSupplicantNetwork *network; - const char *path = NULL; - - dbus_message_iter_get_basic(iter, &path); - if (!path) - return; - - network = g_hash_table_lookup(interface->net_mapping, path); - if (!network) - return; - - g_hash_table_remove(interface->net_mapping, path); + SUPPLICANT_DBG(""); + return; } static char *create_name(unsigned char *ssid, int ssid_len) @@ -1633,7 +2013,7 @@ static char *create_group(struct g_supplicant_bss *bss) return g_string_free(str, FALSE); } -static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss) +static int add_or_replace_bss_to_network(struct g_supplicant_bss *bss) { GSupplicantInterface *interface = bss->interface; GSupplicantNetwork *network; @@ -1643,7 +2023,7 @@ static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss) SUPPLICANT_DBG("New group created: %s", group); if (!group) - return; + return -ENOMEM; network = g_hash_table_lookup(interface->network_table, group); if (network) { @@ -1656,7 +2036,7 @@ static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss) network = g_try_new0(GSupplicantNetwork, 1); if (!network) { g_free(group); - return; + return -ENOMEM; } network->interface = interface; @@ -1675,16 +2055,24 @@ static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss) #if defined TIZEN_EXT network->keymgmt = bss->keymgmt; - if (bss->wifi_vsie_len > 0) { - SUPPLICANT_DBG("vsie len: %d", bss->wifi_vsie_len); - network->wifi_vsie = (char *)g_try_malloc0(bss->wifi_vsie_len); - if(network->wifi_vsie) { - network->wifi_vsie_len = bss->wifi_vsie_len; - memcpy(network->wifi_vsie, bss->wifi_vsie, network->wifi_vsie_len); - } else { - SUPPLICANT_DBG("Failed to allocate memory for wifi_vsie"); + if (g_slist_length(bss->vsie_list) > 0) { + GSList *list = NULL; + unsigned char *vsie = NULL; + for (list = bss->vsie_list; list; list = list->next) { + unsigned char *ie = (unsigned char *)list->data; + 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); + network->vsie_list = g_slist_append(network->vsie_list, vsie); + } else + SUPPLICANT_DBG("Failed to allocate memory."); } } + + network->isHS20AP = bss->hs20; + memcpy(network->country_code, bss->country_code, COUNTRY_CODE_LENGTH); + network->phy_mode = bss->phy_mode; #endif SUPPLICANT_DBG("New network %s created", network->name); @@ -1707,7 +2095,12 @@ done: network->wps_capabilities |= bss->wps_capabilities; } - if (bss->signal > network->signal) { + /* + * Do not change best BSS if we are connected. It will be done through + * CurrentBSS property in case of misalignment with wpa_s or roaming. + */ + if (network != interface->current_network && + bss->signal > network->signal) { network->signal = bss->signal; network->best_bss = bss; callback_network_changed(network, "Signal"); @@ -1717,6 +2110,8 @@ done: g_hash_table_replace(network->bss_table, bss->path, bss); g_hash_table_replace(bss_mapping, bss->path, interface); + + return 0; } static void bss_rates(DBusMessageIter *iter, void *user_data) @@ -1860,17 +2255,67 @@ static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size, return 0; } +#if defined TIZEN_EXT +static void get_bss_phy_mode(unsigned int max_rate, + unsigned int max_ext_rate, bool ht, bool vht, void *data) +{ + struct g_supplicant_bss *bss = data; + unsigned int freq = bss->frequency; + + /* Following conditions are used to determine + * IEEE 802.11 Protocol Modes:- + * + * 1. If “Supported rates” is only till 11 Mbps, + * and frequency is in 2.4GHz band, then protocol is 11B. + * 2. If “Supported rates” is till 54Mbps or + * “Extended supported rates” are present, + * and frequency is in 2.4GHz band, then protocol is 11G. + * 3. If “Supported rates” is only till 54 Mbps, + * frequency is in 5GHz band , then protocol is 11A. + * 4. If “HT capabilities” is supported , then protocol is 11N. + * 5. If “HT capabilities” & “VHT” is supported and + * frequency is in 5 GHz band, then protocol is 11AC. + * */ + + if (freq >= 2412 && freq <= 2484) { /* 2.4 Ghz Band */ + if (max_rate <= 11 && max_ext_rate <= 0 && !ht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211B; + else if ((max_rate <= 54 || max_ext_rate > 0) && !ht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211BG; + else if ((max_rate >= 54 || max_ext_rate > 0) && ht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211BGN; + else + bss->phy_mode = G_SUPPLICANT_MODE_UNKNOWN; + } else if (freq >= 5180 && freq <= 5825) { /* 5 Ghz Band */ + if (max_rate <= 54 && !ht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211A; + else if ((max_rate >= 54 || max_ext_rate > 0) && ht && !vht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211AN; + else if ((max_rate >= 54 || max_ext_rate > 0) && ht && vht) + bss->phy_mode = G_SUPPLICANT_MODE_IEEE80211ANAC; + else + bss->phy_mode = G_SUPPLICANT_MODE_UNKNOWN; + } +} +#endif + static void bss_process_ies(DBusMessageIter *iter, void *user_data) { struct g_supplicant_bss *bss = user_data; const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 }; -#if defined TIZEN_EXT - const unsigned char WIFI_OUI[] = {0x00, 0x16, 0x32}; -#endif unsigned char *ie, *ie_end; DBusMessageIter array; unsigned int value; int ie_len; +#if defined TIZEN_EXT + int r_len, j; + unsigned char *rates = NULL; + unsigned char *ext_rates = NULL; + unsigned int max_rate = 0; + unsigned int max_ext_rate = 0; + bool ht = false; + bool vht = false; +#endif #define WMM_WPA1_WPS_INFO 221 #define WPS_INFO_MIN_LEN 6 @@ -1884,6 +2329,7 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) #define WPS_CONFIGURED 0x02 #if defined TIZEN_EXT #define VENDOR_SPECIFIC_INFO 0xDD +#define WLAN_EID_COUNTRY 7 #endif dbus_message_iter_recurse(iter, &array); @@ -1894,20 +2340,71 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) bss->wps_capabilities = 0; bss->keymgmt = 0; + memset(bss->country_code, 0, COUNTRY_CODE_LENGTH); for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end; ie += ie[1] + 2) { #if defined TIZEN_EXT - if((ie[0] == VENDOR_SPECIFIC_INFO) && (memcmp(ie+2, WIFI_OUI, sizeof(WIFI_OUI)) == 0)) { - SUPPLICANT_DBG("IE: match WIFI_OUI"); - bss->wifi_vsie = (char *)g_try_malloc0(ie[1] + 2); // tag number size(1), tag length size(1) - if (bss->wifi_vsie) { - bss->wifi_vsie_len = ie[1] + 2; - memcpy(bss->wifi_vsie, ie, bss->wifi_vsie_len); - } else { - SUPPLICANT_DBG("Failed to allocate memory for wifi_vsie"); - } + unsigned char *vsie; + int vsie_len = 0; + if(ie[0] == VENDOR_SPECIFIC_INFO && memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) { + SUPPLICANT_DBG("IE: match vendor specific data"); + + vsie_len = ie[1]+2; // tag number size(1), tag length size(1) + vsie = (unsigned char *)g_try_malloc0(vsie_len); + + if (vsie) { + memcpy(vsie, ie, vsie_len); + bss->vsie_list = g_slist_append(bss->vsie_list, vsie); + } else + SUPPLICANT_DBG("Failed to allocate memory"); + continue; + } + + 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); + continue; + } + } + + if (ie[0] == WLAN_EID_HT_CAP && ie[1]) { + ht = true; + continue; + } + + if (ie[0] == WLAN_EID_VHT_CAP && ie[1]) { + vht = true; + continue; + } + + if (ie[0] == WLAN_EID_SUPP_RATES && ie[1]) { + r_len = ie[1]; + rates = g_malloc0(r_len); + if (!rates) + continue; + + for (j = 0; ie && j < r_len; j++) { + rates[j] = ((ie[j + 2] & 0x7f) * 500000)/1000000; + if (max_rate < rates[j]) + max_rate = rates[j]; + } + continue; + } + + if (ie[0] == WLAN_EID_EXT_SUPP_RATES && ie[1] > 0) { + r_len = ie[1]; + ext_rates = g_malloc0(r_len); + if (!ext_rates) continue; + + for (j = 0; ie && j < r_len; j++) { + ext_rates[j] = ((ie[j + 2] & 0x7f) * 500000)/1000000; + if (max_ext_rate < ext_rates[j]) + max_ext_rate = ext_rates[j]; + } + continue; } #endif if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN || @@ -1944,6 +2441,13 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) SUPPLICANT_DBG("WPS Methods 0x%x", bss->wps_capabilities); } +#ifdef TIZEN_EXT + get_bss_phy_mode(max_rate, max_ext_rate, ht, vht, user_data); + if (rates) + g_free(rates); + if (ext_rates) + g_free(ext_rates); +#endif } static void bss_compute_security(struct g_supplicant_bss *bss) @@ -1990,6 +2494,11 @@ static void bss_compute_security(struct g_supplicant_bss *bss) bss->psk = TRUE; #endif +#if defined TIZEN_EXT + if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_SAE) + bss->sae = TRUE; +#endif + if (bss->ieee8021x) bss->security = G_SUPPLICANT_SECURITY_IEEE8021X; else if (bss->psk) @@ -2000,6 +2509,10 @@ static void bss_compute_security(struct g_supplicant_bss *bss) else if (bss->ft_ieee8021x == TRUE) bss->security = G_SUPPLICANT_SECURITY_IEEE8021X; #endif +#if defined TIZEN_EXT + else if (bss->sae) + bss->security = G_SUPPLICANT_SECURITY_SAE; +#endif else if (bss->privacy) bss->security = G_SUPPLICANT_SECURITY_WEP; else @@ -2101,6 +2614,12 @@ static void bss_property(const char *key, DBusMessageIter *iter, bss->rsn_selected = FALSE; supplicant_dbus_property_foreach(iter, bss_wpa, bss); +#if defined TIZEN_EXT + } else if (g_strcmp0(key, "HS20") == 0) { + dbus_bool_t hs20 = FALSE; + dbus_message_iter_get_basic(iter, &hs20); + bss->hs20 = hs20; +#endif } else if (g_strcmp0(key, "IEs") == 0) bss_process_ies(iter, bss); else @@ -2164,7 +2683,8 @@ static void interface_bss_added_with_keys(DBusMessageIter *iter, supplicant_dbus_property_foreach(iter, bss_property, bss); bss_compute_security(bss); - add_or_replace_bss_to_network(bss); + if (add_or_replace_bss_to_network(bss) < 0) + SUPPLICANT_DBG("add_or_replace_bss_to_network failed"); } static void interface_bss_added_without_keys(DBusMessageIter *iter, @@ -2183,7 +2703,8 @@ static void interface_bss_added_without_keys(DBusMessageIter *iter, bss_property, bss, NULL); bss_compute_security(bss); - add_or_replace_bss_to_network(bss); + if (add_or_replace_bss_to_network(bss) < 0) + SUPPLICANT_DBG("add_or_replace_bss_to_network failed"); } static void update_signal(gpointer key, gpointer value, @@ -2209,12 +2730,82 @@ static void update_network_signal(GSupplicantNetwork *network) SUPPLICANT_DBG("New network signal %d", network->signal); } +static void interface_current_bss(GSupplicantInterface *interface, + DBusMessageIter *iter) +{ + GSupplicantNetwork *network; + struct g_supplicant_bss *bss; + const char *path; + + dbus_message_iter_get_basic(iter, &path); + if (g_strcmp0(path, "/") == 0) { + interface->current_network = NULL; + return; + } + + interface_bss_added_without_keys(iter, interface); + + network = g_hash_table_lookup(interface->bss_mapping, path); + if (!network) + return; + + bss = g_hash_table_lookup(network->bss_table, path); + if (!bss) + return; + + interface->current_network = network; + + if (bss != network->best_bss) { + /* + * This is the case where either wpa_s got associated + * to a BSS different than the one ConnMan considers + * the best, or we are roaming. + */ + SUPPLICANT_DBG("Update best BSS for %s", network->name); + + network->best_bss = bss; + + if (network->signal != bss->signal) { + SUPPLICANT_DBG("New network signal %d dBm", + bss->signal); + + network->signal = bss->signal; + callback_network_changed(network, "Signal"); + } + } + + /* + * wpa_s could notify about CurrentBSS in any state once + * it got associated. It is not sure such notification will + * arrive together with transition to ASSOCIATED state. + * In fact, for networks with security WEP or OPEN, it + * always arrives together with transition to COMPLETED. + */ + switch (interface->state) { + case G_SUPPLICANT_STATE_UNKNOWN: + case G_SUPPLICANT_STATE_DISABLED: + case G_SUPPLICANT_STATE_DISCONNECTED: + case G_SUPPLICANT_STATE_INACTIVE: + case G_SUPPLICANT_STATE_SCANNING: + case G_SUPPLICANT_STATE_AUTHENTICATING: + case G_SUPPLICANT_STATE_ASSOCIATING: + return; + case G_SUPPLICANT_STATE_ASSOCIATED: + case G_SUPPLICANT_STATE_4WAY_HANDSHAKE: + case G_SUPPLICANT_STATE_GROUP_HANDSHAKE: + case G_SUPPLICANT_STATE_COMPLETED: + callback_network_associated(network); + break; + } +} + static void interface_bss_removed(DBusMessageIter *iter, void *user_data) { GSupplicantInterface *interface = user_data; GSupplicantNetwork *network; struct g_supplicant_bss *bss = NULL; const char *path = NULL; + bool is_current_network_bss = false; dbus_message_iter_get_basic(iter, &path); if (!path) @@ -2228,6 +2819,7 @@ static void interface_bss_removed(DBusMessageIter *iter, void *user_data) if (network->best_bss == bss) { network->best_bss = NULL; network->signal = BSS_UNKNOWN_STRENGTH; + is_current_network_bss = true; } g_hash_table_remove(bss_mapping, path); @@ -2237,16 +2829,51 @@ static void interface_bss_removed(DBusMessageIter *iter, void *user_data) update_network_signal(network); - if (g_hash_table_size(network->bss_table) == 0) + if (g_hash_table_size(network->bss_table) == 0) { g_hash_table_remove(interface->network_table, network->group); + } else { + if (is_current_network_bss && network->best_bss) +#if defined TIZEN_EXT + callback_network_changed(network, "CheckMultiBssidConnect"); +#else + callback_network_changed(network, ""); +#endif + } } static void set_config_methods(DBusMessageIter *iter, void *user_data) { - const char *config_methods = "push_button"; + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, user_data); +} + +static void wps_property(const char *key, DBusMessageIter *iter, + void *user_data) +{ + GSupplicantInterface *interface = user_data; + + if (!interface) + return; + + SUPPLICANT_DBG("key: %s", key); + + if (g_strcmp0(key, "ConfigMethods") == 0) { + const char *config_methods = "push_button", *str = NULL; + + dbus_message_iter_get_basic(iter, &str); + if (str && strlen(str) > 0) { + /* It was already set at wpa_s level, don't modify it. */ + SUPPLICANT_DBG("%s", str); + return; + } + + supplicant_dbus_property_set(interface->path, + SUPPLICANT_INTERFACE ".Interface.WPS", + "ConfigMethods", DBUS_TYPE_STRING_AS_STRING, + set_config_methods, NULL, &config_methods, NULL); + + SUPPLICANT_DBG("No value. Set %s", config_methods); + } - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, - &config_methods); } static void interface_property(const char *key, DBusMessageIter *iter, @@ -2275,11 +2902,9 @@ static void interface_property(const char *key, DBusMessageIter *iter, debug_strvalmap("Mode capability", mode_capa_map, interface->mode_capa); - - supplicant_dbus_property_set(interface->path, + supplicant_dbus_property_get_all(interface->path, SUPPLICANT_INTERFACE ".Interface.WPS", - "ConfigMethods", DBUS_TYPE_STRING_AS_STRING, - set_config_methods, NULL, NULL, NULL); + wps_property, interface, interface); if (interface->ready) callback_interface_added(interface); @@ -2294,6 +2919,10 @@ static void interface_property(const char *key, DBusMessageIter *iter, if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_P2P) interface->p2p_support = true; #endif +#if defined TIZEN_EXT_WIFI_MESH + if (interface->mode_capa & G_SUPPLICANT_CAPABILITY_MODE_MESH) + interface->mesh_support = true; +#endif } else if (g_strcmp0(key, "State") == 0) { const char *str = NULL; @@ -2303,6 +2932,14 @@ static void interface_property(const char *key, DBusMessageIter *iter, interface->state = string2state(str); callback_interface_state(interface); } + + if (interface->ap_create_in_progress) { + if (interface->state == G_SUPPLICANT_STATE_DISCONNECTED) + callback_ap_create_fail(interface); + + interface->ap_create_in_progress = false; + } + if (interface->state == G_SUPPLICANT_STATE_DISABLED) interface->ready = FALSE; else @@ -2350,8 +2987,17 @@ static void interface_property(const char *key, DBusMessageIter *iter, g_free(interface->bridge); interface->bridge = g_strdup(str); } + } else if (g_strcmp0(key, "ConfigFile") == 0) { + const char *str = NULL; + + dbus_message_iter_get_basic(iter, &str); + if (str && strlen(str) > 0 && interface->ifname) { + SUPPLICANT_DBG("New {%s, %s}", interface->ifname, str); + g_hash_table_replace(config_file_table, + g_strdup(interface->ifname), g_strdup(str)); + } } else if (g_strcmp0(key, "CurrentBSS") == 0) { - interface_bss_added_without_keys(iter, interface); + interface_current_bss(interface, iter); } else if (g_strcmp0(key, "CurrentNetwork") == 0) { #if defined TIZEN_EXT if (interface->state != G_SUPPLICANT_STATE_COMPLETED) @@ -2378,9 +3024,10 @@ static void interface_property(const char *key, DBusMessageIter *iter, dbus_message_iter_get_basic(iter, &status_code); callback_assoc_status_code(interface, status_code); } - } else + } else { SUPPLICANT_DBG("key %s type %c", key, dbus_message_iter_get_arg_type(iter)); + } } static void scan_network_update(DBusMessageIter *iter, void *user_data) @@ -2453,8 +3100,6 @@ static GSupplicantInterface *interface_alloc(const char *path) g_str_equal, NULL, remove_peer); interface->group_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, remove_group); - interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, NULL); interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); @@ -2467,6 +3112,7 @@ static void interface_added(DBusMessageIter *iter, void *user_data) { GSupplicantInterface *interface; const char *path = NULL; + bool properties_appended = GPOINTER_TO_UINT(user_data); SUPPLICANT_DBG(""); @@ -2485,18 +3131,20 @@ static void interface_added(DBusMessageIter *iter, void *user_data) if (!interface) return; + if (!properties_appended) { + supplicant_dbus_property_get_all(path, + SUPPLICANT_INTERFACE ".Interface", + interface_property, interface, + interface); + return; + } + dbus_message_iter_next(iter); if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) { supplicant_dbus_property_foreach(iter, interface_property, interface); interface_property(NULL, NULL, interface); - return; } - - supplicant_dbus_property_get_all(path, - SUPPLICANT_INTERFACE ".Interface", - interface_property, interface, - interface); } static void interface_removed(DBusMessageIter *iter, void *user_data) @@ -2599,6 +3247,7 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter) g_hash_table_remove_all(bss_mapping); g_hash_table_remove_all(peer_mapping); g_hash_table_remove_all(group_mapping); + g_hash_table_remove_all(config_file_table); g_hash_table_remove_all(interface_table); callback_system_killed(); } @@ -2626,7 +3275,7 @@ static void signal_interface_added(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH); if (g_strcmp0(path, SUPPLICANT_PATH) == 0) - interface_added(iter, NULL); + interface_added(iter, GUINT_TO_POINTER(true)); } static void signal_interface_removed(const char *path, DBusMessageIter *iter) @@ -2738,6 +3387,13 @@ static void signal_network_removed(const char *path, DBusMessageIter *iter) interface_network_removed(iter, interface); } +#if defined TIZEN_EXT +void *copy_vsie_list(gconstpointer src, gpointer data) +{ + return g_strdup(src); +} +#endif + static void signal_bss_changed(const char *path, DBusMessageIter *iter) { @@ -2763,6 +3419,7 @@ 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; #endif old_security = network->security; bss_compute_security(bss); @@ -2789,10 +3446,20 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) memcpy(new_bss, bss, sizeof(struct g_supplicant_bss)); new_bss->path = g_strdup(bss->path); +#if defined TIZEN_EXT + new_bss->vsie_list = g_slist_copy_deep(bss->vsie_list, copy_vsie_list, NULL); +#endif g_hash_table_remove(interface->network_table, network->group); - add_or_replace_bss_to_network(new_bss); + if (add_or_replace_bss_to_network(new_bss) < 0) { + /* Remove entries in hash tables to handle the + * failure in add_or_replace_bss_to_network + */ + g_hash_table_remove(bss_mapping, path); + g_hash_table_remove(interface->bss_mapping, path); + g_hash_table_remove(network->bss_table, path); + } return; } @@ -2805,6 +3472,10 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) network->wps = FALSE; #endif + /* Consider only property changes of the connected BSS */ + if (network == interface->current_network && bss != network->best_bss) + return; + if (bss->signal == network->signal) #ifndef TIZEN_EXT return; @@ -3061,7 +3732,7 @@ static void peer_groups_relation(DBusMessageIter *iter, void *user_data) if (!group) return; - elem = g_slist_find_custom(data->old_groups, str, g_str_equal); + elem = g_slist_find_custom(data->old_groups, str, (GCompareFunc)g_strcmp0); if (elem) { data->old_groups = g_slist_remove_link(data->old_groups, elem); peer->groups = g_slist_concat(elem, peer->groups); @@ -3557,90 +4228,308 @@ static void signal_group_peer_disconnected(const char *path, DBusMessageIter *it peer->connection_requested = false; } -static struct { - const char *interface; - const char *member; - void (*function) (const char *path, DBusMessageIter *iter); -} signal_map[] = { - { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed }, - - { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed }, - { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added }, - { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added }, - { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed }, - - { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed }, - { SUPPLICANT_INTERFACE ".Interface", "ScanDone", signal_scan_done }, - { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added }, - { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed }, - { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added }, - { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed }, +#if defined TIZEN_EXT_WIFI_MESH +const void *g_supplicant_interface_get_mesh_group_ssid( + GSupplicantInterface *interface, + unsigned int *ssid_len) +{ + if (!ssid_len) + return NULL; - { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed }, + if (!interface || interface->group_info.ssid_len == 0) { + *ssid_len = 0; + return NULL; + } - { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials }, - { SUPPLICANT_INTERFACE ".Interface.WPS", "Event", signal_wps_event }, -#if defined TIZEN_EXT - { "org.tizen.system.deviced.PowerOff", "ChangeState", signal_power_off }, -#endif + *ssid_len = interface->group_info.ssid_len; + return interface->group_info.ssid; +} - { SUPPLICANT_INTERFACE".Interface", "StaAuthorized", signal_station_connected }, - { SUPPLICANT_INTERFACE".Interface", "StaDeauthorized", signal_station_disconnected }, +int g_supplicant_mesh_get_disconnect_reason(GSupplicantInterface *interface) +{ + if (!interface) + return -EINVAL; - { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceFound", signal_peer_found }, - { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceLost", signal_peer_lost }, + return interface->group_info.disconnect_reason; +} - { SUPPLICANT_INTERFACE ".Peer", "PropertiesChanged", signal_peer_changed }, +const char *g_supplicant_mesh_peer_get_address(GSupplicantMeshPeer *mesh_peer) +{ + if (!mesh_peer || !mesh_peer->peer_address) + return NULL; - { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationSuccess", signal_group_success }, - { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationFailure", signal_group_failure }, - { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupStarted", signal_group_started }, - { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupFinished", signal_group_finished }, - { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationRequest", signal_group_request }, + return mesh_peer->peer_address; +} - { SUPPLICANT_INTERFACE ".Group", "PeerJoined", signal_group_peer_joined }, - { SUPPLICANT_INTERFACE ".Group", "PeerDisconnected", signal_group_peer_disconnected }, +int g_supplicant_mesh_peer_get_disconnect_reason(GSupplicantMeshPeer *mesh_peer) +{ + if (!mesh_peer) + return -EINVAL; - { } -}; + return mesh_peer->disconnect_reason; +} -static DBusHandlerResult g_supplicant_filter(DBusConnection *conn, - DBusMessage *message, void *data) +static void callback_mesh_group_started(GSupplicantInterface *interface) { - DBusMessageIter iter; - const char *path; - int i; - - path = dbus_message_get_path(message); - if (!path) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (!callbacks_pointer) + return; - if (!dbus_message_iter_init(message, &iter)) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (!callbacks_pointer->mesh_group_started) + return; - for (i = 0; signal_map[i].interface; i++) { - if (!dbus_message_has_interface(message, signal_map[i].interface)) - continue; + callbacks_pointer->mesh_group_started(interface); +} - if (!dbus_message_has_member(message, signal_map[i].member)) - continue; +static void callback_mesh_group_removed(GSupplicantInterface *interface) +{ + if (!callbacks_pointer) + return; - signal_map[i].function(path, &iter); - break; - } + if (!callbacks_pointer->mesh_group_removed) + return; - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + callbacks_pointer->mesh_group_removed(interface); } -void g_supplicant_interface_cancel(GSupplicantInterface *interface) +static void mesh_group_info(const char *key, DBusMessageIter *iter, + void *user_data) { - SUPPLICANT_DBG("Cancelling any pending DBus calls"); - supplicant_dbus_method_call_cancel_all(interface); - supplicant_dbus_property_call_cancel_all(interface); -} + GSupplicantInterface *interface = user_data; + if (!key) + return; -struct supplicant_regdom { - GSupplicantCountryCallback callback; + if (g_strcmp0(key, "SSID") == 0) { + DBusMessageIter array; + unsigned char *ssid; + int ssid_len; + + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len); + + if (ssid_len > 0 && ssid_len < 33) { + memcpy(interface->group_info.ssid, ssid, ssid_len); + interface->group_info.ssid_len = ssid_len; + } else { + memset(interface->group_info.ssid, 0, 32); + interface->group_info.ssid_len = 0; + } + } else if (g_strcmp0(key, "DisconnectReason") == 0) { + int disconnect_reason = 0; + dbus_message_iter_get_basic(iter, &disconnect_reason); + interface->group_info.disconnect_reason = disconnect_reason; + } +} + +static void signal_mesh_group_started(const char *path, DBusMessageIter *iter) +{ + GSupplicantInterface *interface; + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + + supplicant_dbus_property_foreach(iter, mesh_group_info, interface); + + callback_mesh_group_started(interface); +} + +static void signal_mesh_group_removed(const char *path, DBusMessageIter *iter) +{ + GSupplicantInterface *interface; + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + + supplicant_dbus_property_foreach(iter, mesh_group_info, interface); + + callback_mesh_group_removed(interface); +} + +static void callback_mesh_peer_connected(GSupplicantMeshPeer *mesh_peer) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->mesh_peer_connected) + return; + + callbacks_pointer->mesh_peer_connected(mesh_peer); +} + +static void callback_mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->mesh_peer_disconnected) + return; + + callbacks_pointer->mesh_peer_disconnected(mesh_peer); +} + +static void mesh_peer_info(const char *key, DBusMessageIter *iter, + void *user_data) +{ + GSupplicantMeshPeer *mesh_peer = user_data; + if (!key) + return; + + if (g_strcmp0(key, "PeerAddress") == 0) { + DBusMessageIter array; + unsigned char *addr; + int addr_len; + + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &addr, &addr_len); + + if (addr_len == 6) { + mesh_peer->peer_address = g_malloc0(19); + snprintf(mesh_peer->peer_address, 19, + "%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], + addr[2], addr[3], addr[4], addr[5]); + } + } else if (g_strcmp0(key, "DisconnectReason") == 0) { + int disconnect_reason = 0; + dbus_message_iter_get_basic(iter, &disconnect_reason); + mesh_peer->disconnect_reason = disconnect_reason; + } +} + +static void signal_mesh_peer_connected(const char *path, DBusMessageIter *iter) +{ + GSupplicantInterface *interface; + GSupplicantMeshPeer *mesh_peer; + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + + mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer)); + mesh_peer->interface = interface; + + supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer); + + callback_mesh_peer_connected(mesh_peer); + g_free(mesh_peer->peer_address); + g_free(mesh_peer); +} + +static void signal_mesh_peer_disconnected(const char *path, + DBusMessageIter *iter) +{ + GSupplicantInterface *interface; + GSupplicantMeshPeer *mesh_peer; + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + + mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer)); + mesh_peer->interface = interface; + + supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer); + + callback_mesh_peer_disconnected(mesh_peer); + g_free(mesh_peer->peer_address); + g_free(mesh_peer); +} +#endif + +static struct { + const char *interface; + const char *member; + void (*function) (const char *path, DBusMessageIter *iter); +} signal_map[] = { + { DBUS_INTERFACE_DBUS, "NameOwnerChanged", signal_name_owner_changed }, + + { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed }, + { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added }, + { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added }, + { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed }, + + { SUPPLICANT_INTERFACE ".Interface", "PropertiesChanged", signal_interface_changed }, + { SUPPLICANT_INTERFACE ".Interface", "ScanDone", signal_scan_done }, + { SUPPLICANT_INTERFACE ".Interface", "BSSAdded", signal_bss_added }, + { SUPPLICANT_INTERFACE ".Interface", "BSSRemoved", signal_bss_removed }, + { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added }, + { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed }, + + { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed }, + + { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials }, + { SUPPLICANT_INTERFACE ".Interface.WPS", "Event", signal_wps_event }, +#if defined TIZEN_EXT + { "org.tizen.system.deviced.PowerOff", "ChangeState", signal_power_off }, +#endif + + { SUPPLICANT_INTERFACE".Interface", "StaAuthorized", signal_station_connected }, + { SUPPLICANT_INTERFACE".Interface", "StaDeauthorized", signal_station_disconnected }, + + { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceFound", signal_peer_found }, + { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeviceLost", signal_peer_lost }, + + { SUPPLICANT_INTERFACE ".Peer", "PropertiesChanged", signal_peer_changed }, + + { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationSuccess", signal_group_success }, + { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationFailure", signal_group_failure }, + { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupStarted", signal_group_started }, + { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GroupFinished", signal_group_finished }, + { SUPPLICANT_INTERFACE ".Interface.P2PDevice", "GONegotiationRequest", signal_group_request }, + + { SUPPLICANT_INTERFACE ".Group", "PeerJoined", signal_group_peer_joined }, + { SUPPLICANT_INTERFACE ".Group", "PeerDisconnected", signal_group_peer_disconnected }, +#if defined TIZEN_EXT_WIFI_MESH + { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshGroupStarted", + signal_mesh_group_started }, + { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshGroupRemoved", + signal_mesh_group_removed }, + { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshPeerConnected", + signal_mesh_peer_connected }, + { SUPPLICANT_INTERFACE ".Interface.Mesh", "MeshPeerDisconnected", + signal_mesh_peer_disconnected }, +#endif + + { } +}; + +static DBusHandlerResult g_supplicant_filter(DBusConnection *conn, + DBusMessage *message, void *data) +{ + DBusMessageIter iter; + const char *path; + int i; + + path = dbus_message_get_path(message); + if (!path) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!dbus_message_iter_init(message, &iter)) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + for (i = 0; signal_map[i].interface; i++) { + if (!dbus_message_has_interface(message, signal_map[i].interface)) + continue; + + if (!dbus_message_has_member(message, signal_map[i].member)) + continue; + + signal_map[i].function(path, &iter); + break; + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +void g_supplicant_interface_cancel(GSupplicantInterface *interface) +{ + SUPPLICANT_DBG("Cancelling any pending DBus calls"); + supplicant_dbus_method_call_cancel_all(interface); + supplicant_dbus_property_call_cancel_all(interface); +} + +struct supplicant_regdom { + GSupplicantCountryCallback callback; const char *alpha2; const void *user_data; }; @@ -3681,6 +4570,7 @@ int g_supplicant_set_country(const char *alpha2, const void *user_data) { struct supplicant_regdom *regdom; + int ret; SUPPLICANT_DBG("Country setting %s", alpha2); @@ -3695,10 +4585,15 @@ int g_supplicant_set_country(const char *alpha2, regdom->alpha2 = alpha2; regdom->user_data = user_data; - return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE, + ret = supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE, "Country", DBUS_TYPE_STRING_AS_STRING, country_params, country_result, regdom, NULL); + if (ret < 0) { + dbus_free(regdom); + SUPPLICANT_DBG("Unable to set Country configuration"); + } + return ret; } int g_supplicant_interface_set_country(GSupplicantInterface *interface, @@ -3707,6 +4602,7 @@ int g_supplicant_interface_set_country(GSupplicantInterface *interface, void *user_data) { struct supplicant_regdom *regdom; + int ret; regdom = dbus_malloc0(sizeof(*regdom)); if (!regdom) @@ -3716,11 +4612,17 @@ int g_supplicant_interface_set_country(GSupplicantInterface *interface, regdom->alpha2 = alpha2; regdom->user_data = user_data; - return supplicant_dbus_property_set(interface->path, + ret = supplicant_dbus_property_set(interface->path, SUPPLICANT_INTERFACE ".Interface", "Country", DBUS_TYPE_STRING_AS_STRING, country_params, country_result, regdom, NULL); + if (ret < 0) { + dbus_free(regdom); + SUPPLICANT_DBG("Unable to set Country configuration"); + } + + return ret; } bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface) @@ -3860,48 +4762,14 @@ GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interf return peer; } -struct interface_data { - GSupplicantInterface *interface; - char *path; /* Interface path cannot be taken from interface (above) as - * it might have been freed already. - */ - GSupplicantInterfaceCallback callback; - void *user_data; -}; - -struct interface_create_data { - char *ifname; - char *driver; - char *bridge; - GSupplicantInterface *interface; - GSupplicantInterfaceCallback callback; - void *user_data; -}; - -struct interface_connect_data { - GSupplicantInterface *interface; - char *path; - GSupplicantInterfaceCallback callback; - union { - GSupplicantSSID *ssid; - GSupplicantPeerParams *peer; - }; - void *user_data; -}; - -struct interface_scan_data { - GSupplicantInterface *interface; - char *path; - GSupplicantInterfaceCallback callback; - GSupplicantScanParams *scan_params; - void *user_data; -}; - static void interface_create_data_free(struct interface_create_data *data) { g_free(data->ifname); g_free(data->driver); g_free(data->bridge); +#if defined TIZEN_EXT_WIFI_MESH + g_free(data->parent_ifname); +#endif dbus_free(data); } @@ -3929,6 +4797,9 @@ static void interface_create_property(const char *key, DBusMessageIter *iter, #if !defined TIZEN_EXT callback_p2p_support(interface); #endif +#if defined TIZEN_EXT_WIFI_MESH + callback_mesh_support(interface); +#endif } interface_create_data_free(data); @@ -3990,6 +4861,7 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data) { struct interface_create_data *data = user_data; DBusMessageIter dict; + char *config_file = NULL; SUPPLICANT_DBG(""); @@ -4006,6 +4878,25 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data) supplicant_dbus_dict_append_basic(&dict, "BridgeIfname", DBUS_TYPE_STRING, &data->bridge); + config_file = g_hash_table_lookup(config_file_table, data->ifname); + if (config_file) { + SUPPLICANT_DBG("[%s] ConfigFile %s", data->ifname, config_file); + + supplicant_dbus_dict_append_basic(&dict, "ConfigFile", + DBUS_TYPE_STRING, &config_file); + } + +#if defined TIZEN_EXT_WIFI_MESH + if (data->is_mesh_interface) { + if (data->parent_ifname) + supplicant_dbus_dict_append_basic(&dict, "ParentIfname", + DBUS_TYPE_STRING, &data->parent_ifname); + + supplicant_dbus_dict_append_basic(&dict, "IsMeshInterface", + DBUS_TYPE_BOOLEAN, &data->is_mesh_interface); + } +#endif + supplicant_dbus_dict_close(iter, &dict); } @@ -4041,6 +4932,9 @@ static void interface_get_result(const char *error, #if !defined TIZEN_EXT callback_p2p_support(interface); #endif +#if defined TIZEN_EXT_WIFI_MESH + callback_mesh_support(interface); +#endif } interface_create_data_free(data); @@ -4080,6 +4974,117 @@ static void interface_get_params(DBusMessageIter *iter, void *user_data) dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname); } +#if defined TIZEN_EXT_WIFI_MESH +int g_supplicant_mesh_interface_create(const char *ifname, const char *driver, + const char *bridge, const char *parent_ifname, + GSupplicantInterfaceCallback callback, void *user_data) +{ + struct interface_create_data *data; + int ret; + + SUPPLICANT_DBG("ifname %s", ifname); + + if (!ifname || !parent_ifname) + return -EINVAL; + + if (!system_available) + return -EFAULT; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->ifname = g_strdup(ifname); + data->driver = g_strdup(driver); + data->bridge = g_strdup(bridge); + data->is_mesh_interface = true; + data->parent_ifname = g_strdup(parent_ifname); + data->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(SUPPLICANT_PATH, + SUPPLICANT_INTERFACE, + "CreateInterface", + interface_create_params, + interface_create_result, data, + NULL); + return ret; +} + +struct interface_mesh_peer_data { + char *peer_address; + char *method; + GSupplicantInterface *interface; + GSupplicantInterfaceCallback callback; + void *user_data; +}; + +static void interface_mesh_change_peer_params(DBusMessageIter *iter, + void *user_data) +{ + struct interface_mesh_peer_data *data = user_data; + + SUPPLICANT_DBG(""); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->peer_address); +} + +static void interface_mesh_change_peer_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_mesh_peer_data *data = user_data; + int err = 0; + + SUPPLICANT_DBG("%s", data->method); + + if (error) { + err = -EIO; + SUPPLICANT_DBG("error %s", error); + } + + if (data->callback) + data->callback(err, data->interface, data->user_data); + + g_free(data->peer_address); + g_free(data->method); + dbus_free(data); +} + +int g_supplicant_interface_mesh_peer_change_status( + GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, const char *peer_address, + const char *method, void *user_data) +{ + struct interface_mesh_peer_data *data; + int ret; + + if (!peer_address) + return -EINVAL; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->peer_address = g_strdup(peer_address); + data->method = g_strdup(method); + data->interface = interface; + data->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface.Mesh", + method, interface_mesh_change_peer_params, + interface_mesh_change_peer_result, data, NULL); + if (ret < 0) { + g_free(data->peer_address); + g_free(data->method); + dbus_free(data); + } + + return ret; +} +#endif + int g_supplicant_interface_create(const char *ifname, const char *driver, const char *bridge, GSupplicantInterfaceCallback callback, @@ -4126,6 +5131,7 @@ static void interface_remove_result(const char *error, if (error) { err = -EIO; + SUPPLICANT_DBG("error: %s", error); goto done; } @@ -4386,20 +5392,162 @@ static int interface_ready_to_scan(GSupplicantInterface *interface) break; } - return 0; + return 0; +} + +#if defined TIZEN_EXT_WIFI_MESH +static void interface_abort_scan_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_scan_data *data = user_data; + int err = 0; + + if (error) { + SUPPLICANT_DBG("error %s", error); + err = -EIO; + } + + g_free(data->path); + + if (data->callback) + data->callback(err, data->interface, data->user_data); + + dbus_free(data); +} + +int g_supplicant_interface_abort_scan(GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, void *user_data) +{ + struct interface_scan_data *data; + int ret; + + if (!interface->scanning) + return -EEXIST; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->interface = interface; + data->path = g_strdup(interface->path); + data->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface", "AbortScan", NULL, + interface_abort_scan_result, data, interface); + + if (ret < 0) { + g_free(data->path); + dbus_free(data); + } + + return ret; +} +#endif + +int g_supplicant_interface_scan(GSupplicantInterface *interface, + GSupplicantScanParams *scan_data, + GSupplicantInterfaceCallback callback, + void *user_data) +{ + struct interface_scan_data *data; + int ret; + + ret = interface_ready_to_scan(interface); + if (ret) + return ret; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->interface = interface; + data->path = g_strdup(interface->path); +#if defined TIZEN_EXT + data->interface->scan_callback = data->callback = callback; + data->interface->scan_data = data->user_data = user_data; +#else + data->callback = callback; + data->user_data = user_data; +#endif + data->scan_params = scan_data; + + interface->scan_callback = callback; + interface->scan_data = user_data; + + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface", "Scan", + interface_scan_params, interface_scan_result, data, + interface); + + if (ret < 0) { + g_free(data->path); + dbus_free(data); + } + + return ret; +} + +#if defined TIZEN_EXT +static void interface_signalpoll_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_signalpoll_data *data = user_data; + int err = 0; + dbus_int32_t maxspeed = 0; + DBusMessageIter sub_iter, dict; + + if (error) { + err = -EIO; + SUPPLICANT_DBG("error: %s", error); + goto out; + } + + dbus_message_iter_get_arg_type(iter); + dbus_message_iter_recurse(iter, &sub_iter); + dbus_message_iter_recurse(&sub_iter, &dict); + + while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) { + DBusMessageIter entry, value; + const char *key; + + dbus_message_iter_recurse(&dict, &entry); + dbus_message_iter_get_basic(&entry, &key); + dbus_message_iter_next(&entry); + dbus_message_iter_recurse(&entry, &value); + + switch (dbus_message_iter_get_arg_type(&value)) { + case DBUS_TYPE_INT32: + if (g_strcmp0(key, "linkspeed") == 0) { + dbus_message_iter_get_basic(&value, &maxspeed); + SUPPLICANT_DBG("linkspeed = %d", maxspeed); + break; + } + } + dbus_message_iter_next(&dict); + } + +out: + if(data->callback) + data->callback(err, maxspeed, data->user_data); + + g_free(data->path); + dbus_free(data); } -int g_supplicant_interface_scan(GSupplicantInterface *interface, - GSupplicantScanParams *scan_data, - GSupplicantInterfaceCallback callback, - void *user_data) +int g_supplicant_interface_signalpoll(GSupplicantInterface *interface, + GSupplicantMaxSpeedCallback callback, + void *user_data) { - struct interface_scan_data *data; + struct interface_signalpoll_data *data; int ret; - ret = interface_ready_to_scan(interface); - if (ret) - return ret; + if (!interface) + return -EINVAL; + + if (!system_available) + return -EFAULT; data = dbus_malloc0(sizeof(*data)); if (!data) @@ -4407,21 +5555,12 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface, data->interface = interface; data->path = g_strdup(interface->path); -#if defined TIZEN_EXT - data->interface->scan_callback = data->callback = callback; - data->interface->scan_data = data->user_data = user_data; -#else data->callback = callback; data->user_data = user_data; -#endif - data->scan_params = scan_data; - - interface->scan_callback = callback; - interface->scan_data = user_data; ret = supplicant_dbus_method_call(interface->path, - SUPPLICANT_INTERFACE ".Interface", "Scan", - interface_scan_params, interface_scan_result, data, + SUPPLICANT_INTERFACE ".Interface", "SignalPoll", + NULL, interface_signalpoll_result, data, interface); if (ret < 0) { @@ -4431,10 +5570,11 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface, return ret; } +#endif static int parse_supplicant_error(DBusMessageIter *iter) { - int err = -ECANCELED; + int err = -ECONNABORTED; char *key; if (!iter) @@ -4481,6 +5621,10 @@ static void interface_select_network_result(const char *error, if (data->callback) data->callback(err, data->interface, data->user_data); +#if defined TIZEN_EXT + g_free(data->ssid->ssid); + g_free((char *)data->ssid->passphrase); +#endif g_free(data->ssid); dbus_free(data); } @@ -4497,7 +5641,8 @@ static void interface_select_network_params(DBusMessageIter *iter, dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &interface->network_path); #if defined TIZEN_EXT - dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &ssid->freq); + if (!ssid->bssid_for_connect_len) + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &ssid->freq); #endif } @@ -4518,19 +5663,30 @@ static void interface_add_network_result(const char *error, SUPPLICANT_DBG("PATH: %s", path); - g_free(interface->network_path); +#if defined TIZEN_EXT + if (interface->network_path) + g_free(interface->network_path); +#endif interface->network_path = g_strdup(path); + store_network_information(interface, data->ssid); + #if defined TIZEN_EXT SUPPLICANT_DBG(".Interface.SelectNetworkFreq"); -#endif + GSupplicantSSID *ssid = data->ssid; -#if defined TIZEN_EXT - supplicant_dbus_method_call(data->interface->path, - SUPPLICANT_INTERFACE ".Interface", "SelectNetworkFreq", - interface_select_network_params, - interface_select_network_result, data, - interface); + if (!ssid->bssid_for_connect_len) + supplicant_dbus_method_call(data->interface->path, + SUPPLICANT_INTERFACE ".Interface", "SelectNetworkFreq", + interface_select_network_params, + interface_select_network_result, data, + interface); + else + supplicant_dbus_method_call(data->interface->path, + SUPPLICANT_INTERFACE ".Interface", "SelectNetwork", + interface_select_network_params, + interface_select_network_result, data, + interface); #else supplicant_dbus_method_call(data->interface->path, SUPPLICANT_INTERFACE ".Interface", "SelectNetwork", @@ -4554,6 +5710,10 @@ error: } g_free(data->path); +#if defined TIZEN_EXT + g_free(data->ssid->ssid); + g_free((char *)data->ssid->passphrase); +#endif g_free(data->ssid); g_free(data); } @@ -4805,6 +5965,33 @@ static void add_network_security_aka_sim(DBusMessageIter *dict, DBUS_TYPE_STRING, &ssid->passphrase); } + +static void add_network_security_fast(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + /* + * For FAST, we at least need: + * id / password + * phase1 (provisiong information) + * pac_file + */ + + /* Allow provisioing both authenticated and unauthenticated */ + const char *phase1 = "fast_provisioning=2"; + supplicant_dbus_dict_append_basic(dict, "phase1", + DBUS_TYPE_STRING, + &phase1); + + SUPPLICANT_DBG("pac_file [%s]", ssid->pac_file); + if(ssid->pac_file) + supplicant_dbus_dict_append_basic(dict, "pac_file", + DBUS_TYPE_STRING, + &ssid->pac_file); + + supplicant_dbus_dict_append_basic(dict, "password", + DBUS_TYPE_STRING, + &ssid->passphrase); +} #endif static void add_network_security_eap(DBusMessageIter *dict, @@ -4831,8 +6018,20 @@ static void add_network_security_eap(DBusMessageIter *dict, #if defined TIZEN_EXT } else if (g_strcmp0(ssid->eap, "sim") == 0 || - g_strcmp0(ssid->eap, "aka") == 0) { + g_strcmp0(ssid->eap, "aka") == 0 || + g_strcmp0(ssid->eap, "aka'") == 0) { add_network_security_aka_sim(dict, ssid); + } else if (g_strcmp0(ssid->eap, "pwd") == 0) { + if(!ssid->passphrase) + return; + supplicant_dbus_dict_append_basic(dict, "password", + DBUS_TYPE_STRING, + &ssid->passphrase); + } else if (g_strcmp0(ssid->eap, "fast") == 0){ + if (!ssid->identity || !ssid->passphrase) + return; + + add_network_security_fast(dict, ssid); #endif } else return; @@ -4852,6 +6051,30 @@ static void add_network_security_eap(DBusMessageIter *dict, DBUS_TYPE_STRING, &ssid->identity); #endif + if(ssid->anonymous_identity) + supplicant_dbus_dict_append_basic(dict, "anonymous_identity", + DBUS_TYPE_STRING, + &ssid->anonymous_identity); + + if(ssid->subject_match) + supplicant_dbus_dict_append_basic(dict, "subject_match", + DBUS_TYPE_STRING, + &ssid->subject_match); + + if(ssid->altsubject_match) + supplicant_dbus_dict_append_basic(dict, "altsubject_match", + DBUS_TYPE_STRING, + &ssid->altsubject_match); + + if(ssid->domain_suffix_match) + supplicant_dbus_dict_append_basic(dict, "domain_suffix_match", + DBUS_TYPE_STRING, + &ssid->domain_suffix_match); + + if(ssid->domain_match) + supplicant_dbus_dict_append_basic(dict, "domain_match", + DBUS_TYPE_STRING, + &ssid->domain_match); g_free(eap_value); } @@ -4948,6 +6171,17 @@ static void add_network_security_proto(DBusMessageIter *dict, g_free(proto); } +#if defined TIZEN_EXT +static void add_network_ieee80211w(DBusMessageIter *dict, GSupplicantSSID *ssid) +{ + if (ssid->security != G_SUPPLICANT_SECURITY_SAE) + return; + + supplicant_dbus_dict_append_basic(dict, "ieee80211w", DBUS_TYPE_UINT32, + &ssid->ieee80211w); +} +#endif + static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid) { char *key_mgmt; @@ -4989,6 +6223,10 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid) add_network_security_ciphers(dict, ssid); add_network_security_proto(dict, ssid); break; + case G_SUPPLICANT_SECURITY_SAE: + key_mgmt = "SAE"; + add_network_security_psk(dict, ssid); + break; #endif } @@ -5011,6 +6249,11 @@ static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid) case G_SUPPLICANT_MODE_MASTER: mode = 2; break; +#if defined TIZEN_EXT_WIFI_MESH + case G_SUPPLICANT_MODE_MESH: + mode = 5; + break; +#endif } supplicant_dbus_dict_append_basic(dict, "mode", @@ -5041,6 +6284,10 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data) add_network_security(&dict, ssid); +#if defined TIZEN_EXT + add_network_ieee80211w(&dict, ssid); +#endif + supplicant_dbus_dict_append_fixed_array(&dict, "ssid", DBUS_TYPE_BYTE, &ssid->ssid, ssid->ssid_len); @@ -5058,9 +6305,16 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data) supplicant_dbus_dict_close(iter, &dict); return; } - snprintf(bssid, 18, "%02x:%02x:%02x:%02x:%02x:%02x", + + 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]); + 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]); + supplicant_dbus_dict_append_basic(&dict, "bssid", DBUS_TYPE_STRING, &bssid); g_free(bssid); @@ -5165,13 +6419,144 @@ static void wps_process_credentials(DBusMessageIter *iter, void *user_data) } +#if defined TIZEN_EXT +#define NETCONFIG_SERVICE "net.netconfig" +#define NETCONFIG_WIFI_PATH "/net/netconfig/wifi" +#define NETCONFIG_WIFI_INTERFACE NETCONFIG_SERVICE ".wifi" + +struct dec_method_call_data { + struct interface_connect_data *data; + DBusPendingCall *pending_call; +}; + +static struct dec_method_call_data decrypt_request_data; + +static void crypt_method_call_cancel(void) +{ + if (decrypt_request_data.pending_call) { + dbus_pending_call_cancel(decrypt_request_data.pending_call); + dbus_pending_call_unref(decrypt_request_data.pending_call); + decrypt_request_data.pending_call = NULL; + } + + g_free(decrypt_request_data.data->path); + g_free(decrypt_request_data.data->ssid); + dbus_free(decrypt_request_data.data); + decrypt_request_data.data = NULL; +} + +static void decryption_request_reply(DBusPendingCall *call, + void *user_data) +{ + DBusMessage *reply; + DBusError error; + DBusMessageIter args; + char *out_data; + int ret; + struct interface_connect_data *data = user_data; + + SUPPLICANT_DBG(""); + + reply = dbus_pending_call_steal_reply(call); + + dbus_error_init(&error); + if (dbus_set_error_from_message(&error, reply)) { + SUPPLICANT_DBG("decryption_request_reply() %s %s", error.name, error.message); + dbus_error_free(&error); + ret = -EINVAL; + goto done; + } + + if (dbus_message_iter_init(reply, &args) == FALSE) { + SUPPLICANT_DBG("dbus_message_iter_init() failed"); + ret = -EINVAL; + goto done; + } + + dbus_message_iter_get_basic(&args, &out_data); + data->ssid->passphrase = g_strdup((const gchar *)out_data); + + ret = supplicant_dbus_method_call(data->interface->path, + SUPPLICANT_INTERFACE ".Interface", "AddNetwork", + interface_add_network_params, + interface_add_network_result, data, + data->interface); + +done: + if (ret < 0) { + SUPPLICANT_DBG("AddNetwork failed %d", ret); + callback_assoc_failed(decrypt_request_data.data->user_data); + g_free(data->path); + g_free(data->ssid->ssid); + g_free((char *)data->ssid->passphrase); + g_free(data->ssid); + dbus_free(data); + } + + dbus_message_unref(reply); + dbus_pending_call_unref(call); + + decrypt_request_data.pending_call = NULL; + decrypt_request_data.data = NULL; +} + +static int send_decryption_request(const char *passphrase, + struct interface_connect_data *data) +{ + DBusMessage *msg = NULL; + DBusPendingCall *call; + + SUPPLICANT_DBG("Decryption request"); + + if (!passphrase) { + SUPPLICANT_DBG("Invalid parameter"); + return -EINVAL; + } + + if (!connection) + return -EINVAL; + + msg = dbus_message_new_method_call(NETCONFIG_SERVICE, NETCONFIG_WIFI_PATH, + NETCONFIG_WIFI_INTERFACE, "DecryptPassphrase"); + if (!msg) + return -EINVAL; + + dbus_message_append_args(msg, DBUS_TYPE_STRING, &passphrase, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send_with_reply(connection, msg, + &call, DBUS_TIMEOUT_USE_DEFAULT)) { + dbus_message_unref(msg); + return -EIO; + } + + if (!call) { + dbus_message_unref(msg); + return -EIO; + } + + decrypt_request_data.pending_call = call; + decrypt_request_data.data = data; + + dbus_pending_call_set_notify(call, decryption_request_reply, data, NULL); + dbus_message_unref(msg); + + SUPPLICANT_DBG("Decryption request succeeded"); + + return 0; +} +#endif + int g_supplicant_interface_connect(GSupplicantInterface *interface, GSupplicantSSID *ssid, GSupplicantInterfaceCallback callback, void *user_data) { struct interface_connect_data *data; - int ret; + struct interface_data *intf_data; + int ret = 0; + + SUPPLICANT_DBG(""); if (!interface) return -EINVAL; @@ -5200,12 +6585,69 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface, SUPPLICANT_INTERFACE ".Interface.WPS", "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING, wps_process_credentials, wps_start, data, interface); - } else - ret = supplicant_dbus_method_call(interface->path, - SUPPLICANT_INTERFACE ".Interface", "AddNetwork", - interface_add_network_params, - interface_add_network_result, data, - interface); + } else { + /* By the time there is a request for connect and the network + * path is not NULL it means that connman has not removed the + * previous network pointer. This can happen in the case AP + * deauthenticated client and connman does not remove the + * previously connected network pointer. This causes supplicant + * to reallocate the memory for struct wpa_ssid again even if it + * is the same SSID. This causes memory usage of wpa_supplicnat + * to go high. The idea here is that if the previously connected + * network is not removed at the time of next connection attempt + * check if the network path is not NULL. In case it is non-NULL + * first remove the network and then once removal is successful, add + * the network. + */ + + if (interface->network_path != NULL) { + g_free(data->path); + dbus_free(data); + + /* + * If this add network is for the same network for + * which wpa_supplicant already has a profile then do + * not need to add another profile. Only if the + * profile that needs to get added is different from + * what is there in wpa_s delete the current one. A + * network is identified by its SSID, security_type + * and passphrase (private passphrase in case security + * type is 802.11x). + */ + if (compare_network_parameters(interface, ssid)) { + return -EALREADY; + } + + intf_data = dbus_malloc0(sizeof(*intf_data)); + if (!intf_data) + return -ENOMEM; + + intf_data->interface = interface; + intf_data->path = g_strdup(interface->path); + intf_data->callback = callback; + intf_data->ssid = ssid; + intf_data->user_data = user_data; + intf_data->network_remove_in_progress = TRUE; + network_remove(intf_data); + } else +#if defined TIZEN_EXT + if (ssid->passphrase && + g_strcmp0(ssid->passphrase, "") != 0 && +#if defined TIZEN_EXT_WIFI_MESH + ssid->mode != G_SUPPLICANT_MODE_MESH && +#endif + !ssid->eap) { + ret = send_decryption_request(ssid->passphrase, data); + if (ret < 0) + SUPPLICANT_DBG("Decryption request failed %d", ret); + } else +#endif + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface", "AddNetwork", + interface_add_network_params, + interface_add_network_result, data, + interface); + } if (ret < 0) { g_free(data->path); @@ -5220,22 +6662,60 @@ static void network_remove_result(const char *error, DBusMessageIter *iter, void *user_data) { struct interface_data *data = user_data; + struct interface_connect_data *connect_data; int result = 0; SUPPLICANT_DBG(""); if (error) { result = -EIO; + SUPPLICANT_DBG("error: %s", error); + if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod", error) == 0) result = -ECONNABORTED; } - g_free(data->path); + g_free(data->interface->network_path); + data->interface->network_path = NULL; - if (data->callback) - data->callback(result, data->interface, data->user_data); + remove_network_information(data->interface); + if (data->network_remove_in_progress == TRUE) { + data->network_remove_in_progress = FALSE; + connect_data = dbus_malloc0(sizeof(*connect_data)); + if (!connect_data) + return; + + connect_data->interface = data->interface; + connect_data->path = g_strdup(data->path); + connect_data->callback = data->callback; + connect_data->ssid = data->ssid; + connect_data->user_data = data->user_data; + +#if defined TIZEN_EXT + int ret; + if (data->ssid->passphrase && g_strcmp0(data->ssid->passphrase, "") != 0 + && !data->ssid->eap) { + ret = send_decryption_request(data->ssid->passphrase, connect_data); + if (ret < 0) { + SUPPLICANT_DBG("Decryption request failed %d", ret); + g_free(connect_data->ssid); + g_free(connect_data->path); + dbus_free(connect_data); + } + } else +#endif + supplicant_dbus_method_call(data->interface->path, + SUPPLICANT_INTERFACE ".Interface", "AddNetwork", + interface_add_network_params, + interface_add_network_result, connect_data, + connect_data->interface); + } else { + if (data->callback) + data->callback(result, data->interface, data->user_data); + } + g_free(data->path); dbus_free(data); } @@ -5281,25 +6761,31 @@ static void interface_disconnect_result(const char *error, if (error) { result = -EIO; + SUPPLICANT_DBG("error: %s", error); + if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod", error) == 0) result = -ECONNABORTED; } - if (result < 0 && data->callback) { - data->callback(result, data->interface, data->user_data); - data->callback = NULL; - } - /* If we are disconnecting from previous WPS successful * association. i.e.: it did not went through AddNetwork, * and interface->network_path was never set. */ if (!data->interface->network_path) { + if (data->callback) + data->callback(result, data->interface, + data->user_data); + g_free(data->path); dbus_free(data); return; } + if (result < 0 && data->callback) { + data->callback(result, data->interface, data->user_data); + data->callback = NULL; + } + if (result != -ECONNABORTED) { if (network_remove(data) < 0) { g_free(data->path); @@ -5325,7 +6811,17 @@ int g_supplicant_interface_disconnect(GSupplicantInterface *interface, if (!system_available) return -EFAULT; +#if defined TIZEN_EXT + if (decrypt_request_data.pending_call && + decrypt_request_data.data && + decrypt_request_data.data->user_data == user_data) { + callback_assoc_failed(decrypt_request_data.data->user_data); + crypt_method_call_cancel(); + + return 0; + } +#endif data = dbus_malloc0(sizeof(*data)); if (!data) return -ENOMEM; @@ -5446,8 +6942,10 @@ static void interface_p2p_connect_result(const char *error, SUPPLICANT_DBG(""); - if (error) + if (error) { + SUPPLICANT_DBG("error: %s", error); err = parse_supplicant_error(iter); + } if (data->callback) data->callback(err, data->interface, data->user_data); @@ -5505,6 +7003,9 @@ int g_supplicant_interface_p2p_connect(GSupplicantInterface *interface, return -ENOTSUP; data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + data->interface = interface; data->path = g_strdup(interface->path); data->peer = peer_params; @@ -5649,6 +7150,9 @@ int g_supplicant_interface_p2p_add_service(GSupplicantInterface *interface, return -ENOTSUP; data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + data->registration = true; data->interface = interface; data->service = p2p_service_params; @@ -5679,6 +7183,9 @@ int g_supplicant_interface_p2p_del_service(GSupplicantInterface *interface, return -ENOTSUP; data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + data->interface = interface; data->service = p2p_service_params; @@ -5764,6 +7271,9 @@ int g_supplicant_set_widi_ies(GSupplicantP2PServiceParams *p2p_service_params, return -EFAULT; data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + data->service = p2p_service_params; data->callback = callback; data->user_data = user_data; @@ -5786,29 +7296,6 @@ int g_supplicant_set_widi_ies(GSupplicantP2PServiceParams *p2p_service_params, return -EINPROGRESS; } -#if defined TIZEN_EXT -int g_supplicant_interface_remove_network(GSupplicantInterface *interface) -{ - struct interface_data *data; - - SUPPLICANT_DBG(""); - - if (interface == NULL) - return -EINVAL; - - if (system_available == FALSE) - return -EFAULT; - - data = dbus_malloc0(sizeof(*data)); - if (data == NULL) - return -ENOMEM; - - data->interface = interface; - - return network_remove(data); -} -#endif - static const char *g_supplicant_rule0 = "type=signal," "path=" DBUS_PATH_DBUS "," "sender=" DBUS_SERVICE_DBUS "," @@ -5833,6 +7320,10 @@ static const char *g_supplicant_rule7 = "type=signal," static const char *g_supplicant_rule8 = "type=signal," "interface=" SUPPLICANT_INTERFACE ".Group"; #endif +#if defined TIZEN_EXT_WIFI_MESH +static const char *g_supplicant_rule9 = "type=signal," + "interface=" SUPPLICANT_INTERFACE ".Interface.Mesh"; +#endif static void invoke_introspect_method(void) { @@ -5878,6 +7369,8 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks) NULL, NULL); pending_peer_connection = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); + config_file_table = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); supplicant_dbus_setup(connection); @@ -5897,6 +7390,9 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks) dbus_bus_add_match(connection, g_supplicant_rule7, NULL); dbus_bus_add_match(connection, g_supplicant_rule8, NULL); #endif +#if defined TIZEN_EXT_WIFI_MESH + dbus_bus_add_match(connection, g_supplicant_rule9, NULL); +#endif dbus_connection_flush(connection); if (dbus_bus_name_has_owner(connection, @@ -5938,6 +7434,9 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks) SUPPLICANT_DBG(""); if (connection) { +#if defined TIZEN_EXT_WIFI_MESH + dbus_bus_remove_match(connection, g_supplicant_rule9, NULL); +#endif #if !defined TIZEN_EXT dbus_bus_remove_match(connection, g_supplicant_rule8, NULL); dbus_bus_remove_match(connection, g_supplicant_rule7, NULL); @@ -5955,6 +7454,11 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks) g_supplicant_filter, NULL); } + if (config_file_table) { + g_hash_table_destroy(config_file_table); + config_file_table = NULL; + } + if (bss_mapping) { g_hash_table_destroy(bss_mapping); bss_mapping = NULL;