X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gsupplicant%2Fsupplicant.c;h=1c0e64198b41aa51e71a2866c1fb12723d7a3dba;hb=69efc565b595bb39ebdbe635f063675ecf59278c;hp=be5e72bfeb1f74f82a302e2ed6183491e0012de1;hpb=5230672c36edeb8ac49a365a10586fb1710071c4;p=platform%2Fupstream%2Fconnman.git diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c index be5e72b..1c0e641 100644 --- a/gsupplicant/supplicant.c +++ b/gsupplicant/supplicant.c @@ -2,7 +2,7 @@ * * WPA supplicant library with GLib integration * - * Copyright (C) 2012 Intel Corporation. All rights reserved. + * Copyright (C) 2012-2013 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #include #include @@ -37,12 +40,21 @@ #include "dbus.h" #include "gsupplicant.h" -#define TIMEOUT 5000 - #define IEEE80211_CAP_ESS 0x0001 #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; static const GSupplicantCallbacks *callbacks_pointer; @@ -89,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_WIFI_MESH + { "sae", G_SUPPLICANT_KEYMGMT_SAE }, +#endif { } }; @@ -131,11 +146,19 @@ static struct strvalmap mode_capa_map[] = { { "infrastructure", G_SUPPLICANT_CAPABILITY_MODE_INFRA }, { "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 { } }; static GHashTable *interface_table; 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]; @@ -143,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; @@ -154,6 +192,9 @@ struct _GSupplicantInterface { unsigned int scan_capa; unsigned int mode_capa; 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; @@ -166,9 +207,21 @@ struct _GSupplicantInterface { struct _GSupplicantWpsCredentials wps_cred; GSupplicantWpsState wps_state; GHashTable *network_table; - GHashTable *net_mapping; + GHashTable *peer_table; + GHashTable *group_table; 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 { @@ -193,7 +246,18 @@ struct g_supplicant_bss { dbus_bool_t privacy; dbus_bool_t psk; dbus_bool_t ieee8021x; +#if defined TIZEN_EXT + dbus_bool_t ft_psk; + dbus_bool_t ft_ieee8021x; + 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_WIFI_MESH + dbus_bool_t sae; +#endif }; struct _GSupplicantNetwork { @@ -212,14 +276,117 @@ struct _GSupplicantNetwork { unsigned int wps_capabilities; GHashTable *bss_table; GHashTable *config_table; +#if defined TIZEN_EXT + bool isHS20AP; + char *eap; + char *identity; + char *phase2; + unsigned int keymgmt; + GSList *vsie_list; + unsigned char country_code[COUNTRY_CODE_LENGTH]; + GSupplicantPhy_mode phy_mode; +#endif +}; + +struct _GSupplicantPeer { + GSupplicantInterface *interface; + char *path; + unsigned char device_address[ETH_ALEN]; + unsigned char iface_address[ETH_ALEN]; + char *name; + unsigned char *widi_ies; + int widi_ies_length; + char *identifier; + unsigned int wps_capabilities; + GSList *groups; + const GSupplicantInterface *current_group_iface; + bool connection_requested; +}; + +struct _GSupplicantGroup { + GSupplicantInterface *interface; + GSupplicantInterface *orig_interface; + char *path; + int role; + 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 == NULL) + if (!callbacks_pointer || !callbacks_pointer->debug) return; va_start(ap, format); @@ -235,13 +402,17 @@ static inline void debug(const char *format, ...) static GSupplicantMode string2mode(const char *mode) { - if (mode == NULL) + if (!mode) return G_SUPPLICANT_MODE_UNKNOWN; - if (g_str_equal(mode, "infrastructure") == TRUE) + if (g_str_equal(mode, "infrastructure")) return G_SUPPLICANT_MODE_INFRA; - else if (g_str_equal(mode, "ad-hoc") == TRUE) + 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; } @@ -257,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; @@ -275,6 +450,16 @@ static const char *security2string(GSupplicantSecurity security) return "psk"; case G_SUPPLICANT_SECURITY_IEEE8021X: return "ieee8021x"; +#if defined TIZEN_EXT + case G_SUPPLICANT_SECURITY_FT_PSK: + return "ft_psk"; + case G_SUPPLICANT_SECURITY_FT_IEEE8021X: + return "ft_ieee8021x"; +#endif +#if defined TIZEN_EXT_WIFI_MESH + case G_SUPPLICANT_SECURITY_SAE: + return "sae"; +#endif } return NULL; @@ -282,46 +467,115 @@ static const char *security2string(GSupplicantSecurity security) static GSupplicantState string2state(const char *state) { - if (state == NULL) + if (!state) return G_SUPPLICANT_STATE_UNKNOWN; - if (g_str_equal(state, "unknown") == TRUE) + if (g_str_equal(state, "unknown")) return G_SUPPLICANT_STATE_UNKNOWN; - else if (g_str_equal(state, "interface_disabled") == TRUE) + else if (g_str_equal(state, "interface_disabled")) return G_SUPPLICANT_STATE_DISABLED; - else if (g_str_equal(state, "disconnected") == TRUE) + else if (g_str_equal(state, "disconnected")) return G_SUPPLICANT_STATE_DISCONNECTED; - else if (g_str_equal(state, "inactive") == TRUE) + else if (g_str_equal(state, "inactive")) return G_SUPPLICANT_STATE_INACTIVE; - else if (g_str_equal(state, "scanning") == TRUE) + else if (g_str_equal(state, "scanning")) return G_SUPPLICANT_STATE_SCANNING; - else if (g_str_equal(state, "authenticating") == TRUE) + else if (g_str_equal(state, "authenticating")) return G_SUPPLICANT_STATE_AUTHENTICATING; - else if (g_str_equal(state, "associating") == TRUE) + else if (g_str_equal(state, "associating")) return G_SUPPLICANT_STATE_ASSOCIATING; - else if (g_str_equal(state, "associated") == TRUE) + else if (g_str_equal(state, "associated")) return G_SUPPLICANT_STATE_ASSOCIATED; - else if (g_str_equal(state, "group_handshake") == TRUE) + else if (g_str_equal(state, "group_handshake")) return G_SUPPLICANT_STATE_GROUP_HANDSHAKE; - else if (g_str_equal(state, "4way_handshake") == TRUE) + else if (g_str_equal(state, "4way_handshake")) return G_SUPPLICANT_STATE_4WAY_HANDSHAKE; - else if (g_str_equal(state, "completed") == TRUE) + else if (g_str_equal(state, "completed")) return G_SUPPLICANT_STATE_COMPLETED; 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 == TRUE) + if (system_ready) return; system_ready = TRUE; - if (callbacks_pointer == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->system_ready == NULL) + if (!callbacks_pointer->system_ready) return; callbacks_pointer->system_ready(); @@ -331,10 +585,10 @@ static void callback_system_killed(void) { system_ready = FALSE; - if (callbacks_pointer == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->system_killed == NULL) + if (!callbacks_pointer->system_killed) return; callbacks_pointer->system_killed(); @@ -344,10 +598,10 @@ static void callback_interface_added(GSupplicantInterface *interface) { SUPPLICANT_DBG(""); - if (callbacks_pointer == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->interface_added == NULL) + if (!callbacks_pointer->interface_added) return; callbacks_pointer->interface_added(interface); @@ -355,10 +609,10 @@ static void callback_interface_added(GSupplicantInterface *interface) static void callback_interface_state(GSupplicantInterface *interface) { - if (callbacks_pointer == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->interface_state == NULL) + if (!callbacks_pointer->interface_state) return; callbacks_pointer->interface_state(interface); @@ -366,32 +620,77 @@ static void callback_interface_state(GSupplicantInterface *interface) static void callback_interface_removed(GSupplicantInterface *interface) { - if (callbacks_pointer == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->interface_removed == NULL) + if (!callbacks_pointer->interface_removed) return; callbacks_pointer->interface_removed(interface); } +#if !defined TIZEN_EXT +static void callback_p2p_support(GSupplicantInterface *interface) +{ + SUPPLICANT_DBG(""); + + if (!interface->p2p_support) + return; + + if (callbacks_pointer && callbacks_pointer->p2p_support) + callbacks_pointer->p2p_support(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 == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->scan_started == NULL) + if (!callbacks_pointer->scan_started) return; 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 == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->scan_finished == NULL) + if (!callbacks_pointer->scan_finished) return; callbacks_pointer->scan_finished(interface); @@ -399,10 +698,10 @@ static void callback_scan_finished(GSupplicantInterface *interface) static void callback_network_added(GSupplicantNetwork *network) { - if (callbacks_pointer == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->network_added == NULL) + if (!callbacks_pointer->network_added) return; callbacks_pointer->network_added(network); @@ -410,36 +709,157 @@ static void callback_network_added(GSupplicantNetwork *network) static void callback_network_removed(GSupplicantNetwork *network) { - if (callbacks_pointer == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->network_removed == NULL) + if (!callbacks_pointer->network_removed) return; callbacks_pointer->network_removed(network); } +#if defined TIZEN_EXT +static void callback_network_merged(GSupplicantNetwork *network) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->network_merged) + return; + + 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, const char *property) { - if (callbacks_pointer == NULL) + if (!callbacks_pointer) return; - if (callbacks_pointer->network_changed == NULL) + if (!callbacks_pointer->network_changed) return; 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) + return; + + if (!callbacks_pointer->peer_found) + return; + + callbacks_pointer->peer_found(peer); +} + +static void callback_peer_lost(GSupplicantPeer *peer) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->peer_lost) + return; + + callbacks_pointer->peer_lost(peer); +} + +static void callback_peer_changed(GSupplicantPeer *peer, + GSupplicantPeerState state) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->peer_changed) + return; + + callbacks_pointer->peer_changed(peer, state); +} + +static void callback_peer_request(GSupplicantPeer *peer) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->peer_request) + return; + + peer->connection_requested = true; + + callbacks_pointer->peer_request(peer); +} + +static void callback_disconnect_reason_code(GSupplicantInterface *interface, + int reason_code) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->disconnect_reasoncode) + return; + + if (reason_code != 0) + callbacks_pointer->disconnect_reasoncode(interface, + reason_code); +} + +static void callback_assoc_status_code(GSupplicantInterface *interface, + int status_code) +{ + if (!callbacks_pointer) + return; + + if (!callbacks_pointer->assoc_status_code) + return; + + callbacks_pointer->assoc_status_code(interface, status_code); + +} + +static void remove_group(gpointer data) +{ + GSupplicantGroup *group = data; + + if (group->members) + g_slist_free_full(group->members, g_free); + + g_free(group->path); + g_free(group); +} + 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); - if (interface->scan_callback != NULL) { + if (interface->scan_callback) { SUPPLICANT_DBG("call interface %p callback %p scanning %d", interface, interface->scan_callback, interface->scanning); @@ -448,7 +868,7 @@ static void remove_interface(gpointer data) interface->scan_callback = NULL; interface->scan_data = NULL; - if (interface->scanning == TRUE) { + if (interface->scanning) { interface->scanning = FALSE; callback_scan_finished(interface); } @@ -459,9 +879,13 @@ static void remove_interface(gpointer data) g_free(interface->wps_cred.key); g_free(interface->path); g_free(interface->network_path); +#if defined TIZEN_EXT + interface->network_path = NULL; +#endif g_free(interface->ifname); g_free(interface->driver); g_free(interface->bridge); + remove_network_information(interface); g_free(interface); } @@ -478,6 +902,15 @@ static void remove_network(gpointer data) g_free(network->path); g_free(network->group); g_free(network->name); +#if defined TIZEN_EXT + g_free(network->eap); + g_free(network->identity); + g_free(network->phase2); +#endif +#if defined TIZEN_EXT + g_slist_free_full(network->vsie_list, g_free); +#endif + g_free(network); } @@ -486,15 +919,41 @@ static void remove_bss(gpointer data) struct g_supplicant_bss *bss = data; g_free(bss->path); +#if defined TIZEN_EXT + g_slist_free_full(bss->vsie_list, g_free); +#endif g_free(bss); } +static void remove_peer(gpointer data) +{ + GSupplicantPeer *peer = data; + + callback_peer_lost(peer); + + if (peer->groups) + g_slist_free_full(peer->groups, g_free); + + if (peer_mapping) + g_hash_table_remove(peer_mapping, peer->path); + + if (pending_peer_connection) + g_hash_table_remove(pending_peer_connection, peer->path); + + g_free(peer->path); + g_free(peer->name); + g_free(peer->identifier); + g_free(peer->widi_ies); + + g_free(peer); +} + static void debug_strvalmap(const char *label, struct strvalmap *map, unsigned int val) { int i; - for (i = 0; map[i].str != NULL; i++) { + for (i = 0; map[i].str; i++) { if (val & map[i].val) SUPPLICANT_DBG("%s: %s", label, map[i].str); } @@ -507,10 +966,10 @@ static void interface_capability_keymgmt(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; keymgmt_map[i].str != NULL; i++) + for (i = 0; keymgmt_map[i].str; i++) if (strcmp(str, keymgmt_map[i].str) == 0) { interface->keymgmt_capa |= keymgmt_map[i].val; break; @@ -524,10 +983,10 @@ static void interface_capability_authalg(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; authalg_capa_map[i].str != NULL; i++) + for (i = 0; authalg_capa_map[i].str; i++) if (strcmp(str, authalg_capa_map[i].str) == 0) { interface->authalg_capa |= authalg_capa_map[i].val; break; @@ -541,10 +1000,10 @@ static void interface_capability_proto(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; proto_capa_map[i].str != NULL; i++) + for (i = 0; proto_capa_map[i].str; i++) if (strcmp(str, proto_capa_map[i].str) == 0) { interface->proto_capa |= proto_capa_map[i].val; break; @@ -559,10 +1018,10 @@ static void interface_capability_pairwise(DBusMessageIter *iter, int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; pairwise_map[i].str != NULL; i++) + for (i = 0; pairwise_map[i].str; i++) if (strcmp(str, pairwise_map[i].str) == 0) { interface->pairwise_capa |= pairwise_map[i].val; break; @@ -576,10 +1035,10 @@ static void interface_capability_group(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; group_map[i].str != NULL; i++) + for (i = 0; group_map[i].str; i++) if (strcmp(str, group_map[i].str) == 0) { interface->group_capa |= group_map[i].val; break; @@ -593,10 +1052,10 @@ static void interface_capability_scan(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; scan_capa_map[i].str != NULL; i++) + for (i = 0; scan_capa_map[i].str; i++) if (strcmp(str, scan_capa_map[i].str) == 0) { interface->scan_capa |= scan_capa_map[i].val; break; @@ -610,10 +1069,10 @@ static void interface_capability_mode(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; mode_capa_map[i].str != NULL; i++) + for (i = 0; mode_capa_map[i].str; i++) if (strcmp(str, mode_capa_map[i].str) == 0) { interface->mode_capa |= mode_capa_map[i].val; break; @@ -625,7 +1084,7 @@ static void interface_capability(const char *key, DBusMessageIter *iter, { GSupplicantInterface *interface = user_data; - if (key == NULL) + if (!key) return; if (g_strcmp0(key, "KeyMgmt") == 0) @@ -656,40 +1115,88 @@ 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); } -int g_supplicant_interface_set_apscan(GSupplicantInterface *interface, - unsigned int ap_scan) +static void set_apscan_complete(const char *error, + DBusMessageIter *iter, void *user_data) { - return supplicant_dbus_property_set(interface->path, - SUPPLICANT_INTERFACE ".Interface", - "ApScan", DBUS_TYPE_UINT32_AS_STRING, - set_apscan, NULL, &ap_scan); + 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); } -void g_supplicant_interface_set_data(GSupplicantInterface *interface, - void *data) +int g_supplicant_interface_set_apscan(GSupplicantInterface *interface, + unsigned int ap_scan) { - if (interface == NULL) + 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, set_apscan_complete, data, NULL); + if (ret < 0) + dbus_free(data); + + return ret; +} + +void g_supplicant_interface_set_data(GSupplicantInterface *interface, + void *data) +{ + if (!interface) return; interface->data = data; + + if (!data) + interface->scan_callback = NULL; } void *g_supplicant_interface_get_data(GSupplicantInterface *interface) { - if (interface == NULL) + if (!interface) return NULL; return interface->data; @@ -697,15 +1204,25 @@ void *g_supplicant_interface_get_data(GSupplicantInterface *interface) const char *g_supplicant_interface_get_ifname(GSupplicantInterface *interface) { - if (interface == NULL) + if (!interface) return NULL; 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 == NULL) + if (!interface) return NULL; return interface->driver; @@ -714,7 +1231,7 @@ const char *g_supplicant_interface_get_driver(GSupplicantInterface *interface) GSupplicantState g_supplicant_interface_get_state( GSupplicantInterface *interface) { - if (interface == NULL) + if (!interface) return G_SUPPLICANT_STATE_UNKNOWN; return interface->state; @@ -722,7 +1239,7 @@ GSupplicantState g_supplicant_interface_get_state( const char *g_supplicant_interface_get_wps_key(GSupplicantInterface *interface) { - if (interface == NULL) + if (!interface) return NULL; return (const char *)interface->wps_cred.key; @@ -731,10 +1248,10 @@ const char *g_supplicant_interface_get_wps_key(GSupplicantInterface *interface) const void *g_supplicant_interface_get_wps_ssid(GSupplicantInterface *interface, unsigned int *ssid_len) { - if (ssid_len == NULL) + if (!ssid_len) return NULL; - if (interface == NULL || interface->wps_cred.ssid == NULL) { + if (!interface || interface->wps_cred.ssid_len == 0) { *ssid_len = 0; return NULL; } @@ -746,7 +1263,7 @@ const void *g_supplicant_interface_get_wps_ssid(GSupplicantInterface *interface, GSupplicantWpsState g_supplicant_interface_get_wps_state( GSupplicantInterface *interface) { - if (interface == NULL) + if (!interface) return G_SUPPLICANT_WPS_STATE_UNKNOWN; return interface->wps_state; @@ -754,7 +1271,7 @@ GSupplicantWpsState g_supplicant_interface_get_wps_state( unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface) { - if (interface == NULL) + if (!interface) return 0; return interface->mode_capa; @@ -763,9 +1280,12 @@ unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface) unsigned int g_supplicant_interface_get_max_scan_ssids( GSupplicantInterface *interface) { - if (interface == NULL) + if (!interface) return 0; + if (interface->max_scan_ssids == 0) + return WPAS_MAX_SCAN_SSIDS; + return interface->max_scan_ssids; } @@ -779,22 +1299,22 @@ static void set_network_enabled(DBusMessageIter *iter, void *user_data) int g_supplicant_interface_enable_selected_network(GSupplicantInterface *interface, dbus_bool_t enable) { - if (interface == NULL) + if (!interface) return -1; - if (interface->network_path == NULL) + if (!interface->network_path) return -1; SUPPLICANT_DBG(" "); return supplicant_dbus_property_set(interface->network_path, SUPPLICANT_INTERFACE ".Network", "Enabled", DBUS_TYPE_BOOLEAN_AS_STRING, - set_network_enabled, NULL, &enable); + set_network_enabled, NULL, &enable, NULL); } dbus_bool_t g_supplicant_interface_get_ready(GSupplicantInterface *interface) { - if (interface == NULL) + if (!interface) return FALSE; return interface->ready; @@ -803,7 +1323,7 @@ dbus_bool_t g_supplicant_interface_get_ready(GSupplicantInterface *interface) GSupplicantInterface *g_supplicant_network_get_interface( GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return NULL; return network->interface; @@ -811,7 +1331,7 @@ GSupplicantInterface *g_supplicant_network_get_interface( const char *g_supplicant_network_get_name(GSupplicantNetwork *network) { - if (network == NULL || network->name == NULL) + if (!network || !network->name) return ""; return network->name; @@ -819,7 +1339,7 @@ const char *g_supplicant_network_get_name(GSupplicantNetwork *network) const char *g_supplicant_network_get_identifier(GSupplicantNetwork *network) { - if (network == NULL || network->group == NULL) + if (!network || !network->group) return ""; return network->group; @@ -827,7 +1347,7 @@ const char *g_supplicant_network_get_identifier(GSupplicantNetwork *network) const char *g_supplicant_network_get_path(GSupplicantNetwork *network) { - if (network == NULL || network->path == NULL) + if (!network || !network->path) return NULL; return network->path; @@ -835,7 +1355,7 @@ const char *g_supplicant_network_get_path(GSupplicantNetwork *network) const char *g_supplicant_network_get_mode(GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return G_SUPPLICANT_MODE_UNKNOWN; return mode2string(network->mode); @@ -843,7 +1363,7 @@ const char *g_supplicant_network_get_mode(GSupplicantNetwork *network) const char *g_supplicant_network_get_security(GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return G_SUPPLICANT_SECURITY_UNKNOWN; return security2string(network->security); @@ -852,7 +1372,7 @@ const char *g_supplicant_network_get_security(GSupplicantNetwork *network) const void *g_supplicant_network_get_ssid(GSupplicantNetwork *network, unsigned int *ssid_len) { - if (network == NULL || network->ssid == NULL) { + if (!network) { *ssid_len = 0; return NULL; } @@ -863,7 +1383,7 @@ const void *g_supplicant_network_get_ssid(GSupplicantNetwork *network, dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return 0; return network->signal; @@ -871,7 +1391,7 @@ dbus_int16_t g_supplicant_network_get_signal(GSupplicantNetwork *network) dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return 0; return network->frequency; @@ -879,7 +1399,7 @@ dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network) dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return FALSE; return network->wps; @@ -887,7 +1407,7 @@ dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network) dbus_bool_t g_supplicant_network_is_wps_active(GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return FALSE; if (network->wps_capabilities & G_SUPPLICANT_WPS_CONFIGURED) @@ -898,7 +1418,7 @@ dbus_bool_t g_supplicant_network_is_wps_active(GSupplicantNetwork *network) dbus_bool_t g_supplicant_network_is_wps_pbc(GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return FALSE; if (network->wps_capabilities & G_SUPPLICANT_WPS_PBC) @@ -909,7 +1429,7 @@ dbus_bool_t g_supplicant_network_is_wps_pbc(GSupplicantNetwork *network) dbus_bool_t g_supplicant_network_is_wps_advertizing(GSupplicantNetwork *network) { - if (network == NULL) + if (!network) return FALSE; if (network->wps_capabilities & G_SUPPLICANT_WPS_REGISTRAR) @@ -918,43 +1438,410 @@ 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) + return NULL; + + return peer->interface; +} + +const char *g_supplicant_peer_get_path(GSupplicantPeer *peer) +{ + if (!peer) + return NULL; + + return peer->path; +} + +const char *g_supplicant_peer_get_identifier(GSupplicantPeer *peer) +{ + if (!peer) + return NULL; + + return peer->identifier; +} + +const void *g_supplicant_peer_get_device_address(GSupplicantPeer *peer) +{ + if (!peer) + return NULL; + + return peer->device_address; +} + +const void *g_supplicant_peer_get_iface_address(GSupplicantPeer *peer) +{ + if (!peer) + return NULL; + + return peer->iface_address; +} + +const char *g_supplicant_peer_get_name(GSupplicantPeer *peer) +{ + if (!peer) + return NULL; + + return peer->name; +} + +#if defined TIZEN_EXT +bool g_supplicant_network_is_hs20AP(GSupplicantNetwork *network) +{ + if (!network) + return 0; + + return network->isHS20AP; +} + +const char *g_supplicant_network_get_eap(GSupplicantNetwork *network) +{ + if (!network || !network->eap) + return NULL; + + return network->eap; +} + +const char *g_supplicant_network_get_identity(GSupplicantNetwork *network) +{ + if (!network || !network->identity) + return NULL; + + return network->identity; +} + +const char *g_supplicant_network_get_phase2(GSupplicantNetwork *network) +{ + if (!network || !network->phase2) + return NULL; + + return network->phase2; +} + +unsigned int g_supplicant_network_get_keymgmt(GSupplicantNetwork *network) +{ + if (network == NULL) + return 0; + + 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, + int *length) +{ + if (!peer || !length) + return NULL; + + *length = peer->widi_ies_length; + return peer->widi_ies; +} + +bool g_supplicant_peer_is_wps_pbc(GSupplicantPeer *peer) +{ + if (!peer) + return false; + + if (peer->wps_capabilities & G_SUPPLICANT_WPS_PBC) + return true; + + return false; +} + +bool g_supplicant_peer_is_wps_pin(GSupplicantPeer *peer) +{ + if (!peer) + return false; + + if (peer->wps_capabilities & G_SUPPLICANT_WPS_PIN) + return true; + + return false; +} + +bool g_supplicant_peer_is_in_a_group(GSupplicantPeer *peer) +{ + if (!peer || !peer->groups) + return false; + + return true; +} + +GSupplicantInterface *g_supplicant_peer_get_group_interface(GSupplicantPeer *peer) +{ + if (!peer) + return NULL; + + return (GSupplicantInterface *) peer->current_group_iface; +} + +bool g_supplicant_peer_is_client(GSupplicantPeer *peer) +{ + GSupplicantGroup *group; + GSList *list; + + if (!peer) + return false; + + for (list = peer->groups; list; list = list->next) { + const char *path = list->data; + + group = g_hash_table_lookup(group_mapping, path); + if (!group) + continue; + + if (group->role != G_SUPPLICANT_GROUP_ROLE_CLIENT || + group->orig_interface != peer->interface) + continue; + + if (group->interface == peer->current_group_iface) + return true; + } + + return false; +} + +bool g_supplicant_peer_has_requested_connection(GSupplicantPeer *peer) +{ + if (!peer) + return false; + + return peer->connection_requested; +} + +#if defined TIZEN_EXT +/* + * Description: Network client requires additional wifi specific info + */ +const unsigned char *g_supplicant_network_get_bssid(GSupplicantNetwork *network) +{ + if (network == NULL || network->best_bss == NULL) + return NULL; + + return (const unsigned char *)network->best_bss->bssid; +} + +unsigned int g_supplicant_network_get_maxrate(GSupplicantNetwork *network) +{ + if (network == NULL || network->best_bss == NULL) + return 0; + + return network->best_bss->maxrate; +} + +const char *g_supplicant_network_get_enc_mode(GSupplicantNetwork *network) +{ + if (network == NULL || network->best_bss == NULL) + return NULL; + + if (network->best_bss->security == G_SUPPLICANT_SECURITY_PSK || + network->best_bss->security == G_SUPPLICANT_SECURITY_IEEE8021X) { + unsigned int pairwise; + + pairwise = network->best_bss->rsn_pairwise | + network->best_bss->wpa_pairwise; + + if ((pairwise & G_SUPPLICANT_PAIRWISE_CCMP) && + (pairwise & G_SUPPLICANT_PAIRWISE_TKIP)) + return "mixed"; + else if (pairwise & G_SUPPLICANT_PAIRWISE_CCMP) + return "aes"; + else if (pairwise & G_SUPPLICANT_PAIRWISE_TKIP) + return "tkip"; + + } else if (network->best_bss->security == G_SUPPLICANT_SECURITY_WEP) + return "wep"; + else if (network->best_bss->security == G_SUPPLICANT_SECURITY_NONE) + return "none"; + + return NULL; +} + +bool g_supplicant_network_get_rsn_mode(GSupplicantNetwork *network) +{ + if (network == NULL || network->best_bss == NULL) + return 0; + + if (network->best_bss->rsn_selected) { + const char *mode = g_supplicant_network_get_enc_mode(network); + if (g_strcmp0(mode, "aes") == 0 || + g_strcmp0(mode, "mixed") == 0) + return true; + else + return false; + } else + return false; +} + +void *g_supplicant_network_get_wifi_vsie(GSupplicantNetwork *network) +{ + 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 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"); +} + +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); + + return bssid_list; +} +#endif + static void merge_network(GSupplicantNetwork *network) { GString *str; const char *ssid, *mode, *key_mgmt; +#if defined TIZEN_EXT + const char *isHS20AP; + const char *eap, *identity, *phase2; +#endif unsigned int i, ssid_len; char *group; ssid = g_hash_table_lookup(network->config_table, "ssid"); mode = g_hash_table_lookup(network->config_table, "mode"); key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt"); +#if defined TIZEN_EXT + isHS20AP = g_hash_table_lookup(network->config_table, "isHS20AP"); + 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"); +#endif SUPPLICANT_DBG("ssid %s mode %s", ssid, mode); - if (ssid != NULL) + if (ssid) ssid_len = strlen(ssid); else ssid_len = 0; str = g_string_sized_new((ssid_len * 2) + 24); - if (str == NULL) + if (!str) return; for (i = 0; i < ssid_len; i++) +#if defined TIZEN_EXT + { + if (ssid[i] != '"') +#endif g_string_append_printf(str, "%02x", ssid[i]); +#if defined TIZEN_EXT + } +#endif if (g_strcmp0(mode, "0") == 0) 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"); +#if defined TIZEN_EXT + else if (g_strcmp0(key_mgmt, "WPA-EAP") == 0) + g_string_append_printf(str, "_ieee8021x"); + else + g_string_append_printf(str, "_none"); +#endif group = g_string_free(str, FALSE); SUPPLICANT_DBG("%s", group); +#if defined TIZEN_EXT + if (g_strcmp0(isHS20AP, "1") == 0) { + network->isHS20AP = 1; + if (network->eap) + g_free(network->eap); + network->eap = g_strdup(eap); + + if (network->identity) + g_free(network->identity); + network->identity = g_strdup(identity); + + if (network->phase2) + g_free(network->phase2); + network->phase2 = g_strdup(phase2); + } else + network->isHS20AP = 0; + + network->group = g_strdup(group); + callback_network_merged(network); + g_free(network->group); +#endif + g_free(group); g_hash_table_destroy(network->config_table); @@ -968,10 +1855,10 @@ static void network_property(const char *key, DBusMessageIter *iter, { GSupplicantNetwork *network = user_data; - if (network->interface == NULL) + if (!network->interface) return; - if (key == NULL) { + if (!key) { merge_network(network); return; } @@ -984,7 +1871,7 @@ static void network_property(const char *key, DBusMessageIter *iter, const char *str = NULL; dbus_message_iter_get_basic(iter, &str); - if (str != NULL) { + if (str) { g_hash_table_replace(network->config_table, g_strdup(key), g_strdup(str)); } @@ -1002,18 +1889,14 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data) SUPPLICANT_DBG(""); dbus_message_iter_get_basic(iter, &path); - if (path == NULL) + if (!path) return; if (g_strcmp0(path, "/") == 0) return; - network = g_hash_table_lookup(interface->net_mapping, path); - if (network != NULL) - return; - network = g_try_new0(GSupplicantNetwork, 1); - if (network == NULL) + if (!network) return; network->interface = interface; @@ -1032,24 +1915,13 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data) supplicant_dbus_property_get_all(path, SUPPLICANT_INTERFACE ".Network", - network_property, network); + network_property, network, NULL); } 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 == NULL) - return; - - network = g_hash_table_lookup(interface->net_mapping, path); - if (network == NULL) - return; - - g_hash_table_remove(interface->net_mapping, path); + SUPPLICANT_DBG(""); + return; } static char *create_name(unsigned char *ssid, int ssid_len) @@ -1067,13 +1939,13 @@ static char *create_name(unsigned char *ssid, int ssid_len) while (remaining_bytes != 0) { if (g_utf8_validate(remainder, remaining_bytes, - &invalid) == TRUE) { + &invalid)) { break; } valid_bytes = invalid - remainder; - if (string == NULL) + if (!string) string = g_string_sized_new(remaining_bytes); g_string_append_len(string, remainder, valid_bytes); @@ -1085,7 +1957,7 @@ static char *create_name(unsigned char *ssid, int ssid_len) remainder = invalid + 1; } - if (string == NULL) + if (!string) return g_strndup((const gchar *)ssid, ssid_len + 1); g_string_append(string, remainder); @@ -1100,7 +1972,7 @@ static char *create_group(struct g_supplicant_bss *bss) const char *mode, *security; str = g_string_sized_new((bss->ssid_len * 2) + 24); - if (str == NULL) + if (!str) return NULL; if (bss->ssid_len > 0 && bss->ssid[0] != '\0') { @@ -1110,17 +1982,17 @@ static char *create_group(struct g_supplicant_bss *bss) g_string_append_printf(str, "hidden"); mode = mode2string(bss->mode); - if (mode != NULL) + if (mode) g_string_append_printf(str, "_%s", mode); security = security2string(bss->security); - if (security != NULL) + if (security) g_string_append_printf(str, "_%s", security); 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; @@ -1129,11 +2001,11 @@ static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss) group = create_group(bss); SUPPLICANT_DBG("New group created: %s", group); - if (group == NULL) - return; + if (!group) + return -ENOMEM; network = g_hash_table_lookup(interface->network_table, group); - if (network != NULL) { + if (network) { g_free(group); SUPPLICANT_DBG("Network %s already exist", network->name); @@ -1141,13 +2013,13 @@ static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss) } network = g_try_new0(GSupplicantNetwork, 1); - if (network == NULL) { + if (!network) { g_free(group); - return; + return -ENOMEM; } network->interface = interface; - if (network->path == NULL) + if (!network->path) network->path = g_strdup(bss->path); network->group = group; network->name = create_name(bss->ssid, bss->ssid_len); @@ -1159,6 +2031,29 @@ static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss) network->frequency = bss->frequency; network->best_bss = bss; +#if defined TIZEN_EXT + network->keymgmt = bss->keymgmt; + + 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); network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal, @@ -1179,7 +2074,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"); @@ -1189,7 +2089,9 @@ 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) { @@ -1211,10 +2113,10 @@ static void bss_keymgmt(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; keymgmt_map[i].str != NULL; i++) + for (i = 0; keymgmt_map[i].str; i++) if (strcmp(str, keymgmt_map[i].str) == 0) { SUPPLICANT_DBG("Keymgmt: %s", str); *keymgmt |= keymgmt_map[i].val; @@ -1229,10 +2131,10 @@ static void bss_group(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; group_map[i].str != NULL; i++) + for (i = 0; group_map[i].str; i++) if (strcmp(str, group_map[i].str) == 0) { SUPPLICANT_DBG("Group: %s", str); *group |= group_map[i].val; @@ -1247,10 +2149,10 @@ static void bss_pairwise(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; pairwise_map[i].str != NULL; i++) + for (i = 0; pairwise_map[i].str; i++) if (strcmp(str, pairwise_map[i].str) == 0) { SUPPLICANT_DBG("Pairwise: %s", str); *pairwise |= pairwise_map[i].val; @@ -1269,21 +2171,21 @@ static void bss_wpa(const char *key, DBusMessageIter *iter, if (g_strcmp0(key, "KeyMgmt") == 0) { supplicant_dbus_array_foreach(iter, bss_keymgmt, &value); - if (bss->rsn_selected == TRUE) + if (bss->rsn_selected) bss->rsn_keymgmt = value; else bss->wpa_keymgmt = value; } else if (g_strcmp0(key, "Group") == 0) { supplicant_dbus_array_foreach(iter, bss_group, &value); - if (bss->rsn_selected == TRUE) + if (bss->rsn_selected) bss->rsn_group = value; else bss->wpa_group = value; } else if (g_strcmp0(key, "Pairwise") == 0) { supplicant_dbus_array_foreach(iter, bss_pairwise, &value); - if (bss->rsn_selected == TRUE) + if (bss->rsn_selected) bss->rsn_pairwise = value; else bss->wpa_pairwise = value; @@ -1332,6 +2234,50 @@ 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; @@ -1340,6 +2286,15 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) 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 @@ -1351,19 +2306,86 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data) #define WPS_PBC 0x04 #define WPS_PIN 0x00 #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); dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); - if (ie == NULL || ie_len < 2) + if (!ie || ie_len < 2) return; 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 + 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 || memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0) continue; @@ -1398,6 +2420,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) @@ -1409,24 +2438,61 @@ static void bss_compute_security(struct g_supplicant_bss *bss) bss->ieee8021x = FALSE; bss->psk = FALSE; +#if defined TIZEN_EXT + bss->ft_ieee8021x = FALSE; + bss->ft_psk = FALSE; +#endif +#if defined TIZEN_EXT + if (bss->keymgmt & + (G_SUPPLICANT_KEYMGMT_WPA_EAP | + G_SUPPLICANT_KEYMGMT_WPA_EAP_256)) + bss->ieee8021x = TRUE; + else if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_EAP) + bss->ft_ieee8021x = TRUE; +#else if (bss->keymgmt & (G_SUPPLICANT_KEYMGMT_WPA_EAP | G_SUPPLICANT_KEYMGMT_WPA_FT_EAP | G_SUPPLICANT_KEYMGMT_WPA_EAP_256)) bss->ieee8021x = TRUE; +#endif +#if defined TIZEN_EXT + if (bss->keymgmt & + (G_SUPPLICANT_KEYMGMT_WPA_PSK | + G_SUPPLICANT_KEYMGMT_WPA_PSK_256)) + bss->psk = TRUE; + else if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPA_FT_PSK) + bss->ft_psk = TRUE; +#else if (bss->keymgmt & (G_SUPPLICANT_KEYMGMT_WPA_PSK | G_SUPPLICANT_KEYMGMT_WPA_FT_PSK | G_SUPPLICANT_KEYMGMT_WPA_PSK_256)) bss->psk = TRUE; +#endif + +#if defined TIZEN_EXT_WIFI_MESH + if (bss->keymgmt & G_SUPPLICANT_KEYMGMT_SAE) + bss->sae = TRUE; +#endif - if (bss->ieee8021x == TRUE) + if (bss->ieee8021x) bss->security = G_SUPPLICANT_SECURITY_IEEE8021X; - else if (bss->psk == TRUE) + else if (bss->psk) bss->security = G_SUPPLICANT_SECURITY_PSK; - else if (bss->privacy == TRUE) +#if defined TIZEN_EXT + else if (bss->ft_psk) + bss->security = G_SUPPLICANT_SECURITY_FT_PSK; + else if (bss->ft_ieee8021x == TRUE) + bss->security = G_SUPPLICANT_SECURITY_IEEE8021X; +#endif +#if defined TIZEN_EXT_WIFI_MESH + else if (bss->sae) + bss->security = G_SUPPLICANT_SECURITY_SAE; +#endif + else if (bss->privacy) bss->security = G_SUPPLICANT_SECURITY_WEP; else bss->security = G_SUPPLICANT_SECURITY_NONE; @@ -1438,12 +2504,12 @@ static void bss_property(const char *key, DBusMessageIter *iter, { struct g_supplicant_bss *bss = user_data; - if (bss->interface == NULL) + if (!bss->interface) return; SUPPLICANT_DBG("key %s", key); - if (key == NULL) + if (!key) return; if (g_strcmp0(key, "BSSID") == 0) { @@ -1499,6 +2565,9 @@ static void bss_property(const char *key, DBusMessageIter *iter, dbus_message_iter_get_basic(iter, &signal); bss->signal = signal; + if (!bss->signal) + bss->signal = BSS_UNKNOWN_STRENGTH; + } else if (g_strcmp0(key, "Level") == 0) { dbus_int32_t level = 0; @@ -1524,6 +2593,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 @@ -1542,7 +2617,7 @@ static struct g_supplicant_bss *interface_bss_added(DBusMessageIter *iter, SUPPLICANT_DBG(""); dbus_message_iter_get_basic(iter, &path); - if (path == NULL) + if (!path) return NULL; if (g_strcmp0(path, "/") == 0) @@ -1551,18 +2626,19 @@ static struct g_supplicant_bss *interface_bss_added(DBusMessageIter *iter, SUPPLICANT_DBG("%s", path); network = g_hash_table_lookup(interface->bss_mapping, path); - if (network != NULL) { + if (network) { bss = g_hash_table_lookup(network->bss_table, path); - if (bss != NULL) + if (bss) return NULL; } bss = g_try_new0(struct g_supplicant_bss, 1); - if (bss == NULL) + if (!bss) return NULL; bss->interface = interface; bss->path = g_strdup(path); + bss->signal = BSS_UNKNOWN_STRENGTH; return bss; } @@ -1575,7 +2651,7 @@ static void interface_bss_added_with_keys(DBusMessageIter *iter, SUPPLICANT_DBG(""); bss = interface_bss_added(iter, user_data); - if (bss == NULL) + if (!bss) return; dbus_message_iter_next(iter); @@ -1586,7 +2662,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, @@ -1597,15 +2674,16 @@ static void interface_bss_added_without_keys(DBusMessageIter *iter, SUPPLICANT_DBG(""); bss = interface_bss_added(iter, user_data); - if (bss == NULL) + if (!bss) return; supplicant_dbus_property_get_all(bss->path, SUPPLICANT_INTERFACE ".BSS", - bss_property, bss); + 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, @@ -1622,7 +2700,7 @@ static void update_signal(gpointer key, gpointer value, static void update_network_signal(GSupplicantNetwork *network) { - if (g_hash_table_size(network->bss_table) <= 1) + if (g_hash_table_size(network->bss_table) <= 1 && network->best_bss) return; g_hash_table_foreach(network->bss_table, @@ -1631,20 +2709,98 @@ 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 == NULL) + if (!path) return; network = g_hash_table_lookup(interface->bss_mapping, path); - if (network == NULL) + if (!network) return; + bss = g_hash_table_lookup(network->bss_table, path); + 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); g_hash_table_remove(interface->bss_mapping, path); @@ -1652,8 +2808,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) +{ + 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); + } + } static void interface_property(const char *key, DBusMessageIter *iter, @@ -1661,12 +2860,12 @@ static void interface_property(const char *key, DBusMessageIter *iter, { GSupplicantInterface *interface = user_data; - if (interface == NULL) + if (!interface) return; SUPPLICANT_DBG("%s", key); - if (key == NULL) { + if (!key) { debug_strvalmap("KeyMgmt capability", keymgmt_map, interface->keymgmt_capa); debug_strvalmap("AuthAlg capability", authalg_capa_map, @@ -1682,22 +2881,44 @@ static void interface_property(const char *key, DBusMessageIter *iter, debug_strvalmap("Mode capability", mode_capa_map, interface->mode_capa); - callback_interface_added(interface); + supplicant_dbus_property_get_all(interface->path, + SUPPLICANT_INTERFACE ".Interface.WPS", + wps_property, interface, interface); + + if (interface->ready) + callback_interface_added(interface); + return; } if (g_strcmp0(key, "Capabilities") == 0) { supplicant_dbus_property_foreach(iter, interface_capability, interface); +#if !defined TIZEN_EXT + 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; dbus_message_iter_get_basic(iter, &str); - if (str != NULL) + if (str) if (string2state(str) != interface->state) { 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 @@ -1710,8 +2931,8 @@ static void interface_property(const char *key, DBusMessageIter *iter, dbus_message_iter_get_basic(iter, &scanning); interface->scanning = scanning; - if (interface->ready == TRUE) { - if (interface->scanning == TRUE) + if (interface->ready) { + if (interface->scanning) callback_scan_started(interface); else callback_scan_finished(interface); @@ -1725,7 +2946,7 @@ static void interface_property(const char *key, DBusMessageIter *iter, const char *str = NULL; dbus_message_iter_get_basic(iter, &str); - if (str != NULL) { + if (str) { g_free(interface->ifname); interface->ifname = g_strdup(str); } @@ -1733,7 +2954,7 @@ static void interface_property(const char *key, DBusMessageIter *iter, const char *str = NULL; dbus_message_iter_get_basic(iter, &str); - if (str != NULL) { + if (str) { g_free(interface->driver); interface->driver = g_strdup(str); } @@ -1741,25 +2962,51 @@ static void interface_property(const char *key, DBusMessageIter *iter, const char *str = NULL; dbus_message_iter_get_basic(iter, &str); - if (str != NULL) { + if (str) { 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) +#endif interface_network_added(iter, interface); } else if (g_strcmp0(key, "BSSs") == 0) { - supplicant_dbus_array_foreach(iter, interface_bss_added_without_keys, - interface); + supplicant_dbus_array_foreach(iter, + interface_bss_added_without_keys, + interface); } else if (g_strcmp0(key, "Blobs") == 0) { /* Nothing */ } else if (g_strcmp0(key, "Networks") == 0) { supplicant_dbus_array_foreach(iter, interface_network_added, interface); - } else + } else if (g_strcmp0(key, "DisconnectReason") == 0) { + int reason_code; + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) { + dbus_message_iter_get_basic(iter, &reason_code); + callback_disconnect_reason_code(interface, reason_code); + } + } else if (g_strcmp0(key, "AssocStatusCode") == 0) { + int status_code; + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) { + dbus_message_iter_get_basic(iter, &status_code); + callback_assoc_status_code(interface, status_code); + } + } 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) @@ -1768,12 +3015,12 @@ static void scan_network_update(DBusMessageIter *iter, void *user_data) GSupplicantNetwork *network; char *path; - if (iter == NULL) + if (!iter) return; dbus_message_iter_get_basic(iter, &path); - if (path == NULL) + if (!path) return; if (g_strcmp0(path, "/") == 0) @@ -1781,7 +3028,7 @@ static void scan_network_update(DBusMessageIter *iter, void *user_data) /* Update the network details based on scan BSS data */ network = g_hash_table_lookup(interface->bss_mapping, path); - if (network != NULL) + if (network) callback_network_added(network); } @@ -1790,15 +3037,30 @@ static void scan_bss_data(const char *key, DBusMessageIter *iter, { GSupplicantInterface *interface = user_data; +/*Fixed : stucking in scanning state when scan failed*/ +#if defined TIZEN_EXT + GSupplicantInterfaceCallback scan_callback; +#endif + if (iter) supplicant_dbus_array_foreach(iter, scan_network_update, interface); - if (interface->scan_callback != NULL) +#if defined TIZEN_EXT + scan_callback = interface->scan_callback; +#endif + + if (interface->scan_callback) interface->scan_callback(0, interface, interface->scan_data); +#if defined TIZEN_EXT + if (interface->scan_callback == scan_callback) { +#endif interface->scan_callback = NULL; interface->scan_data = NULL; +#if defined TIZEN_EXT + } +#endif } static GSupplicantInterface *interface_alloc(const char *path) @@ -1806,16 +3068,17 @@ static GSupplicantInterface *interface_alloc(const char *path) GSupplicantInterface *interface; interface = g_try_new0(GSupplicantInterface, 1); - if (interface == NULL) + if (!interface) return NULL; interface->path = g_strdup(path); interface->network_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, remove_network); - - interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, NULL); + interface->peer_table = g_hash_table_new_full(g_str_hash, + g_str_equal, NULL, remove_peer); + interface->group_table = g_hash_table_new_full(g_str_hash, + g_str_equal, NULL, remove_group); interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); @@ -1828,45 +3091,53 @@ 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(""); dbus_message_iter_get_basic(iter, &path); - if (path == NULL) + if (!path) return; if (g_strcmp0(path, "/") == 0) return; interface = g_hash_table_lookup(interface_table, path); - if (interface != NULL) + if (interface) return; interface = interface_alloc(path); - if (interface == NULL) + 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); } static void interface_removed(DBusMessageIter *iter, void *user_data) { const char *path = NULL; + GSupplicantInterface *interface = user_data; dbus_message_iter_get_basic(iter, &path); - if (path == NULL) + if (!path) return; + interface = g_hash_table_lookup(interface_table, path); + g_supplicant_interface_cancel(interface); + g_hash_table_remove(interface_table, path); } @@ -1876,10 +3147,10 @@ static void eap_method(DBusMessageIter *iter, void *user_data) int i; dbus_message_iter_get_basic(iter, &str); - if (str == NULL) + if (!str) return; - for (i = 0; eap_method_map[i].str != NULL; i++) + for (i = 0; eap_method_map[i].str; i++) if (strcmp(str, eap_method_map[i].str) == 0) { eap_methods |= eap_method_map[i].val; break; @@ -1889,7 +3160,7 @@ static void eap_method(DBusMessageIter *iter, void *user_data) static void service_property(const char *key, DBusMessageIter *iter, void *user_data) { - if (key == NULL) { + if (!key) { callback_system_ready(); return; } @@ -1899,7 +3170,7 @@ static void service_property(const char *key, DBusMessageIter *iter, int i; dbus_message_iter_get_basic(iter, &str); - for (i = 0; debug_strings[i] != NULL; i++) + for (i = 0; debug_strings[i]; i++) if (g_strcmp0(debug_strings[i], str) == 0) { debug_level = i; break; @@ -1936,7 +3207,7 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter) return; dbus_message_iter_get_basic(iter, &name); - if (name == NULL) + if (!name) return; if (g_strcmp0(name, SUPPLICANT_SERVICE) != 0) @@ -1947,12 +3218,15 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter) dbus_message_iter_next(iter); dbus_message_iter_get_basic(iter, &new); - if (old == NULL || new == NULL) + if (!old || !new) return; if (strlen(old) > 0 && strlen(new) == 0) { system_available = FALSE; 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(); } @@ -1960,8 +3234,8 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter) if (strlen(new) > 0 && strlen(old) == 0) { system_available = TRUE; supplicant_dbus_property_get_all(SUPPLICANT_PATH, - SUPPLICANT_INTERFACE, - service_property, NULL); + SUPPLICANT_INTERFACE, + service_property, NULL, NULL); } } @@ -1980,7 +3254,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) @@ -1998,7 +3272,7 @@ static void signal_interface_changed(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) + if (!interface) return; supplicant_dbus_property_foreach(iter, interface_property, interface); @@ -2012,17 +3286,22 @@ static void signal_scan_done(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) + if (!interface) return; dbus_message_iter_get_basic(iter, &success); + if (interface->scanning) { + callback_scan_finished(interface); + interface->scanning = FALSE; + } + /* * If scan is unsuccessful return -EIO else get the scanned BSSs * and update the network details accordingly */ - if (success == FALSE) { - if (interface->scan_callback != NULL) + if (!success) { + if (interface->scan_callback) interface->scan_callback(-EIO, interface, interface->scan_data); @@ -2033,7 +3312,7 @@ static void signal_scan_done(const char *path, DBusMessageIter *iter) } supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface", - "BSSs", scan_bss_data, interface); + "BSSs", scan_bss_data, interface, interface); } static void signal_bss_added(const char *path, DBusMessageIter *iter) @@ -2043,7 +3322,7 @@ static void signal_bss_added(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) + if (!interface) return; interface_bss_added_with_keys(iter, interface); @@ -2056,7 +3335,7 @@ static void signal_bss_removed(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) + if (!interface) return; interface_bss_removed(iter, interface); @@ -2069,7 +3348,7 @@ static void signal_network_added(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) + if (!interface) return; interface_network_added(iter, interface); @@ -2082,11 +3361,18 @@ static void signal_network_removed(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) + if (!interface) return; 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) { @@ -2098,19 +3384,22 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(bss_mapping, path); - if (interface == NULL) + if (!interface) return; network = g_hash_table_lookup(interface->bss_mapping, path); - if (network == NULL) + if (!network) return; bss = g_hash_table_lookup(network->bss_table, path); - if (bss == NULL) + if (!bss) return; 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); @@ -2131,21 +3420,50 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) * plugin about it. */ new_bss = g_try_new0(struct g_supplicant_bss, 1); - if (new_bss == NULL) + if (!new_bss) return; 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; } +#if defined TIZEN_EXT + if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) { + network->wps = TRUE; + network->wps_capabilities |= bss->wps_capabilities; + } else + 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; +#else + { + callback_network_changed(network, ""); return; + } +#endif /* * If the new signal is lower than the SSID signal, we need @@ -2153,7 +3471,14 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) */ if (bss->signal < network->signal) { if (bss != network->best_bss) +#ifndef TIZEN_EXT return; +#else + { + callback_network_changed(network, ""); + return; + } +#endif network->signal = bss->signal; update_network_signal(network); } else { @@ -2161,7 +3486,8 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter) network->best_bss = bss; } - SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid, network->signal); + SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid, + network->signal); callback_network_changed(network, "Signal"); } @@ -2171,7 +3497,7 @@ static void wps_credentials(const char *key, DBusMessageIter *iter, { GSupplicantInterface *interface = user_data; - if (key == NULL) + if (!key) return; SUPPLICANT_DBG("key %s", key); @@ -2188,7 +3514,7 @@ static void wps_credentials(const char *key, DBusMessageIter *iter, interface->wps_cred.key = g_try_malloc0( sizeof(char) * key_len + 1); - if (interface->wps_cred.key == NULL) + if (!interface->wps_cred.key) return; memcpy(interface->wps_cred.key, key_val, @@ -2220,7 +3546,7 @@ static void signal_wps_credentials(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) + if (!interface) return; supplicant_dbus_property_foreach(iter, wps_credentials, interface); @@ -2231,7 +3557,7 @@ static void wps_event_args(const char *key, DBusMessageIter *iter, { GSupplicantInterface *interface = user_data; - if (key == NULL || interface == NULL) + if (!key || !interface) return; SUPPLICANT_DBG("Arg Key %s", key); @@ -2245,7 +3571,7 @@ static void signal_wps_event(const char *path, DBusMessageIter *iter) SUPPLICANT_DBG(""); interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) + if (!interface) return; dbus_message_iter_get_basic(iter, &name); @@ -2267,1422 +3593,3689 @@ static void signal_wps_event(const char *path, DBusMessageIter *iter) supplicant_dbus_property_foreach(iter, wps_event_args, interface); } -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 }, +#if defined TIZEN_EXT +static void signal_power_off(const char *path, DBusMessageIter *iter) +{ + int poweroff_state = 0; - { SUPPLICANT_INTERFACE, "PropertiesChanged", signal_properties_changed }, - { SUPPLICANT_INTERFACE, "InterfaceAdded", signal_interface_added }, - { SUPPLICANT_INTERFACE, "InterfaceCreated", signal_interface_added }, - { SUPPLICANT_INTERFACE, "InterfaceRemoved", signal_interface_removed }, + dbus_message_iter_get_basic(iter, &poweroff_state); - { 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_DBG("poweroff_state(%d)", poweroff_state); - { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed }, + /* POWER_OFF_DIRECT 2 && POWER_OFF_RESTART 3 */ + if (poweroff_state != 2 && poweroff_state != 3) + return; - { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials }, - { SUPPLICANT_INTERFACE ".Interface.WPS", "Event", signal_wps_event }, + if (callbacks_pointer == NULL) + return; - { } -}; + if (callbacks_pointer->system_power_off == NULL) + return; -static DBusHandlerResult g_supplicant_filter(DBusConnection *conn, - DBusMessage *message, void *data) + callbacks_pointer->system_power_off(); +} +#endif + +static void signal_station_connected(const char *path, DBusMessageIter *iter) { - DBusMessageIter iter; - const char *path; - int i; + GSupplicantInterface *interface; + const char *sta_mac = NULL; - path = dbus_message_get_path(message); - if (path == NULL) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH); - if (dbus_message_iter_init(message, &iter) == FALSE) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + if (callbacks_pointer->add_station == NULL) + return; - for (i = 0; signal_map[i].interface != NULL; i++) { - if (dbus_message_has_interface(message, - signal_map[i].interface) == FALSE) - continue; + if (g_strcmp0(path, "/") == 0) + return; - if (dbus_message_has_member(message, - signal_map[i].member) == FALSE) - continue; + interface = g_hash_table_lookup(interface_table, path); + if (interface == NULL) + return; - signal_map[i].function(path, &iter); - break; - } + dbus_message_iter_get_basic(iter, &sta_mac); + if (sta_mac == NULL) + return; - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + SUPPLICANT_DBG("New station %s connected", sta_mac); + callbacks_pointer->add_station(sta_mac); } -struct supplicant_regdom { - GSupplicantCountryCallback callback; - const char *alpha2; - const void *user_data; -}; - -static void country_result(const char *error, - DBusMessageIter *iter, void *user_data) +static void signal_station_disconnected(const char *path, DBusMessageIter *iter) { - struct supplicant_regdom *regdom = user_data; - int result = 0; + GSupplicantInterface *interface; + const char *sta_mac = NULL; - SUPPLICANT_DBG("Country setting result"); + SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH); - if (user_data == NULL) + if (callbacks_pointer->remove_station == NULL) return; - if (error != NULL) { - SUPPLICANT_DBG("Country setting failure %s", error); - result = -EINVAL; - } + if (g_strcmp0(path, "/") == 0) + return; - if (regdom->callback) - regdom->callback(result, regdom->alpha2, - (void *) regdom->user_data); + interface = g_hash_table_lookup(interface_table, path); + if (interface == NULL) + return; - g_free(regdom); + dbus_message_iter_get_basic(iter, &sta_mac); + if (sta_mac == NULL) + return; + + SUPPLICANT_DBG("Station %s disconnected", sta_mac); + callbacks_pointer->remove_station(sta_mac); } -static void country_params(DBusMessageIter *iter, void *user_data) +static void create_peer_identifier(GSupplicantPeer *peer) { - struct supplicant_regdom *regdom = user_data; + const unsigned char test[ETH_ALEN] = {}; - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, - ®dom->alpha2); -} + if (!peer) + return; -int g_supplicant_set_country(const char *alpha2, - GSupplicantCountryCallback callback, - const void *user_data) -{ - struct supplicant_regdom *regdom; + if (!memcmp(peer->device_address, test, ETH_ALEN)) { + peer->identifier = g_strdup(peer->name); + return; + } - SUPPLICANT_DBG("Country setting %s", alpha2); + peer->identifier = g_malloc0(19); + snprintf(peer->identifier, 19, "%02x%02x%02x%02x%02x%02x", + peer->device_address[0], + peer->device_address[1], + peer->device_address[2], + peer->device_address[3], + peer->device_address[4], + peer->device_address[5]); +} + +struct peer_property_data { + GSupplicantPeer *peer; + GSList *old_groups; + bool groups_changed; + bool services_changed; +}; - if (system_available == FALSE) - return -EFAULT; +static void peer_groups_relation(DBusMessageIter *iter, void *user_data) +{ + struct peer_property_data *data = user_data; + GSupplicantPeer *peer = data->peer; + GSupplicantGroup *group; + const char *str = NULL; + GSList *elem; - regdom = dbus_malloc0(sizeof(*regdom)); - if (regdom == NULL) - return -ENOMEM; + dbus_message_iter_get_basic(iter, &str); + if (!str) + return; - regdom->callback = callback; - regdom->alpha2 = alpha2; - regdom->user_data = user_data; + group = g_hash_table_lookup(group_mapping, str); + if (!group) + return; - return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE, - "Country", DBUS_TYPE_STRING_AS_STRING, - country_params, country_result, - regdom); + 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); + } else { + peer->groups = g_slist_prepend(peer->groups, g_strdup(str)); + data->groups_changed = true; + } } -int g_supplicant_interface_set_country(GSupplicantInterface *interface, - GSupplicantCountryCallback callback, - const char *alpha2, +static void peer_property(const char *key, DBusMessageIter *iter, void *user_data) { - struct supplicant_regdom *regdom; + GSupplicantPeer *pending_peer; + struct peer_property_data *data = user_data; + GSupplicantPeer *peer = data->peer; - regdom = dbus_malloc0(sizeof(*regdom)); - if (regdom == NULL) - return -ENOMEM; + SUPPLICANT_DBG("key: %s", key); - regdom->callback = callback; - regdom->alpha2 = alpha2; - regdom->user_data = user_data; + if (!peer->interface) + return; - return supplicant_dbus_property_set(interface->path, - SUPPLICANT_INTERFACE ".Interface", - "Country", DBUS_TYPE_STRING_AS_STRING, - country_params, country_result, - regdom); -} + if (!key) { + if (peer->name) { + create_peer_identifier(peer); + callback_peer_found(peer); + pending_peer = g_hash_table_lookup( + pending_peer_connection, peer->path); + + if (pending_peer && pending_peer == peer) { + callback_peer_request(peer); + g_hash_table_remove(pending_peer_connection, + peer->path); + } -struct interface_data { - GSupplicantInterface *interface; - GSupplicantInterfaceCallback callback; - void *user_data; -}; + dbus_free(data); + } -struct interface_create_data { - const char *ifname; - const char *driver; - const char *bridge; - GSupplicantInterface *interface; - GSupplicantInterfaceCallback callback; - void *user_data; -}; + return; + } -struct interface_connect_data { - GSupplicantInterface *interface; - GSupplicantInterfaceCallback callback; - GSupplicantSSID *ssid; - void *user_data; -}; + if (g_strcmp0(key, "DeviceAddress") == 0) { + unsigned char *dev_addr; + DBusMessageIter array; + int len; -struct interface_scan_data { - GSupplicantInterface *interface; - GSupplicantInterfaceCallback callback; - GSupplicantScanParams *scan_params; - void *user_data; -}; + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &dev_addr, &len); -struct interface_autoscan_data { - GSupplicantInterface *interface; - GSupplicantInterfaceCallback callback; - const char *autoscan_params; - void *user_data; -}; + if (len == ETH_ALEN) + memcpy(peer->device_address, dev_addr, len); + } else if (g_strcmp0(key, "DeviceName") == 0) { + const char *str = NULL; -static void interface_create_property(const char *key, DBusMessageIter *iter, - void *user_data) -{ - struct interface_create_data *data = user_data; - GSupplicantInterface *interface = data->interface; + dbus_message_iter_get_basic(iter, &str); + if (str) + peer->name = g_strdup(str); + } else if (g_strcmp0(key, "config_method") == 0) { + uint16_t wps_config; - if (key == NULL) { - if (data->callback != NULL) - data->callback(0, data->interface, data->user_data); + dbus_message_iter_get_basic(iter, &wps_config); - dbus_free(data); - } + if (wps_config & G_SUPPLICANT_WPS_CONFIG_PBC) + peer->wps_capabilities |= G_SUPPLICANT_WPS_PBC; + if (wps_config & ~G_SUPPLICANT_WPS_CONFIG_PBC) + peer->wps_capabilities |= G_SUPPLICANT_WPS_PIN; + } else if (g_strcmp0(key, "Groups") == 0) { + data->old_groups = peer->groups; + peer->groups = NULL; - interface_property(key, iter, interface); + supplicant_dbus_array_foreach(iter, + peer_groups_relation, data); + if (g_slist_length(data->old_groups) > 0) { + g_slist_free_full(data->old_groups, g_free); + data->groups_changed = true; + } + } else if (g_strcmp0(key, "IEs") == 0) { + DBusMessageIter array; + unsigned char *ie; + int ie_len; + + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &ie, &ie_len); + + if (!ie || ie_len < 2) + return; + + if (peer->widi_ies) { + if (memcmp(peer->widi_ies, ie, ie_len) == 0) + return; + + g_free(peer->widi_ies); + peer->widi_ies_length = 0; + } + + peer->widi_ies = g_malloc0(ie_len * sizeof(unsigned char)); + + memcpy(peer->widi_ies, ie, ie_len); + peer->widi_ies_length = ie_len; + data->services_changed = true; + } } -static void interface_create_result(const char *error, - DBusMessageIter *iter, void *user_data) +static void signal_peer_found(const char *path, DBusMessageIter *iter) { - struct interface_create_data *data = user_data; - const char *path = NULL; - int err; + struct peer_property_data *property_data; + GSupplicantInterface *interface; + const char *obj_path = NULL; + GSupplicantPeer *peer; SUPPLICANT_DBG(""); - if (error != NULL) { - g_warning("error %s", error); - err = -EIO; - goto done; - } - - dbus_message_iter_get_basic(iter, &path); - if (path == NULL) { - err = -EINVAL; - goto done; - } + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; - if (system_available == FALSE) { - err = -EFAULT; - goto done; - } + dbus_message_iter_get_basic(iter, &obj_path); + if (!obj_path || g_strcmp0(obj_path, "/") == 0) + return; - data->interface = g_hash_table_lookup(interface_table, path); - if (data->interface == NULL) { - data->interface = interface_alloc(path); - if (data->interface == NULL) { - err = -ENOMEM; - goto done; - } - } + peer = g_hash_table_lookup(interface->peer_table, obj_path); + if (peer) + return; - err = supplicant_dbus_property_get_all(path, - SUPPLICANT_INTERFACE ".Interface", - interface_create_property, data); - if (err == 0) + peer = g_try_new0(GSupplicantPeer, 1); + if (!peer) return; -done: - if (data->callback != NULL) - data->callback(err, NULL, data->user_data); + peer->interface = interface; + peer->path = g_strdup(obj_path); + g_hash_table_insert(interface->peer_table, peer->path, peer); + g_hash_table_replace(peer_mapping, peer->path, interface); - dbus_free(data); + property_data = dbus_malloc0(sizeof(struct peer_property_data)); + property_data->peer = peer; + + dbus_message_iter_next(iter); + if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) { + supplicant_dbus_property_foreach(iter, peer_property, + property_data); + peer_property(NULL, NULL, property_data); + return; + } + + supplicant_dbus_property_get_all(obj_path, + SUPPLICANT_INTERFACE ".Peer", + peer_property, property_data, NULL); } -static void interface_create_params(DBusMessageIter *iter, void *user_data) +static void signal_peer_lost(const char *path, DBusMessageIter *iter) { - struct interface_create_data *data = user_data; - DBusMessageIter dict; + GSupplicantInterface *interface; + const char *obj_path = NULL; + GSupplicantPeer *peer; SUPPLICANT_DBG(""); - supplicant_dbus_dict_open(iter, &dict); - - supplicant_dbus_dict_append_basic(&dict, "Ifname", - DBUS_TYPE_STRING, &data->ifname); + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; - if (data->driver != NULL) - supplicant_dbus_dict_append_basic(&dict, "Driver", - DBUS_TYPE_STRING, &data->driver); + dbus_message_iter_get_basic(iter, &obj_path); + if (!obj_path || g_strcmp0(obj_path, "/") == 0) + return; - if (data->bridge != NULL) - supplicant_dbus_dict_append_basic(&dict, "BridgeIfname", - DBUS_TYPE_STRING, &data->bridge); + peer = g_hash_table_lookup(interface->peer_table, obj_path); + if (!peer) + return; - supplicant_dbus_dict_close(iter, &dict); + g_hash_table_remove(interface->peer_table, obj_path); } -static void interface_get_result(const char *error, - DBusMessageIter *iter, void *user_data) +static void signal_peer_changed(const char *path, DBusMessageIter *iter) { - struct interface_create_data *data = user_data; + struct peer_property_data *property_data; GSupplicantInterface *interface; - const char *path = NULL; - int err; + GSupplicantPeer *peer; SUPPLICANT_DBG(""); - if (error != NULL) { - SUPPLICANT_DBG("Interface not created yet"); - goto create; - } + interface = g_hash_table_lookup(peer_mapping, path); + if (!interface) + return; - dbus_message_iter_get_basic(iter, &path); - if (path == NULL) { - err = -EINVAL; - goto done; + peer = g_hash_table_lookup(interface->peer_table, path); + if (!peer) { + g_hash_table_remove(peer_mapping, path); + return; } - interface = g_hash_table_lookup(interface_table, path); - if (interface == NULL) { - err = -ENOENT; - goto done; - } + property_data = dbus_malloc0(sizeof(struct peer_property_data)); + property_data->peer = peer; - if (data->callback != NULL) - data->callback(0, interface, data->user_data); + supplicant_dbus_property_foreach(iter, peer_property, property_data); + if (property_data->services_changed) + callback_peer_changed(peer, + G_SUPPLICANT_PEER_SERVICES_CHANGED); - dbus_free(data); + if (property_data->groups_changed) + callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_CHANGED); - return; + dbus_free(property_data); -create: - if (system_available == FALSE) { - err = -EFAULT; - goto done; - } + if (!g_supplicant_peer_is_in_a_group(peer)) + peer->connection_requested = false; +} - SUPPLICANT_DBG("Creating interface"); +struct group_sig_data { + const char *peer_obj_path; + unsigned char iface_address[ETH_ALEN]; + const char *interface_obj_path; + const char *group_obj_path; + int role; +}; - err = supplicant_dbus_method_call(SUPPLICANT_PATH, - SUPPLICANT_INTERFACE, - "CreateInterface", - interface_create_params, - interface_create_result, data); - if (err == 0) +static void group_sig_property(const char *key, DBusMessageIter *iter, + void *user_data) +{ + struct group_sig_data *data = user_data; + + if (!key) return; -done: - if (data->callback != NULL) - data->callback(err, NULL, data->user_data); + if (g_strcmp0(key, "peer_interface_addr") == 0) { + unsigned char *dev_addr; + DBusMessageIter array; + int len; - dbus_free(data); -} + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &dev_addr, &len); -static void interface_get_params(DBusMessageIter *iter, void *user_data) -{ - struct interface_create_data *data = user_data; + if (len == ETH_ALEN) + memcpy(data->iface_address, dev_addr, len); + } else if (g_strcmp0(key, "role") == 0) { + const char *str = NULL; - SUPPLICANT_DBG(""); + dbus_message_iter_get_basic(iter, &str); + if (g_strcmp0(str, "GO") == 0) + data->role = G_SUPPLICANT_GROUP_ROLE_GO; + else + data->role = G_SUPPLICANT_GROUP_ROLE_CLIENT; + } else if (g_strcmp0(key, "peer_object") == 0) + dbus_message_iter_get_basic(iter, &data->peer_obj_path); + else if (g_strcmp0(key, "interface_object") == 0) + dbus_message_iter_get_basic(iter, &data->interface_obj_path); + else if (g_strcmp0(key, "group_object") == 0) + dbus_message_iter_get_basic(iter, &data->group_obj_path); - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname); } -int g_supplicant_interface_create(const char *ifname, const char *driver, - const char *bridge, - GSupplicantInterfaceCallback callback, - void *user_data) +static void signal_group_success(const char *path, DBusMessageIter *iter) { - struct interface_create_data *data; - - SUPPLICANT_DBG("ifname %s", ifname); + GSupplicantInterface *interface; + struct group_sig_data data = {}; + GSupplicantPeer *peer; - if (ifname == NULL) - return -EINVAL; + SUPPLICANT_DBG(""); - if (system_available == FALSE) - return -EFAULT; + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; - data = dbus_malloc0(sizeof(*data)); - if (data == NULL) - return -ENOMEM; + supplicant_dbus_property_foreach(iter, group_sig_property, &data); + if (!data.peer_obj_path) + return; - data->ifname = ifname; - data->driver = driver; - data->bridge = bridge; - data->callback = callback; - data->user_data = user_data; + peer = g_hash_table_lookup(interface->peer_table, data.peer_obj_path); + if (!peer) + return; - return supplicant_dbus_method_call(SUPPLICANT_PATH, - SUPPLICANT_INTERFACE, - "GetInterface", - interface_get_params, - interface_get_result, data); + memcpy(peer->iface_address, data.iface_address, ETH_ALEN); + interface->pending_peer_path = peer->path; } -static void interface_remove_result(const char *error, - DBusMessageIter *iter, void *user_data) +static void signal_group_failure(const char *path, DBusMessageIter *iter) { - struct interface_data *data = user_data; - int err; - - if (error != NULL) { - err = -EIO; - goto done; - } - - if (system_available == FALSE) { - err = -EFAULT; - goto done; - } - - /* - * The gsupplicant interface is already freed by the InterfaceRemoved - * signal callback. Simply invoke the interface_data callback. - */ - err = 0; + GSupplicantInterface *interface; + struct group_sig_data data = {}; + GSupplicantPeer *peer; -done: - if (data->callback != NULL) - data->callback(err, NULL, data->user_data); + SUPPLICANT_DBG(""); - dbus_free(data); -} + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; + supplicant_dbus_property_foreach(iter, group_sig_property, &data); + if (!data.peer_obj_path) + return; -static void interface_remove_params(DBusMessageIter *iter, void *user_data) -{ - struct interface_data *data = user_data; + peer = g_hash_table_lookup(interface->peer_table, data.peer_obj_path); + if (!peer) + return; - dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, - &data->interface->path); + callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_FAILED); + peer->connection_requested = false; } - -int g_supplicant_interface_remove(GSupplicantInterface *interface, - GSupplicantInterfaceCallback callback, - void *user_data) +static void signal_group_started(const char *path, DBusMessageIter *iter) { - struct interface_data *data; + GSupplicantInterface *interface, *g_interface; + struct group_sig_data data = {}; + GSupplicantGroup *group; + GSupplicantPeer *peer; - if (interface == NULL) - return -EINVAL; - - if (system_available == FALSE) - return -EFAULT; + SUPPLICANT_DBG(""); - data = dbus_malloc0(sizeof(*data)); - if (data == NULL) - return -ENOMEM; + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; - data->interface = interface; - data->callback = callback; - data->user_data = user_data; + supplicant_dbus_property_foreach(iter, group_sig_property, &data); + if (!data.interface_obj_path || !data.group_obj_path) + return; - return supplicant_dbus_method_call(SUPPLICANT_PATH, - SUPPLICANT_INTERFACE, - "RemoveInterface", - interface_remove_params, - interface_remove_result, data); -} + peer = g_hash_table_lookup(interface->peer_table, + interface->pending_peer_path); + interface->pending_peer_path = NULL; + if (!peer) + return; -static void interface_scan_result(const char *error, - DBusMessageIter *iter, void *user_data) -{ - struct interface_scan_data *data = user_data; - int err = 0; + g_interface = g_hash_table_lookup(interface_table, + data.interface_obj_path); + if (!g_interface) + return; - if (error != NULL) { - SUPPLICANT_DBG("error %s", error); - err = -EIO; - } + group = g_hash_table_lookup(interface->group_table, + data.group_obj_path); + if (group) + return; - /* A non ready interface cannot send/receive anything */ - if (data->interface->ready == FALSE) - err = -ENOLINK; + group = g_try_new0(GSupplicantGroup, 1); + if (!group) + return; - if (err != 0) { - if (data->callback != NULL) - data->callback(err, data->interface, data->user_data); - } else { - data->interface->scan_callback = data->callback; - data->interface->scan_data = data->user_data; - } + group->interface = g_interface; + group->orig_interface = interface; + group->path = g_strdup(data.group_obj_path); + group->role = data.role; - if (data != NULL && data->scan_params != NULL) - g_supplicant_free_scan_params(data->scan_params); + g_hash_table_insert(interface->group_table, group->path, group); + g_hash_table_replace(group_mapping, group->path, group); - dbus_free(data); + peer->current_group_iface = g_interface; + callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_STARTED); } -static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq) +static void remove_peer_group_interface(GHashTable *group_table, + const char* path) { - DBusMessageIter data; - unsigned int width = 0; /* Not used by wpa_supplicant atm */ + GSupplicantGroup *group; + GHashTableIter iter; + gpointer value, key; - dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data); + if (!group_table) + return; - dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq); - dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width); + group = g_hash_table_lookup(group_table, path); - dbus_message_iter_close_container(iter, &data); -} + if (!group || !group->orig_interface) + return; -static void add_scan_frequencies(DBusMessageIter *iter, - void *user_data) -{ - GSupplicantScanParams *scan_data = user_data; - unsigned int freq; - int i; + g_hash_table_iter_init(&iter, group->orig_interface->peer_table); - for (i = 0; i < scan_data->num_ssids; i++) { - freq = scan_data->freqs[i]; - if (!freq) - break; + while (g_hash_table_iter_next(&iter, &key, &value)) { + GSupplicantPeer *peer = value; - add_scan_frequency(iter, freq); + if (peer->current_group_iface == group->interface) + peer->current_group_iface = NULL; } } -static void append_ssid(DBusMessageIter *iter, - const void *ssid, unsigned int len) +static void signal_group_finished(const char *path, DBusMessageIter *iter) { - DBusMessageIter array; + GSupplicantInterface *interface; + struct group_sig_data data = {}; - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, - DBUS_TYPE_BYTE_AS_STRING, &array); + SUPPLICANT_DBG(""); - dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, - &ssid, len); - dbus_message_iter_close_container(iter, &array); -} + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; -static void append_ssids(DBusMessageIter *iter, void *user_data) -{ - GSupplicantScanParams *scan_data = user_data; - GSList *list; + supplicant_dbus_property_foreach(iter, group_sig_property, &data); + if (!data.interface_obj_path || !data.group_obj_path) + return; - for (list = scan_data->ssids; list; list = list->next) { - struct scan_ssid *scan_ssid = list->data; + remove_peer_group_interface(interface->group_table, data.group_obj_path); - append_ssid(iter, scan_ssid->ssid, scan_ssid->ssid_len); - } + g_hash_table_remove(group_mapping, data.group_obj_path); + + g_hash_table_remove(interface->group_table, data.group_obj_path); } -static void supplicant_add_scan_frequency(DBusMessageIter *dict, - supplicant_dbus_array_function function, - void *user_data) +static void signal_group_request(const char *path, DBusMessageIter *iter) { - GSupplicantScanParams *scan_params = user_data; - DBusMessageIter entry, value, array; - const char *key = "Channels"; - - if (scan_params->freqs && scan_params->freqs[0] != 0) { - dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, - NULL, &entry); + GSupplicantInterface *interface; + GSupplicantPeer *peer; + const char *obj_path; - dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + SUPPLICANT_DBG(""); - dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, - DBUS_TYPE_ARRAY_AS_STRING - DBUS_STRUCT_BEGIN_CHAR_AS_STRING - DBUS_TYPE_UINT32_AS_STRING - DBUS_TYPE_UINT32_AS_STRING - DBUS_STRUCT_END_CHAR_AS_STRING, - &value); + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; - dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, - DBUS_STRUCT_BEGIN_CHAR_AS_STRING - DBUS_TYPE_UINT32_AS_STRING - DBUS_TYPE_UINT32_AS_STRING - DBUS_STRUCT_END_CHAR_AS_STRING, - &array); + dbus_message_iter_get_basic(iter, &obj_path); + if (!obj_path || !g_strcmp0(obj_path, "/")) + return; - if (function) - function(&array, user_data); + peer = g_hash_table_lookup(interface->peer_table, obj_path); + if (!peer) + return; - dbus_message_iter_close_container(&value, &array); - dbus_message_iter_close_container(&entry, &value); - dbus_message_iter_close_container(dict, &entry); - } + /* + * Peer has been previously found and property set, + * otherwise, defer connection to when peer property + * is set. + */ + if (peer->identifier) + callback_peer_request(peer); + else + g_hash_table_replace(pending_peer_connection, peer->path, peer); } -static void interface_scan_params(DBusMessageIter *iter, void *user_data) +static void signal_group_peer_joined(const char *path, DBusMessageIter *iter) { - DBusMessageIter dict; - const char *type = "passive"; - struct interface_scan_data *data = user_data; + const char *peer_path = NULL; + GSupplicantInterface *interface; + GSupplicantGroup *group; + GSupplicantPeer *peer; - supplicant_dbus_dict_open(iter, &dict); + SUPPLICANT_DBG(""); - if (data && data->scan_params) { - type = "active"; + group = g_hash_table_lookup(group_mapping, path); + if (!group) + return; - supplicant_dbus_dict_append_basic(&dict, "Type", - DBUS_TYPE_STRING, &type); + dbus_message_iter_get_basic(iter, &peer_path); + if (!peer_path) + return; - supplicant_dbus_dict_append_array(&dict, "SSIDs", - DBUS_TYPE_STRING, - append_ssids, - data->scan_params); + interface = g_hash_table_lookup(peer_mapping, peer_path); + if (!interface) + return; - supplicant_add_scan_frequency(&dict, add_scan_frequencies, - data->scan_params); - } else - supplicant_dbus_dict_append_basic(&dict, "Type", - DBUS_TYPE_STRING, &type); + peer = g_hash_table_lookup(interface->peer_table, peer_path); + if (!peer) + return; - supplicant_dbus_dict_close(iter, &dict); + group->members = g_slist_prepend(group->members, g_strdup(peer_path)); + + callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_JOINED); } -int g_supplicant_interface_scan(GSupplicantInterface *interface, - GSupplicantScanParams *scan_data, - GSupplicantInterfaceCallback callback, - void *user_data) +static void signal_group_peer_disconnected(const char *path, DBusMessageIter *iter) { - struct interface_scan_data *data; - int ret; + const char *peer_path = NULL; + GSupplicantInterface *interface; + GSupplicantGroup *group; + GSupplicantPeer *peer; + GSList *elem; - if (interface == NULL) - return -EINVAL; + SUPPLICANT_DBG(""); - if (system_available == FALSE) - return -EFAULT; + group = g_hash_table_lookup(group_mapping, path); + if (!group) + return; - if (interface->scanning == TRUE) - return -EALREADY; + dbus_message_iter_get_basic(iter, &peer_path); + if (!peer_path) + return; - switch (interface->state) { - case G_SUPPLICANT_STATE_AUTHENTICATING: - case G_SUPPLICANT_STATE_ASSOCIATING: - case G_SUPPLICANT_STATE_ASSOCIATED: - case G_SUPPLICANT_STATE_4WAY_HANDSHAKE: - case G_SUPPLICANT_STATE_GROUP_HANDSHAKE: - return -EBUSY; - 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_COMPLETED: - break; + for (elem = group->members; elem; elem = elem->next) { + if (!g_strcmp0(elem->data, peer_path)) + break; } - data = dbus_malloc0(sizeof(*data)); - if (data == NULL) - return -ENOMEM; - - data->interface = interface; - data->callback = callback; - data->user_data = user_data; - data->scan_params = scan_data; + if (!elem) + return; - interface->scan_callback = callback; - interface->scan_data = user_data; + g_free(elem->data); + group->members = g_slist_delete_link(group->members, elem); - ret = supplicant_dbus_method_call(interface->path, - SUPPLICANT_INTERFACE ".Interface", "Scan", - interface_scan_params, interface_scan_result, data); + interface = g_hash_table_lookup(peer_mapping, peer_path); + if (!interface) + return; - if (ret < 0) - dbus_free(data); + peer = g_hash_table_lookup(interface->peer_table, peer_path); + if (!peer) + return; - return ret; + callback_peer_changed(peer, G_SUPPLICANT_PEER_GROUP_DISCONNECTED); + peer->connection_requested = false; } -static void interface_autoscan_result(const char *error, - DBusMessageIter *iter, void *user_data) +#if defined TIZEN_EXT_WIFI_MESH +const void *g_supplicant_interface_get_mesh_group_ssid( + GSupplicantInterface *interface, + unsigned int *ssid_len) { - struct interface_autoscan_data *data = user_data; - int err = 0; + if (!ssid_len) + return NULL; - if (error != NULL) { - SUPPLICANT_DBG("error %s", error); - err = -EIO; + if (!interface || interface->group_info.ssid_len == 0) { + *ssid_len = 0; + return NULL; } - if (data != NULL && data->callback != NULL) - data->callback(err, data->interface, data->user_data); - - dbus_free(data); + *ssid_len = interface->group_info.ssid_len; + return interface->group_info.ssid; } -static void interface_autoscan_params(DBusMessageIter *iter, void *user_data) +int g_supplicant_mesh_get_disconnect_reason(GSupplicantInterface *interface) { - struct interface_autoscan_data *data = user_data; + if (!interface) + return -EINVAL; - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, - &data->autoscan_params); + return interface->group_info.disconnect_reason; } -int g_supplicant_interface_autoscan(GSupplicantInterface *interface, - const char *autoscan_data, - GSupplicantInterfaceCallback callback, - void *user_data) +const char *g_supplicant_mesh_peer_get_address(GSupplicantMeshPeer *mesh_peer) { - struct interface_autoscan_data *data; - int ret; + if (!mesh_peer || !mesh_peer->peer_address) + return NULL; - data = dbus_malloc0(sizeof(*data)); - if (data == NULL) - return -ENOMEM; + return mesh_peer->peer_address; +} - data->interface = interface; - data->callback = callback; - data->autoscan_params = autoscan_data; - data->user_data = user_data; +int g_supplicant_mesh_peer_get_disconnect_reason(GSupplicantMeshPeer *mesh_peer) +{ + if (!mesh_peer) + return -EINVAL; - ret = supplicant_dbus_method_call(interface->path, - SUPPLICANT_INTERFACE ".Interface", "AutoScan", - interface_autoscan_params, - interface_autoscan_result, data); - if (ret < 0) - dbus_free(data); + return mesh_peer->disconnect_reason; +} - return ret; -} - -static int parse_supplicant_error(DBusMessageIter *iter) +static void callback_mesh_group_started(GSupplicantInterface *interface) { - int err = -ECANCELED; - char *key; + if (!callbacks_pointer) + return; - /* If the given passphrase is malformed wpa_s returns - * "invalid message format" but this error should be interpreted as - * invalid-key. - */ - while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) { - dbus_message_iter_get_basic(iter, &key); - if (strncmp(key, "psk", 3) == 0 || - strncmp(key, "wep_key", 7) == 0 || - strcmp(key, "invalid message format") == 0) { - err = -ENOKEY; - break; - } - dbus_message_iter_next(iter); - } + if (!callbacks_pointer->mesh_group_started) + return; - return err; + callbacks_pointer->mesh_group_started(interface); } -static void interface_select_network_result(const char *error, - DBusMessageIter *iter, void *user_data) +static void callback_mesh_group_removed(GSupplicantInterface *interface) { - struct interface_connect_data *data = user_data; - int err; - - SUPPLICANT_DBG(""); - - err = 0; - if (error != NULL) { - SUPPLICANT_DBG("SelectNetwork error %s", error); - err = parse_supplicant_error(iter); - } + if (!callbacks_pointer) + return; - if (data->callback != NULL) - data->callback(err, data->interface, data->user_data); + if (!callbacks_pointer->mesh_group_removed) + return; - g_free(data->ssid); - dbus_free(data); + callbacks_pointer->mesh_group_removed(interface); } -static void interface_select_network_params(DBusMessageIter *iter, +static void mesh_group_info(const char *key, DBusMessageIter *iter, void *user_data) { - struct interface_connect_data *data = user_data; - GSupplicantInterface *interface = data->interface; - - dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, - &interface->network_path); -} - -static void interface_add_network_result(const char *error, - DBusMessageIter *iter, void *user_data) -{ - struct interface_connect_data *data = user_data; - GSupplicantInterface *interface = data->interface; - const char *path; - int err; - - if (error != NULL) - goto error; - - dbus_message_iter_get_basic(iter, &path); - if (path == NULL) - goto error; - - SUPPLICANT_DBG("PATH: %s", path); - - g_free(interface->network_path); - interface->network_path = g_strdup(path); - - supplicant_dbus_method_call(data->interface->path, - SUPPLICANT_INTERFACE ".Interface", "SelectNetwork", - interface_select_network_params, - interface_select_network_result, data); + GSupplicantInterface *interface = user_data; + if (!key) + return; - return; + if (g_strcmp0(key, "SSID") == 0) { + DBusMessageIter array; + unsigned char *ssid; + int ssid_len; -error: - SUPPLICANT_DBG("AddNetwork error %s", error); - err = parse_supplicant_error(iter); - if (data->callback != NULL) - data->callback(err, data->interface, data->user_data); + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len); - g_free(interface->network_path); - interface->network_path = NULL; - g_free(data->ssid); - g_free(data); + 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 add_network_security_wep(DBusMessageIter *dict, - GSupplicantSSID *ssid) +static void signal_mesh_group_started(const char *path, DBusMessageIter *iter) { - const char *auth_alg = "OPEN SHARED"; - const char *key_index = "0"; - - supplicant_dbus_dict_append_basic(dict, "auth_alg", - DBUS_TYPE_STRING, &auth_alg); - - if (ssid->passphrase) { - int size = strlen(ssid->passphrase); - if (size == 10 || size == 26) { - unsigned char *key = g_try_malloc(13); - char tmp[3]; - int i; + GSupplicantInterface *interface; - memset(tmp, 0, sizeof(tmp)); - if (key == NULL) - size = 0; + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; - for (i = 0; i < size / 2; i++) { - memcpy(tmp, ssid->passphrase + (i * 2), 2); - key[i] = (unsigned char) strtol(tmp, NULL, 16); - } + supplicant_dbus_property_foreach(iter, mesh_group_info, interface); - supplicant_dbus_dict_append_fixed_array(dict, - "wep_key0", - DBUS_TYPE_BYTE, - &key, size / 2); - g_free(key); - } else if (size == 5 || size == 13) { - unsigned char *key = g_try_malloc(13); - int i; + callback_mesh_group_started(interface); +} - if (key == NULL) - size = 0; +static void signal_mesh_group_removed(const char *path, DBusMessageIter *iter) +{ + GSupplicantInterface *interface; - for (i = 0; i < size; i++) - key[i] = (unsigned char) ssid->passphrase[i]; + interface = g_hash_table_lookup(interface_table, path); + if (!interface) + return; - supplicant_dbus_dict_append_fixed_array(dict, - "wep_key0", - DBUS_TYPE_BYTE, - &key, size); - g_free(key); - } else - supplicant_dbus_dict_append_basic(dict, - "wep_key0", - DBUS_TYPE_STRING, - &ssid->passphrase); + supplicant_dbus_property_foreach(iter, mesh_group_info, interface); - supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx", - DBUS_TYPE_STRING, &key_index); - } + callback_mesh_group_removed(interface); } -static dbus_bool_t is_psk_raw_key(const char *psk) +static void callback_mesh_peer_connected(GSupplicantMeshPeer *mesh_peer) { - int i; - - /* A raw key is always 64 bytes length... */ - if (strlen(psk) != 64) - return FALSE; + if (!callbacks_pointer) + return; - /* ... and its content is in hex representation */ - for (i = 0; i < 64; i++) - if (!isxdigit((unsigned char) psk[i])) - return FALSE; + if (!callbacks_pointer->mesh_peer_connected) + return; - return TRUE; + callbacks_pointer->mesh_peer_connected(mesh_peer); } -static unsigned char hexchar2bin(char c) +static void callback_mesh_peer_disconnected(GSupplicantMeshPeer *mesh_peer) { - if ((c >= '0') && (c <= '9')) - return c - '0'; - else if ((c >= 'A') && (c <= 'F')) - return c - 'A' + 10; - else if ((c >= 'a') && (c <= 'f')) - return c - 'a' + 10; - else - return c; -} + if (!callbacks_pointer) + return; -static void hexstring2bin(const char *string, unsigned char *data, size_t data_len) -{ - size_t i; + if (!callbacks_pointer->mesh_peer_disconnected) + return; - for (i = 0; i < data_len; i++) - data[i] = (hexchar2bin(string[i * 2 + 0]) << 4 | - hexchar2bin(string[i * 2 + 1]) << 0); + callbacks_pointer->mesh_peer_disconnected(mesh_peer); } -static void add_network_security_psk(DBusMessageIter *dict, - GSupplicantSSID *ssid) +static void mesh_peer_info(const char *key, DBusMessageIter *iter, + void *user_data) { - if (ssid->passphrase && strlen(ssid->passphrase) > 0) { - const char *key = "psk"; - - if (is_psk_raw_key(ssid->passphrase) == TRUE) { - unsigned char data[32]; - unsigned char *datap = data; + GSupplicantMeshPeer *mesh_peer = user_data; + if (!key) + return; - /* The above pointer alias is required by D-Bus because - * with D-Bus and GCC, non-heap-allocated arrays cannot - * be passed directly by their base pointer. */ + if (g_strcmp0(key, "PeerAddress") == 0) { + DBusMessageIter array; + unsigned char *addr; + int addr_len; - hexstring2bin(ssid->passphrase, datap, sizeof(data)); + dbus_message_iter_recurse(iter, &array); + dbus_message_iter_get_fixed_array(&array, &addr, &addr_len); - supplicant_dbus_dict_append_fixed_array(dict, - key, DBUS_TYPE_BYTE, - &datap, sizeof(data)); - } else - supplicant_dbus_dict_append_basic(dict, - key, DBUS_TYPE_STRING, - &ssid->passphrase); + 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 add_network_security_tls(DBusMessageIter *dict, - GSupplicantSSID *ssid) +static void signal_mesh_peer_connected(const char *path, DBusMessageIter *iter) { - /* - * For TLS, we at least need: - * The client certificate - * The client private key file - * The client private key file password - * - * The Authority certificate is optional. - */ - if (ssid->client_cert_path == NULL) - return; + GSupplicantInterface *interface; + GSupplicantMeshPeer *mesh_peer; - if (ssid->private_key_path == NULL) + interface = g_hash_table_lookup(interface_table, path); + if (!interface) return; - if (ssid->private_key_passphrase == NULL) - return; + mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer)); + mesh_peer->interface = interface; - if (ssid->ca_cert_path) - supplicant_dbus_dict_append_basic(dict, "ca_cert", - DBUS_TYPE_STRING, &ssid->ca_cert_path); + supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer); - supplicant_dbus_dict_append_basic(dict, "private_key", - DBUS_TYPE_STRING, - &ssid->private_key_path); - supplicant_dbus_dict_append_basic(dict, "private_key_passwd", - DBUS_TYPE_STRING, - &ssid->private_key_passphrase); - supplicant_dbus_dict_append_basic(dict, "client_cert", - DBUS_TYPE_STRING, - &ssid->client_cert_path); + callback_mesh_peer_connected(mesh_peer); + g_free(mesh_peer->peer_address); + g_free(mesh_peer); } -static void add_network_security_peap(DBusMessageIter *dict, - GSupplicantSSID *ssid) +static void signal_mesh_peer_disconnected(const char *path, + DBusMessageIter *iter) { - char *phase2_auth; + GSupplicantInterface *interface; + GSupplicantMeshPeer *mesh_peer; - /* - * For PEAP/TTLS, we at least need - * The authority certificate - * The 2nd phase authentication method - * The 2nd phase passphrase - * - * The Client certificate is optional although strongly recommended - * When setting it, we need in addition - * The Client private key file - * The Client private key file password - */ - if (ssid->passphrase == NULL) + interface = g_hash_table_lookup(interface_table, path); + if (!interface) return; - if (ssid->phase2_auth == NULL) - return; + mesh_peer = dbus_malloc0(sizeof(GSupplicantMeshPeer)); + mesh_peer->interface = interface; - if (ssid->client_cert_path) { - if (ssid->private_key_path == NULL) - return; + supplicant_dbus_property_foreach(iter, mesh_peer_info, mesh_peer); - if (ssid->private_key_passphrase == NULL) - return; + callback_mesh_peer_disconnected(mesh_peer); + g_free(mesh_peer->peer_address); + g_free(mesh_peer); +} +#endif - supplicant_dbus_dict_append_basic(dict, "client_cert", - DBUS_TYPE_STRING, - &ssid->client_cert_path); +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_dbus_dict_append_basic(dict, "private_key", - DBUS_TYPE_STRING, - &ssid->private_key_path); + { 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_dbus_dict_append_basic(dict, "private_key_passwd", - DBUS_TYPE_STRING, - &ssid->private_key_passphrase); + { 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 }, - if (g_str_has_prefix(ssid->phase2_auth, "EAP-") == TRUE) { - phase2_auth = g_strdup_printf("autheap=%s", - ssid->phase2_auth + strlen("EAP-")); - } else - phase2_auth = g_strdup_printf("auth=%s", ssid->phase2_auth); + { 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_dbus_dict_append_basic(dict, "password", - DBUS_TYPE_STRING, - &ssid->passphrase); + { 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 - if (ssid->ca_cert_path) - supplicant_dbus_dict_append_basic(dict, "ca_cert", - DBUS_TYPE_STRING, - &ssid->ca_cert_path); + { } +}; - supplicant_dbus_dict_append_basic(dict, "phase2", - DBUS_TYPE_STRING, - &phase2_auth); +static DBusHandlerResult g_supplicant_filter(DBusConnection *conn, + DBusMessage *message, void *data) +{ + DBusMessageIter iter; + const char *path; + int i; - g_free(phase2_auth); + 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; } -static void add_network_security_eap(DBusMessageIter *dict, - GSupplicantSSID *ssid) +void g_supplicant_interface_cancel(GSupplicantInterface *interface) { - char *eap_value; + SUPPLICANT_DBG("Cancelling any pending DBus calls"); + supplicant_dbus_method_call_cancel_all(interface); + supplicant_dbus_property_call_cancel_all(interface); +} - if (ssid->eap == NULL || ssid->identity == NULL) - return; +struct supplicant_regdom { + GSupplicantCountryCallback callback; + const char *alpha2; + const void *user_data; +}; - if (g_strcmp0(ssid->eap, "tls") == 0) { - add_network_security_tls(dict, ssid); - } else if (g_strcmp0(ssid->eap, "peap") == 0 || - g_strcmp0(ssid->eap, "ttls") == 0) { - add_network_security_peap(dict, ssid); - } else +static void country_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct supplicant_regdom *regdom = user_data; + int result = 0; + + SUPPLICANT_DBG("Country setting result"); + + if (!user_data) return; - eap_value = g_ascii_strup(ssid->eap, -1); + if (error) { + SUPPLICANT_DBG("Country setting failure %s", error); + result = -EINVAL; + } - supplicant_dbus_dict_append_basic(dict, "eap", - DBUS_TYPE_STRING, - &eap_value); - supplicant_dbus_dict_append_basic(dict, "identity", - DBUS_TYPE_STRING, - &ssid->identity); + if (regdom->callback) + regdom->callback(result, regdom->alpha2, + (void *) regdom->user_data); - g_free(eap_value); + g_free(regdom); } -static void add_network_security_ciphers(DBusMessageIter *dict, - GSupplicantSSID *ssid) +static void country_params(DBusMessageIter *iter, void *user_data) { - unsigned int p_cipher, g_cipher, i; - char *pairwise, *group; - char *pair_ciphers[4]; - char *group_ciphers[5]; + struct supplicant_regdom *regdom = user_data; - p_cipher = ssid->pairwise_cipher; - g_cipher = ssid->group_cipher; + dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, + ®dom->alpha2); +} - if (p_cipher == 0 && g_cipher == 0) - return; +int g_supplicant_set_country(const char *alpha2, + GSupplicantCountryCallback callback, + const void *user_data) +{ + struct supplicant_regdom *regdom; + int ret; - i = 0; + SUPPLICANT_DBG("Country setting %s", alpha2); - if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP) - pair_ciphers[i++] = "CCMP"; + if (!system_available) + return -EFAULT; - if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP) - pair_ciphers[i++] = "TKIP"; + regdom = dbus_malloc0(sizeof(*regdom)); + if (!regdom) + return -ENOMEM; - if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE) - pair_ciphers[i++] = "NONE"; + regdom->callback = callback; + regdom->alpha2 = alpha2; + regdom->user_data = user_data; - pair_ciphers[i] = NULL; + 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; +} - i = 0; +int g_supplicant_interface_set_country(GSupplicantInterface *interface, + GSupplicantCountryCallback callback, + const char *alpha2, + void *user_data) +{ + struct supplicant_regdom *regdom; + int ret; - if (g_cipher & G_SUPPLICANT_GROUP_CCMP) - group_ciphers[i++] = "CCMP"; + regdom = dbus_malloc0(sizeof(*regdom)); + if (!regdom) + return -ENOMEM; - if (g_cipher & G_SUPPLICANT_GROUP_TKIP) - group_ciphers[i++] = "TKIP"; + regdom->callback = callback; + regdom->alpha2 = alpha2; + regdom->user_data = user_data; - if (g_cipher & G_SUPPLICANT_GROUP_WEP104) - group_ciphers[i++] = "WEP104"; + 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"); + } - if (g_cipher & G_SUPPLICANT_GROUP_WEP40) - group_ciphers[i++] = "WEP40"; + return ret; +} - group_ciphers[i] = NULL; +bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface) +{ + if (!interface) + return false; - pairwise = g_strjoinv(" ", pair_ciphers); - group = g_strjoinv(" ", group_ciphers); + return interface->p2p_support; +} - SUPPLICANT_DBG("cipher %s %s", pairwise, group); +struct supplicant_p2p_dev_config { + char *device_name; + char *dev_type; +}; - supplicant_dbus_dict_append_basic(dict, "pairwise", - DBUS_TYPE_STRING, - &pairwise); - supplicant_dbus_dict_append_basic(dict, "group", - DBUS_TYPE_STRING, - &group); +static void p2p_device_config_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct supplicant_p2p_dev_config *config = user_data; - g_free(pairwise); - g_free(group); + if (error) + SUPPLICANT_DBG("Unable to set P2P Device configuration: %s", + error); + + g_free(config->device_name); + g_free(config->dev_type); + dbus_free(config); } -static void add_network_security_proto(DBusMessageIter *dict, - GSupplicantSSID *ssid) +static int dev_type_str2bin(const char *type, unsigned char dev_type[8]) { - unsigned int protocol, i; - char *proto; - char *protos[3]; + int length, pos, end; + char b[3] = {}; + char *e = NULL; - protocol = ssid->protocol; + end = strlen(type); + for (length = pos = 0; type[pos] != '\0' && length < 8; length++) { + if (pos+2 > end) + return 0; - if (protocol == 0) - return; + b[0] = type[pos]; + b[1] = type[pos+1]; - i = 0; + dev_type[length] = strtol(b, &e, 16); + if (e && *e != '\0') + return 0; - if (protocol & G_SUPPLICANT_PROTO_RSN) - protos[i++] = "RSN"; + pos += 2; + } - if (protocol & G_SUPPLICANT_PROTO_WPA) - protos[i++] = "WPA"; + return 8; +} - protos[i] = NULL; +static void p2p_device_config_params(DBusMessageIter *iter, void *user_data) +{ + struct supplicant_p2p_dev_config *config = user_data; + DBusMessageIter dict; - proto = g_strjoinv(" ", protos); + supplicant_dbus_dict_open(iter, &dict); - SUPPLICANT_DBG("proto %s", proto); + supplicant_dbus_dict_append_basic(&dict, "DeviceName", + DBUS_TYPE_STRING, &config->device_name); - supplicant_dbus_dict_append_basic(dict, "proto", - DBUS_TYPE_STRING, - &proto); + if (config->dev_type) { + unsigned char dev_type[8] = {}, *type; + int len; - g_free(proto); + len = dev_type_str2bin(config->dev_type, dev_type); + if (len) { + type = dev_type; + supplicant_dbus_dict_append_fixed_array(&dict, + "PrimaryDeviceType", + DBUS_TYPE_BYTE, &type, len); + } + } + + supplicant_dbus_dict_close(iter, &dict); } -static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid) +int g_supplicant_interface_set_p2p_device_config(GSupplicantInterface *interface, + const char *device_name, + const char *primary_dev_type) { - char *key_mgmt; + struct supplicant_p2p_dev_config *config; + int ret; - switch (ssid->security) { - case G_SUPPLICANT_SECURITY_UNKNOWN: - case G_SUPPLICANT_SECURITY_NONE: - case G_SUPPLICANT_SECURITY_WEP: - key_mgmt = "NONE"; - add_network_security_wep(dict, ssid); - add_network_security_ciphers(dict, ssid); - break; - case G_SUPPLICANT_SECURITY_PSK: - key_mgmt = "WPA-PSK"; - add_network_security_psk(dict, ssid); - add_network_security_ciphers(dict, ssid); - add_network_security_proto(dict, ssid); - break; - case G_SUPPLICANT_SECURITY_IEEE8021X: - key_mgmt = "WPA-EAP"; - add_network_security_eap(dict, ssid); - add_network_security_ciphers(dict, ssid); - add_network_security_proto(dict, ssid); - break; + SUPPLICANT_DBG("P2P Device settings %s/%s", + device_name, primary_dev_type); + + config = dbus_malloc0(sizeof(*config)); + if (!config) + return -ENOMEM; + + config->device_name = g_strdup(device_name); + config->dev_type = g_strdup(primary_dev_type); + + ret = supplicant_dbus_property_set(interface->path, + SUPPLICANT_INTERFACE ".Interface.P2PDevice", + "P2PDeviceConfig", + DBUS_TYPE_ARRAY_AS_STRING + DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING + DBUS_TYPE_STRING_AS_STRING + DBUS_TYPE_VARIANT_AS_STRING + DBUS_DICT_ENTRY_END_CHAR_AS_STRING, + p2p_device_config_params, + p2p_device_config_result, config, NULL); + if (ret < 0) { + g_free(config->device_name); + g_free(config->dev_type); + dbus_free(config); + SUPPLICANT_DBG("Unable to set P2P Device configuration"); } - supplicant_dbus_dict_append_basic(dict, "key_mgmt", - DBUS_TYPE_STRING, &key_mgmt); + return ret; } -static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid) +static gboolean peer_lookup_by_identifier(gpointer key, gpointer value, + gpointer user_data) { - dbus_uint32_t mode; + const GSupplicantPeer *peer = value; + const char *identifier = user_data; - switch (ssid->mode) { - case G_SUPPLICANT_MODE_UNKNOWN: - case G_SUPPLICANT_MODE_INFRA: - mode = 0; - break; - case G_SUPPLICANT_MODE_IBSS: - mode = 1; - break; - case G_SUPPLICANT_MODE_MASTER: - mode = 2; - break; - } + if (!g_strcmp0(identifier, peer->identifier)) + return TRUE; + + return FALSE; +} + +GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interface, + const char *identifier) +{ + GSupplicantPeer *peer; + + peer = g_hash_table_find(interface->peer_table, + peer_lookup_by_identifier, + (void *) identifier); + return peer; +} + +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); +} + +static bool interface_exists(GSupplicantInterface *interface, + const char *path) +{ + GSupplicantInterface *tmp; + + tmp = g_hash_table_lookup(interface_table, path); + if (tmp && tmp == interface) + return true; + + return false; +} + +static void interface_create_property(const char *key, DBusMessageIter *iter, + void *user_data) +{ + struct interface_create_data *data = user_data; + GSupplicantInterface *interface = data->interface; + + if (!key) { + if (data->callback) { + data->callback(0, data->interface, data->user_data); +#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); + } + + interface_property(key, iter, interface); +} + +static void interface_create_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_create_data *data = user_data; + const char *path = NULL; + int err; + + SUPPLICANT_DBG(""); + + if (error) { + g_warning("error %s", error); + err = -EIO; + goto done; + } + + dbus_message_iter_get_basic(iter, &path); + if (!path) { + err = -EINVAL; + goto done; + } + + if (!system_available) { + err = -EFAULT; + goto done; + } + + data->interface = g_hash_table_lookup(interface_table, path); + if (!data->interface) { + data->interface = interface_alloc(path); + if (!data->interface) { + err = -ENOMEM; + goto done; + } + } + + err = supplicant_dbus_property_get_all(path, + SUPPLICANT_INTERFACE ".Interface", + interface_create_property, data, + NULL); + if (err == 0) + return; + +done: + if (data->callback) + data->callback(err, NULL, data->user_data); + + interface_create_data_free(data); +} + +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(""); + + supplicant_dbus_dict_open(iter, &dict); + + supplicant_dbus_dict_append_basic(&dict, "Ifname", + DBUS_TYPE_STRING, &data->ifname); + + if (data->driver) + supplicant_dbus_dict_append_basic(&dict, "Driver", + DBUS_TYPE_STRING, &data->driver); + + if (data->bridge) + 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); +} + +static void interface_get_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_create_data *data = user_data; + GSupplicantInterface *interface; + const char *path = NULL; + int err; + + SUPPLICANT_DBG(""); + + if (error) { + SUPPLICANT_DBG("Interface not created yet"); + goto create; + } + + dbus_message_iter_get_basic(iter, &path); + if (!path) { + err = -EINVAL; + goto done; + } + + interface = g_hash_table_lookup(interface_table, path); + if (!interface) { + err = -ENOENT; + goto done; + } + + if (data->callback) { + data->callback(0, interface, data->user_data); +#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); + + return; + +create: + if (!system_available) { + err = -EFAULT; + goto done; + } + + SUPPLICANT_DBG("Creating interface"); + + err = supplicant_dbus_method_call(SUPPLICANT_PATH, + SUPPLICANT_INTERFACE, + "CreateInterface", + interface_create_params, + interface_create_result, data, + NULL); + if (err == 0) + return; + +done: + if (data->callback) + data->callback(err, NULL, data->user_data); + + interface_create_data_free(data); +} + +static void interface_get_params(DBusMessageIter *iter, void *user_data) +{ + struct interface_create_data *data = user_data; + + SUPPLICANT_DBG(""); + + 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, + void *user_data) +{ + struct interface_create_data *data; + int ret; + + SUPPLICANT_DBG("ifname %s", ifname); + + if (!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->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(SUPPLICANT_PATH, + SUPPLICANT_INTERFACE, + "GetInterface", + interface_get_params, + interface_get_result, data, + NULL); + if (ret < 0) + interface_create_data_free(data); + + return ret; +} + +static void interface_remove_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_data *data = user_data; + int err; + + if (error) { + err = -EIO; + SUPPLICANT_DBG("error: %s", error); + goto done; + } + + if (!system_available) { + err = -EFAULT; + goto done; + } + + /* + * The gsupplicant interface is already freed by the InterfaceRemoved + * signal callback. Simply invoke the interface_data callback. + */ + err = 0; + +done: + g_free(data->path); + + if (data->callback) + data->callback(err, NULL, data->user_data); + + dbus_free(data); +} + + +static void interface_remove_params(DBusMessageIter *iter, void *user_data) +{ + struct interface_data *data = user_data; + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, + &data->interface->path); +} + + +int g_supplicant_interface_remove(GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, + void *user_data) +{ + struct interface_data *data; + int ret; + + if (!interface) + return -EINVAL; + + if (!system_available) + return -EFAULT; + + g_supplicant_interface_cancel(interface); + + 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(SUPPLICANT_PATH, + SUPPLICANT_INTERFACE, + "RemoveInterface", + interface_remove_params, + interface_remove_result, data, + NULL); + if (ret < 0) { + g_free(data->path); + dbus_free(data); + } + return ret; +} + +static void interface_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; + } + + /* A non ready interface cannot send/receive anything */ + if (interface_exists(data->interface, data->path)) { + if (!data->interface->ready) + err = -ENOLINK; + } + + g_free(data->path); + + if (err != 0) { + if (data->callback) + data->callback(err, data->interface, data->user_data); + } else { + data->interface->scan_callback = data->callback; + data->interface->scan_data = data->user_data; + } + + if (data->scan_params) + g_supplicant_free_scan_params(data->scan_params); + + dbus_free(data); +} + +static void add_scan_frequency(DBusMessageIter *iter, unsigned int freq) +{ + DBusMessageIter data; + unsigned int width = 0; /* Not used by wpa_supplicant atm */ + + dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &data); + + dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &freq); + dbus_message_iter_append_basic(&data, DBUS_TYPE_UINT32, &width); + + dbus_message_iter_close_container(iter, &data); +} + +static void add_scan_frequencies(DBusMessageIter *iter, + void *user_data) +{ + GSupplicantScanParams *scan_data = user_data; + unsigned int freq; + int i; + + for (i = 0; i < scan_data->num_freqs; i++) { + freq = scan_data->freqs[i]; + if (!freq) + break; + + add_scan_frequency(iter, freq); + } +} + +static void append_ssid(DBusMessageIter *iter, + const void *ssid, unsigned int len) +{ + DBusMessageIter array; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); + + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &ssid, len); + dbus_message_iter_close_container(iter, &array); +} + +static void append_ssids(DBusMessageIter *iter, void *user_data) +{ + GSupplicantScanParams *scan_data = user_data; + GSList *list; + + for (list = scan_data->ssids; list; list = list->next) { + struct scan_ssid *scan_ssid = list->data; + + append_ssid(iter, scan_ssid->ssid, scan_ssid->ssid_len); + } +} + +static void supplicant_add_scan_frequency(DBusMessageIter *dict, + supplicant_dbus_array_function function, + void *user_data) +{ + GSupplicantScanParams *scan_params = user_data; + DBusMessageIter entry, value, array; + const char *key = "Channels"; + + if (scan_params->freqs && scan_params->freqs[0] != 0) { + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, + DBUS_TYPE_ARRAY_AS_STRING + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING, + &value); + + dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, + DBUS_STRUCT_BEGIN_CHAR_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_TYPE_UINT32_AS_STRING + DBUS_STRUCT_END_CHAR_AS_STRING, + &array); + + if (function) + function(&array, user_data); + + dbus_message_iter_close_container(&value, &array); + dbus_message_iter_close_container(&entry, &value); + dbus_message_iter_close_container(dict, &entry); + } +} + +static void interface_scan_params(DBusMessageIter *iter, void *user_data) +{ + DBusMessageIter dict; + const char *type = "passive"; + struct interface_scan_data *data = user_data; + + supplicant_dbus_dict_open(iter, &dict); + + if (data && data->scan_params) { + type = "active"; + + supplicant_dbus_dict_append_basic(&dict, "Type", + DBUS_TYPE_STRING, &type); + +#if defined TIZEN_EXT + SUPPLICANT_DBG("[specific_scan] num_ssids %d", data->scan_params->num_ssids); + if (data->scan_params->num_ssids != 0) +#endif + supplicant_dbus_dict_append_array(&dict, "SSIDs", + DBUS_TYPE_STRING, + append_ssids, + data->scan_params); + + supplicant_add_scan_frequency(&dict, add_scan_frequencies, + data->scan_params); + } else + supplicant_dbus_dict_append_basic(&dict, "Type", + DBUS_TYPE_STRING, &type); + + supplicant_dbus_dict_close(iter, &dict); +} + +static int interface_ready_to_scan(GSupplicantInterface *interface) +{ + if (!interface) + return -EINVAL; + + if (!system_available) + return -EFAULT; + + if (interface->scanning) + return -EALREADY; + + switch (interface->state) { + case G_SUPPLICANT_STATE_AUTHENTICATING: + case G_SUPPLICANT_STATE_ASSOCIATING: + case G_SUPPLICANT_STATE_ASSOCIATED: + case G_SUPPLICANT_STATE_4WAY_HANDSHAKE: + case G_SUPPLICANT_STATE_GROUP_HANDSHAKE: + return -EBUSY; +#if defined TIZEN_EXT + case G_SUPPLICANT_STATE_DISABLED: + return -ENOLINK; + case G_SUPPLICANT_STATE_UNKNOWN: +#else + case G_SUPPLICANT_STATE_UNKNOWN: + case G_SUPPLICANT_STATE_DISABLED: +#endif + case G_SUPPLICANT_STATE_DISCONNECTED: + case G_SUPPLICANT_STATE_INACTIVE: + case G_SUPPLICANT_STATE_SCANNING: + case G_SUPPLICANT_STATE_COMPLETED: + break; + } + + 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_signalpoll(GSupplicantInterface *interface, + GSupplicantMaxSpeedCallback callback, + void *user_data) +{ + struct interface_signalpoll_data *data; + int ret; + + if (!interface) + return -EINVAL; + + if (!system_available) + return -EFAULT; + + 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", "SignalPoll", + NULL, interface_signalpoll_result, data, + interface); + + if (ret < 0) { + g_free(data->path); + dbus_free(data); + } + + return ret; +} +#endif + +static int parse_supplicant_error(DBusMessageIter *iter) +{ + int err = -ECONNABORTED; + char *key; + + if (!iter) + return err; + + /* If the given passphrase is malformed wpa_s returns + * "invalid message format" but this error should be interpreted as + * invalid-key. + */ + while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) { + dbus_message_iter_get_basic(iter, &key); + if (strncmp(key, "psk", 3) == 0 || + strncmp(key, "wep_key", 7) == 0 || + strcmp(key, "invalid message format") == 0) { + err = -ENOKEY; + break; + } + dbus_message_iter_next(iter); + } + + return err; +} + +static void interface_select_network_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_connect_data *data = user_data; + int err; + + SUPPLICANT_DBG(""); + + err = 0; + if (error) { +#if defined TIZEN_EXT + SUPPLICANT_DBG("SelectNetwork errorFreq %s", error); +#else + SUPPLICANT_DBG("SelectNetwork error %s", error); +#endif + err = parse_supplicant_error(iter); + } + + g_free(data->path); + + 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); +} + +static void interface_select_network_params(DBusMessageIter *iter, + void *user_data) +{ + struct interface_connect_data *data = user_data; + GSupplicantInterface *interface = data->interface; +#if defined TIZEN_EXT + GSupplicantSSID *ssid = data->ssid; +#endif + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, + &interface->network_path); +#if defined TIZEN_EXT + if (!ssid->bssid_for_connect_len) + dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &ssid->freq); +#endif +} + +static void interface_add_network_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_connect_data *data = user_data; + GSupplicantInterface *interface = data->interface; + const char *path; + int err; + + if (error) + goto error; + + dbus_message_iter_get_basic(iter, &path); + if (!path) + goto error; + + SUPPLICANT_DBG("PATH: %s", 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"); + GSupplicantSSID *ssid = data->ssid; + + 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", + interface_select_network_params, + interface_select_network_result, data, + interface); +#endif + + return; + +error: + SUPPLICANT_DBG("AddNetwork error %s", error); + + if (interface_exists(data->interface, data->interface->path)) { + err = parse_supplicant_error(iter); + if (data->callback) + data->callback(err, data->interface, data->user_data); + + g_free(interface->network_path); + interface->network_path = NULL; + } + + 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); +} + +static void add_network_security_none(DBusMessageIter *dict) +{ + const char *auth_alg = "OPEN"; + + supplicant_dbus_dict_append_basic(dict, "auth_alg", + DBUS_TYPE_STRING, &auth_alg); +} + +static void add_network_security_wep(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + const char *auth_alg = "OPEN SHARED"; + dbus_uint32_t key_index = 0; + + supplicant_dbus_dict_append_basic(dict, "auth_alg", + DBUS_TYPE_STRING, &auth_alg); + + if (ssid->passphrase) { + int size = strlen(ssid->passphrase); + if (size == 10 || size == 26) { + unsigned char *key = g_try_malloc(13); + char tmp[3]; + int i; + + memset(tmp, 0, sizeof(tmp)); + if (!key) + size = 0; + + for (i = 0; i < size / 2; i++) { + memcpy(tmp, ssid->passphrase + (i * 2), 2); + key[i] = (unsigned char) strtol(tmp, NULL, 16); + } + + supplicant_dbus_dict_append_fixed_array(dict, + "wep_key0", + DBUS_TYPE_BYTE, + &key, size / 2); + g_free(key); + } else if (size == 5 || size == 13) { + unsigned char *key = g_try_malloc(13); + int i; + + if (!key) + size = 0; + + for (i = 0; i < size; i++) + key[i] = (unsigned char) ssid->passphrase[i]; + + supplicant_dbus_dict_append_fixed_array(dict, + "wep_key0", + DBUS_TYPE_BYTE, + &key, size); + g_free(key); + } else + supplicant_dbus_dict_append_basic(dict, + "wep_key0", + DBUS_TYPE_STRING, + &ssid->passphrase); + + supplicant_dbus_dict_append_basic(dict, "wep_tx_keyidx", + DBUS_TYPE_UINT32, &key_index); + } +} + +static dbus_bool_t is_psk_raw_key(const char *psk) +{ + int i; + + /* A raw key is always 64 bytes length... */ + if (strlen(psk) != 64) + return FALSE; + + /* ... and its content is in hex representation */ + for (i = 0; i < 64; i++) + if (!isxdigit((unsigned char) psk[i])) + return FALSE; + + return TRUE; +} + +static unsigned char hexchar2bin(char c) +{ + if ((c >= '0') && (c <= '9')) + return c - '0'; + else if ((c >= 'A') && (c <= 'F')) + return c - 'A' + 10; + else if ((c >= 'a') && (c <= 'f')) + return c - 'a' + 10; + else + return c; +} + +static void hexstring2bin(const char *string, unsigned char *data, + size_t data_len) +{ + size_t i; + + for (i = 0; i < data_len; i++) + data[i] = (hexchar2bin(string[i * 2 + 0]) << 4 | + hexchar2bin(string[i * 2 + 1]) << 0); +} + +static void add_network_security_psk(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + if (ssid->passphrase && strlen(ssid->passphrase) > 0) { + const char *key = "psk"; + + if (is_psk_raw_key(ssid->passphrase)) { + unsigned char data[32]; + unsigned char *datap = data; + + /* The above pointer alias is required by D-Bus because + * with D-Bus and GCC, non-heap-allocated arrays cannot + * be passed directly by their base pointer. */ + + hexstring2bin(ssid->passphrase, datap, sizeof(data)); + + supplicant_dbus_dict_append_fixed_array(dict, + key, DBUS_TYPE_BYTE, + &datap, sizeof(data)); + } else + supplicant_dbus_dict_append_basic(dict, + key, DBUS_TYPE_STRING, + &ssid->passphrase); + } +} + +static void add_network_security_tls(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + /* + * For TLS, we at least need: + * The client certificate + * The client private key file + * The client private key file password + * + * The Authority certificate is optional. + */ + if (!ssid->client_cert_path) + return; + + if (!ssid->private_key_path) + return; + +#if !defined TIZEN_EXT + if (!ssid->private_key_passphrase) + return; +#endif + + if (ssid->ca_cert_path) + supplicant_dbus_dict_append_basic(dict, "ca_cert", + DBUS_TYPE_STRING, &ssid->ca_cert_path); + + supplicant_dbus_dict_append_basic(dict, "private_key", + DBUS_TYPE_STRING, + &ssid->private_key_path); +#if !defined TIZEN_EXT + supplicant_dbus_dict_append_basic(dict, "private_key_passwd", + DBUS_TYPE_STRING, + &ssid->private_key_passphrase); +#endif + supplicant_dbus_dict_append_basic(dict, "client_cert", + DBUS_TYPE_STRING, + &ssid->client_cert_path); +} + +static void add_network_security_peap(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + char *phase2_auth; + + /* + * For PEAP/TTLS, we at least need + * The authority certificate + * The 2nd phase authentication method + * The 2nd phase passphrase + * + * The Client certificate is optional although strongly recommended + * When setting it, we need in addition + * The Client private key file + * The Client private key file password + */ + if (!ssid->passphrase) + return; + + if (!ssid->phase2_auth) + return; + + if (ssid->client_cert_path) { + if (!ssid->private_key_path) + return; + +#if !defined TIZEN_EXT + if (!ssid->private_key_passphrase) + return; +#endif + + supplicant_dbus_dict_append_basic(dict, "client_cert", + DBUS_TYPE_STRING, + &ssid->client_cert_path); + + supplicant_dbus_dict_append_basic(dict, "private_key", + DBUS_TYPE_STRING, + &ssid->private_key_path); + +#if !defined TIZEN_EXT + supplicant_dbus_dict_append_basic(dict, "private_key_passwd", + DBUS_TYPE_STRING, + &ssid->private_key_passphrase); +#endif + + } + + if (g_str_has_prefix(ssid->phase2_auth, "EAP-")) { + phase2_auth = g_strdup_printf("autheap=%s", + ssid->phase2_auth + strlen("EAP-")); + } else + phase2_auth = g_strdup_printf("auth=%s", ssid->phase2_auth); + + supplicant_dbus_dict_append_basic(dict, "password", + DBUS_TYPE_STRING, + &ssid->passphrase); + + if (ssid->ca_cert_path) + supplicant_dbus_dict_append_basic(dict, "ca_cert", + DBUS_TYPE_STRING, + &ssid->ca_cert_path); + + supplicant_dbus_dict_append_basic(dict, "phase2", + DBUS_TYPE_STRING, + &phase2_auth); + + g_free(phase2_auth); +} + +#if defined TIZEN_EXT +static void add_network_security_aka_sim(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + if (!ssid->passphrase) + return; + + supplicant_dbus_dict_append_basic(dict, "password", + 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, + GSupplicantSSID *ssid) +{ + char *eap_value; + +#if defined TIZEN_EXT + if (!ssid->eap) +#else + if (!ssid->eap || !ssid->identity) +#endif + return; + + if (g_strcmp0(ssid->eap, "tls") == 0) { + add_network_security_tls(dict, ssid); + } else if (g_strcmp0(ssid->eap, "peap") == 0 || + g_strcmp0(ssid->eap, "ttls") == 0) { +#if defined TIZEN_EXT + if (!ssid->identity) + return; +#endif + add_network_security_peap(dict, ssid); + +#if defined TIZEN_EXT + } else if (g_strcmp0(ssid->eap, "sim") == 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; + + eap_value = g_ascii_strup(ssid->eap, -1); + + supplicant_dbus_dict_append_basic(dict, "eap", + DBUS_TYPE_STRING, + &eap_value); +#if defined TIZEN_EXT + if (ssid->identity != NULL) + supplicant_dbus_dict_append_basic(dict, "identity", + DBUS_TYPE_STRING, + &ssid->identity); +#else + supplicant_dbus_dict_append_basic(dict, "identity", + 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); +} + +static void add_network_security_ciphers(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + unsigned int p_cipher, g_cipher, i; + char *pairwise, *group; + char *pair_ciphers[4]; + char *group_ciphers[5]; + + p_cipher = ssid->pairwise_cipher; + g_cipher = ssid->group_cipher; + + if (p_cipher == 0 && g_cipher == 0) + return; + + i = 0; + + if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP) + pair_ciphers[i++] = "CCMP"; + + if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP) + pair_ciphers[i++] = "TKIP"; + + if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE) + pair_ciphers[i++] = "NONE"; + + pair_ciphers[i] = NULL; + + i = 0; + + if (g_cipher & G_SUPPLICANT_GROUP_CCMP) + group_ciphers[i++] = "CCMP"; + + if (g_cipher & G_SUPPLICANT_GROUP_TKIP) + group_ciphers[i++] = "TKIP"; + + if (g_cipher & G_SUPPLICANT_GROUP_WEP104) + group_ciphers[i++] = "WEP104"; + + if (g_cipher & G_SUPPLICANT_GROUP_WEP40) + group_ciphers[i++] = "WEP40"; + + group_ciphers[i] = NULL; + + pairwise = g_strjoinv(" ", pair_ciphers); + group = g_strjoinv(" ", group_ciphers); + + SUPPLICANT_DBG("cipher %s %s", pairwise, group); + + supplicant_dbus_dict_append_basic(dict, "pairwise", + DBUS_TYPE_STRING, + &pairwise); + supplicant_dbus_dict_append_basic(dict, "group", + DBUS_TYPE_STRING, + &group); + + g_free(pairwise); + g_free(group); +} + +static void add_network_security_proto(DBusMessageIter *dict, + GSupplicantSSID *ssid) +{ + unsigned int protocol, i; + char *proto; + char *protos[3]; + + protocol = ssid->protocol; + + if (protocol == 0) + return; + + i = 0; + + if (protocol & G_SUPPLICANT_PROTO_RSN) + protos[i++] = "RSN"; + + if (protocol & G_SUPPLICANT_PROTO_WPA) + protos[i++] = "WPA"; + + protos[i] = NULL; + + proto = g_strjoinv(" ", protos); + + SUPPLICANT_DBG("proto %s", proto); + + supplicant_dbus_dict_append_basic(dict, "proto", + DBUS_TYPE_STRING, + &proto); + + g_free(proto); +} + +#if defined TIZEN_EXT_WIFI_MESH +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; + + switch (ssid->security) { + case G_SUPPLICANT_SECURITY_NONE: + key_mgmt = "NONE"; + add_network_security_none(dict); + add_network_security_ciphers(dict, ssid); + break; + case G_SUPPLICANT_SECURITY_UNKNOWN: + case G_SUPPLICANT_SECURITY_WEP: + key_mgmt = "NONE"; + add_network_security_wep(dict, ssid); + add_network_security_ciphers(dict, ssid); + break; + case G_SUPPLICANT_SECURITY_PSK: + key_mgmt = "WPA-PSK"; + add_network_security_psk(dict, ssid); + add_network_security_ciphers(dict, ssid); + add_network_security_proto(dict, ssid); + break; + case G_SUPPLICANT_SECURITY_IEEE8021X: + key_mgmt = "WPA-EAP"; + add_network_security_eap(dict, ssid); + add_network_security_ciphers(dict, ssid); + add_network_security_proto(dict, ssid); + break; +#if defined TIZEN_EXT + case G_SUPPLICANT_SECURITY_FT_PSK: + key_mgmt = "FT-PSK"; + add_network_security_psk(dict, ssid); + add_network_security_ciphers(dict, ssid); + add_network_security_proto(dict, ssid); + break; + case G_SUPPLICANT_SECURITY_FT_IEEE8021X: + key_mgmt = "FT-EAP"; + add_network_security_eap(dict, ssid); + add_network_security_ciphers(dict, ssid); + add_network_security_proto(dict, ssid); + break; +#endif +#if defined TIZEN_EXT_WIFI_MESH + case G_SUPPLICANT_SECURITY_SAE: + key_mgmt = "SAE"; + add_network_security_psk(dict, ssid); + break; +#endif + } + + supplicant_dbus_dict_append_basic(dict, "key_mgmt", + DBUS_TYPE_STRING, &key_mgmt); +} + +static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid) +{ + dbus_uint32_t mode; + + switch (ssid->mode) { + case G_SUPPLICANT_MODE_UNKNOWN: + case G_SUPPLICANT_MODE_INFRA: + mode = 0; + break; + case G_SUPPLICANT_MODE_IBSS: + mode = 1; + break; + 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", + DBUS_TYPE_UINT32, &mode); +} + +static void interface_add_network_params(DBusMessageIter *iter, void *user_data) +{ + DBusMessageIter dict; + struct interface_connect_data *data = user_data; + GSupplicantSSID *ssid = data->ssid; + + supplicant_dbus_dict_open(iter, &dict); + + if (ssid->scan_ssid) + supplicant_dbus_dict_append_basic(&dict, "scan_ssid", + DBUS_TYPE_UINT32, &ssid->scan_ssid); + + if (ssid->freq) + supplicant_dbus_dict_append_basic(&dict, "frequency", + DBUS_TYPE_UINT32, &ssid->freq); + + if (ssid->bgscan) + supplicant_dbus_dict_append_basic(&dict, "bgscan", + DBUS_TYPE_STRING, &ssid->bgscan); + + add_network_mode(&dict, ssid); + + add_network_security(&dict, ssid); + +#if defined TIZEN_EXT_WIFI_MESH + add_network_ieee80211w(&dict, ssid); +#endif + + supplicant_dbus_dict_append_fixed_array(&dict, "ssid", + DBUS_TYPE_BYTE, &ssid->ssid, + ssid->ssid_len); + + supplicant_dbus_dict_append_basic(&dict, "ignore_broadcast_ssid", + DBUS_TYPE_INT32, + &ssid->ignore_broadcast_ssid); + +#if defined TIZEN_EXT + if (ssid->bssid) { + char *bssid = NULL; + bssid = g_try_malloc0(18); + if (bssid == NULL) { + SUPPLICANT_DBG("memory allocation error"); + supplicant_dbus_dict_close(iter, &dict); + return; + } + + 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); + } +#endif + + supplicant_dbus_dict_close(iter, &dict); +} + +static void interface_wps_start_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_connect_data *data = user_data; + int err; + + SUPPLICANT_DBG(""); + + err = 0; + if (error) { + SUPPLICANT_DBG("error: %s", error); + err = parse_supplicant_error(iter); + } + + if(data->callback) + data->callback(err, data->interface, data->user_data); + + g_free(data->path); + g_free(data->ssid); + dbus_free(data); +} + +static void interface_add_wps_params(DBusMessageIter *iter, void *user_data) +{ + struct interface_connect_data *data = user_data; + GSupplicantSSID *ssid = data->ssid; + const char *role = "enrollee", *type; + DBusMessageIter dict; + + SUPPLICANT_DBG(""); + + supplicant_dbus_dict_open(iter, &dict); + + supplicant_dbus_dict_append_basic(&dict, "Role", + DBUS_TYPE_STRING, &role); + + type = "pbc"; + if (ssid->pin_wps) { + type = "pin"; + supplicant_dbus_dict_append_basic(&dict, "Pin", + DBUS_TYPE_STRING, &ssid->pin_wps); + } + + supplicant_dbus_dict_append_basic(&dict, "Type", + DBUS_TYPE_STRING, &type); + +#if defined TIZEN_EXT + if (ssid->bssid) + supplicant_dbus_dict_append_fixed_array(&dict, "Bssid", + DBUS_TYPE_BYTE, &ssid->bssid, 6); +#endif + + supplicant_dbus_dict_close(iter, &dict); +} + +static void wps_start(const char *error, DBusMessageIter *iter, void *user_data) +{ + struct interface_connect_data *data = user_data; + + SUPPLICANT_DBG(""); + + if (error) { + SUPPLICANT_DBG("error: %s", error); + g_free(data->path); + g_free(data->ssid); + dbus_free(data); + return; + } +#if defined TIZEN_EXT + GSupplicantSSID *ssid = data->ssid; + if (ssid->pin_wps != NULL) { + if (!g_utf8_validate(ssid->pin_wps, 8, NULL)) { + SUPPLICANT_DBG("Invalid characters in WPS_PIN"); + g_free(data->ssid); + dbus_free(data); + return; + } + } +#endif + supplicant_dbus_method_call(data->interface->path, + SUPPLICANT_INTERFACE ".Interface.WPS", "Start", + interface_add_wps_params, + interface_wps_start_result, data, NULL); +} + +static void wps_process_credentials(DBusMessageIter *iter, void *user_data) +{ + dbus_bool_t credentials = TRUE; + + SUPPLICANT_DBG(""); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials); +} + + +#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; + struct interface_data *intf_data; + int ret = 0; + + SUPPLICANT_DBG(""); + + if (!interface) + return -EINVAL; + + if (!system_available) + return -EFAULT; + + /* TODO: Check if we're already connected and switch */ + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->interface = interface; + data->path = g_strdup(interface->path); + data->callback = callback; + data->ssid = ssid; + data->user_data = user_data; + + if (ssid->use_wps) { + g_free(interface->wps_cred.key); + memset(&interface->wps_cred, 0, + sizeof(struct _GSupplicantWpsCredentials)); + + ret = supplicant_dbus_property_set(interface->path, + SUPPLICANT_INTERFACE ".Interface.WPS", + "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING, + wps_process_credentials, wps_start, 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); + dbus_free(data); + return ret; + } + + return -EINPROGRESS; +} + +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->interface->network_path); + data->interface->network_path = NULL; + + 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); +} + +static void network_remove_params(DBusMessageIter *iter, void *user_data) +{ + struct interface_data *data = user_data; + const char *path = data->interface->network_path; + + SUPPLICANT_DBG("path %s", path); + + dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); +} + +static int network_remove(struct interface_data *data) +{ + GSupplicantInterface *interface = data->interface; + + SUPPLICANT_DBG(""); + +#if defined TIZEN_EXT + GSupplicantInterface *intf = NULL; + /* + * Check if 'interface' is valid + */ + intf = g_hash_table_lookup(interface_table, interface->path); + if (intf == NULL) + return -EINVAL; +#endif + + return supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork", + network_remove_params, network_remove_result, data, + interface); +} + +static void interface_disconnect_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_data *data = user_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; + } + + /* 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); + dbus_free(data); + } + } else { + g_free(data->path); + dbus_free(data); + } +} + +int g_supplicant_interface_disconnect(GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, + void *user_data) +{ + struct interface_data *data; + int ret; + + SUPPLICANT_DBG(""); + + if (!interface) + return -EINVAL; + + 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; + + 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", "Disconnect", + NULL, interface_disconnect_result, data, + interface); + + if (ret < 0) { + g_free(data->path); + dbus_free(data); + } + + return ret; +} + +static void interface_p2p_find_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct interface_scan_data *data = user_data; + int err = 0; + + SUPPLICANT_DBG("error %s", error); + + if (error) + err = -EIO; + + if (interface_exists(data->interface, data->path)) { + if (!data->interface->ready) + err = -ENOLINK; + if (!err) + data->interface->p2p_finding = true; + } + + if (data->callback) + data->callback(err, data->interface, data->user_data); + + g_free(data->path); + dbus_free(data); +} + +static void interface_p2p_find_params(DBusMessageIter *iter, void *user_data) +{ + DBusMessageIter dict; + + supplicant_dbus_dict_open(iter, &dict); + supplicant_dbus_dict_close(iter, &dict); +} + +int g_supplicant_interface_p2p_find(GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, + void *user_data) +{ + struct interface_scan_data *data; + int ret; + + if (!interface->p2p_support) + return -ENOTSUP; - supplicant_dbus_dict_append_basic(dict, "mode", - DBUS_TYPE_UINT32, &mode); -} + ret = interface_ready_to_scan(interface); + if (ret && ret != -EALREADY) + return ret; -static void interface_add_network_params(DBusMessageIter *iter, void *user_data) -{ - DBusMessageIter dict; - struct interface_connect_data *data = user_data; - GSupplicantSSID *ssid = data->ssid; + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; - supplicant_dbus_dict_open(iter, &dict); + data->interface = interface; + data->path = g_strdup(interface->path); + data->callback = callback; + data->user_data = user_data; - if (ssid->scan_ssid) - supplicant_dbus_dict_append_basic(&dict, "scan_ssid", - DBUS_TYPE_UINT32, &ssid->scan_ssid); + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface.P2PDevice", "Find", + interface_p2p_find_params, interface_p2p_find_result, + data, interface); + if (ret < 0) { + g_free(data->path); + dbus_free(data); + } - if (ssid->freq) - supplicant_dbus_dict_append_basic(&dict, "frequency", - DBUS_TYPE_UINT32, &ssid->freq); + return ret; +} - if (ssid->bgscan != NULL) - supplicant_dbus_dict_append_basic(&dict, "bgscan", - DBUS_TYPE_STRING, &ssid->bgscan); +bool g_supplicant_interface_is_p2p_finding(GSupplicantInterface *interface) +{ + if (!interface) + return false; - add_network_mode(&dict, ssid); + return interface->p2p_finding; +} - add_network_security(&dict, ssid); +int g_supplicant_interface_p2p_stop_find(GSupplicantInterface *interface) +{ + if (!interface->p2p_finding) + return 0; - supplicant_dbus_dict_append_fixed_array(&dict, "ssid", - DBUS_TYPE_BYTE, &ssid->ssid, - ssid->ssid_len); + SUPPLICANT_DBG(""); - supplicant_dbus_dict_close(iter, &dict); + interface->p2p_finding = false; + + return supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface.P2PDevice", "StopFind", + NULL, NULL, NULL, NULL); } -static void interface_wps_start_result(const char *error, - DBusMessageIter *iter, void *user_data) +static void interface_p2p_connect_result(const char *error, + DBusMessageIter *iter, void *user_data) { struct interface_connect_data *data = user_data; + int err = 0; SUPPLICANT_DBG(""); - if (error != NULL) + + if (error) { SUPPLICANT_DBG("error: %s", error); + err = parse_supplicant_error(iter); + } - g_free(data->ssid); - dbus_free(data); + if (data->callback) + data->callback(err, data->interface, data->user_data); + + g_free(data->path); + g_free(data->peer->wps_pin); + g_free(data->peer->path); + g_free(data->peer); + g_free(data); } -static void interface_add_wps_params(DBusMessageIter *iter, void *user_data) +static void interface_p2p_connect_params(DBusMessageIter *iter, void *user_data) { struct interface_connect_data *data = user_data; - GSupplicantSSID *ssid = data->ssid; - const char *role = "enrollee", *type; + const char *wps = "pbc"; DBusMessageIter dict; + int go_intent = 7; SUPPLICANT_DBG(""); supplicant_dbus_dict_open(iter, &dict); - supplicant_dbus_dict_append_basic(&dict, "Role", - DBUS_TYPE_STRING, &role); + if (data->peer->master) + go_intent = 15; - type = "pbc"; - if (ssid->pin_wps != NULL) { - type = "pin"; - supplicant_dbus_dict_append_basic(&dict, "Pin", - DBUS_TYPE_STRING, &ssid->pin_wps); + if (data->peer->wps_pin) + wps = "pin"; + + supplicant_dbus_dict_append_basic(&dict, "peer", + DBUS_TYPE_OBJECT_PATH, &data->peer->path); + supplicant_dbus_dict_append_basic(&dict, "wps_method", + DBUS_TYPE_STRING, &wps); + if (data->peer->wps_pin) { + supplicant_dbus_dict_append_basic(&dict, "pin", + DBUS_TYPE_STRING, &data->peer->wps_pin); } - supplicant_dbus_dict_append_basic(&dict, "Type", - DBUS_TYPE_STRING, &type); + supplicant_dbus_dict_append_basic(&dict, "go_intent", + DBUS_TYPE_INT32, &go_intent); supplicant_dbus_dict_close(iter, &dict); } -static void wps_start(const char *error, DBusMessageIter *iter, void *user_data) +int g_supplicant_interface_p2p_connect(GSupplicantInterface *interface, + GSupplicantPeerParams *peer_params, + GSupplicantInterfaceCallback callback, + void *user_data) { - struct interface_connect_data *data = user_data; + struct interface_connect_data *data; + int ret; SUPPLICANT_DBG(""); - if (error != NULL) { - SUPPLICANT_DBG("error: %s", error); - g_free(data->ssid); + if (!interface->p2p_support) + return -ENOTSUP; + + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->interface = interface; + data->path = g_strdup(interface->path); + data->peer = peer_params; + data->callback = callback; + data->user_data = user_data; + + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface.P2PDevice", "Connect", + interface_p2p_connect_params, interface_p2p_connect_result, + data, interface); + if (ret < 0) { + g_free(data->path); dbus_free(data); - return; + return ret; } - supplicant_dbus_method_call(data->interface->path, - SUPPLICANT_INTERFACE ".Interface.WPS", "Start", - interface_add_wps_params, - interface_wps_start_result, data); + return -EINPROGRESS; } -static void wps_process_credentials(DBusMessageIter *iter, void *user_data) +int g_supplicant_interface_p2p_disconnect(GSupplicantInterface *interface, + GSupplicantPeerParams *peer_params) { - dbus_bool_t credentials = TRUE; + GSupplicantPeer *peer; + int count = 0; + GSList *list; SUPPLICANT_DBG(""); - dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials); + if (!interface->p2p_support) + return -ENOTSUP; + + peer = g_hash_table_lookup(interface->peer_table, peer_params->path); + if (!peer) + return -ENODEV; + + for (list = peer->groups; list; list = list->next, count++) { + const char *group_obj_path = list->data; + GSupplicantInterface *g_interface; + GSupplicantGroup *group; + + group = g_hash_table_lookup(group_mapping, group_obj_path); + if (!group || !group->interface) + continue; + + g_interface = group->interface; + supplicant_dbus_method_call(g_interface->path, + SUPPLICANT_INTERFACE ".Interface.P2PDevice", + "Disconnect", NULL, NULL, NULL, g_interface); + } + + if (count == 0 && peer->current_group_iface) { + supplicant_dbus_method_call(peer->current_group_iface->path, + SUPPLICANT_INTERFACE ".Interface.P2PDevice", + "Disconnect", NULL, NULL, NULL, + peer->current_group_iface->path); + } + + peer->current_group_iface = NULL; + + return -EINPROGRESS; } +struct p2p_service_data { + bool registration; + GSupplicantInterface *interface; + GSupplicantP2PServiceParams *service; + GSupplicantInterfaceCallback callback; + void *user_data; +}; -int g_supplicant_interface_connect(GSupplicantInterface *interface, - GSupplicantSSID *ssid, - GSupplicantInterfaceCallback callback, +static void interface_p2p_service_result(const char *error, + DBusMessageIter *iter, void *user_data) +{ + struct p2p_service_data *data = user_data; + int result = 0; + + SUPPLICANT_DBG("%s result - %s", data->registration ? + "Registration" : "Deletion", + error ? error : "Success"); + if (error) + result = -EINVAL; + + if (data->callback) + data->callback(result, data->interface, data->user_data); + + g_free(data->service->query); + g_free(data->service->response); + g_free(data->service->service); + g_free(data->service->wfd_ies); + g_free(data->service); + dbus_free(data); +} + +static void interface_p2p_service_params(DBusMessageIter *iter, void *user_data) { - struct interface_connect_data *data; - int ret; + struct p2p_service_data *data = user_data; + GSupplicantP2PServiceParams *service; + DBusMessageIter dict; + const char *type; - if (interface == NULL) - return -EINVAL; + SUPPLICANT_DBG(""); - if (system_available == FALSE) - return -EFAULT; + service = data->service; - /* TODO: Check if we're already connected and switch */ + supplicant_dbus_dict_open(iter, &dict); + + if (service->query && service->response) { + type = "bonjour"; + supplicant_dbus_dict_append_basic(&dict, "service_type", + DBUS_TYPE_STRING, &type); + supplicant_dbus_dict_append_fixed_array(&dict, "query", + DBUS_TYPE_BYTE, &service->query, + service->query_length); + supplicant_dbus_dict_append_fixed_array(&dict, "response", + DBUS_TYPE_BYTE, &service->response, + service->response_length); + } else if (service->version && service->service) { + type = "upnp"; + supplicant_dbus_dict_append_basic(&dict, "service_type", + DBUS_TYPE_STRING, &type); + supplicant_dbus_dict_append_basic(&dict, "version", + DBUS_TYPE_INT32, &service->version); + supplicant_dbus_dict_append_basic(&dict, "service", + DBUS_TYPE_STRING, &service->service); + } + + supplicant_dbus_dict_close(iter, &dict); +} + +int g_supplicant_interface_p2p_add_service(GSupplicantInterface *interface, + GSupplicantInterfaceCallback callback, + GSupplicantP2PServiceParams *p2p_service_params, + void *user_data) +{ + struct p2p_service_data *data; + int ret; + + SUPPLICANT_DBG(""); + + if (!interface->p2p_support) + return -ENOTSUP; data = dbus_malloc0(sizeof(*data)); - if (data == NULL) + if (!data) return -ENOMEM; + data->registration = true; data->interface = interface; + data->service = p2p_service_params; data->callback = callback; - data->ssid = ssid; data->user_data = user_data; - if (ssid->use_wps == TRUE) { - g_free(interface->wps_cred.key); - memset(&interface->wps_cred, 0, - sizeof(struct _GSupplicantWpsCredentials)); - - ret = supplicant_dbus_property_set(interface->path, - SUPPLICANT_INTERFACE ".Interface.WPS", - "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING, - wps_process_credentials, wps_start, data); - } else - ret = supplicant_dbus_method_call(interface->path, - SUPPLICANT_INTERFACE ".Interface", "AddNetwork", - interface_add_network_params, - interface_add_network_result, data); - - if (ret < 0) + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface.P2PDevice", "AddService", + interface_p2p_service_params, interface_p2p_service_result, + data, interface); + if (ret < 0) { + dbus_free(data); return ret; + } return -EINPROGRESS; } -static void network_remove_result(const char *error, - DBusMessageIter *iter, void *user_data) +int g_supplicant_interface_p2p_del_service(GSupplicantInterface *interface, + GSupplicantP2PServiceParams *p2p_service_params) { - struct interface_data *data = user_data; - int result = 0; + struct p2p_service_data *data; + int ret; SUPPLICANT_DBG(""); - if (error != NULL) { - result = -EIO; - if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod", - error) == 0) - result = -ECONNABORTED; - } + if (!interface->p2p_support) + return -ENOTSUP; - if (data->callback != NULL) - data->callback(result, data->interface, data->user_data); + data = dbus_malloc0(sizeof(*data)); + if (!data) + return -ENOMEM; - dbus_free(data); + data->interface = interface; + data->service = p2p_service_params; + + ret = supplicant_dbus_method_call(interface->path, + SUPPLICANT_INTERFACE ".Interface.P2PDevice", "DeleteService", + interface_p2p_service_params, interface_p2p_service_result, + data, interface); + if (ret < 0) { + dbus_free(data); + return ret; + } + + return -EINPROGRESS; } -static void network_remove_params(DBusMessageIter *iter, void *user_data) +struct p2p_listen_data { + int period; + int interval; +}; + +static void interface_p2p_listen_params(DBusMessageIter *iter, void *user_data) { - struct interface_data *data = user_data; - const char *path = data->interface->network_path; + struct p2p_listen_data *params = user_data; + DBusMessageIter dict; - SUPPLICANT_DBG("path %s", path); + supplicant_dbus_dict_open(iter, &dict); - dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path); + supplicant_dbus_dict_append_basic(&dict, "period", + DBUS_TYPE_INT32, ¶ms->period); + supplicant_dbus_dict_append_basic(&dict, "interval", + DBUS_TYPE_INT32, ¶ms->interval); + supplicant_dbus_dict_close(iter, &dict); } -static int network_remove(struct interface_data *data) +int g_supplicant_interface_p2p_listen(GSupplicantInterface *interface, + int period, int interval) { - GSupplicantInterface *interface = data->interface; + struct p2p_listen_data params; SUPPLICANT_DBG(""); + if (!interface->p2p_support) + return -ENOTSUP; + + params.period = period; + params.interval = interval; + return supplicant_dbus_method_call(interface->path, - SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork", - network_remove_params, network_remove_result, data); + SUPPLICANT_INTERFACE ".Interface.P2PDevice", + "ExtendedListen", interface_p2p_listen_params, + NULL, ¶ms, NULL); } -static void interface_disconnect_result(const char *error, - DBusMessageIter *iter, void *user_data) +static void widi_ies_params(DBusMessageIter *iter, void *user_data) { - struct interface_data *data = user_data; - int result = 0; - - SUPPLICANT_DBG(""); + struct p2p_service_data *data = user_data; + GSupplicantP2PServiceParams *service = data->service; + DBusMessageIter array; - if (error != NULL) { - result = -EIO; - if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod", - error) == 0) - result = -ECONNABORTED; - } + SUPPLICANT_DBG("%p - %d", service->wfd_ies, service->wfd_ies_length); - if (result < 0 && data->callback != NULL) { - data->callback(result, data->interface, data->user_data); - data->callback = NULL; - } + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE_AS_STRING, &array); - /* 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 == NULL) { - dbus_free(data); - return; + if (service->wfd_ies && service->wfd_ies_length > 0) { + dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, + &service->wfd_ies, service->wfd_ies_length); } - if (result != -ECONNABORTED) - network_remove(data); - else - dbus_free(data); + dbus_message_iter_close_container(iter, &array); } -int g_supplicant_interface_disconnect(GSupplicantInterface *interface, +int g_supplicant_set_widi_ies(GSupplicantP2PServiceParams *p2p_service_params, GSupplicantInterfaceCallback callback, - void *user_data) + void *user_data) { - struct interface_data *data; + struct p2p_service_data *data; + int ret; SUPPLICANT_DBG(""); - if (interface == NULL) - return -EINVAL; - - if (system_available == FALSE) + if (!system_available) return -EFAULT; data = dbus_malloc0(sizeof(*data)); - if (data == NULL) + if (!data) return -ENOMEM; - data->interface = interface; + data->service = p2p_service_params; data->callback = callback; data->user_data = user_data; - return supplicant_dbus_method_call(interface->path, - SUPPLICANT_INTERFACE ".Interface", "Disconnect", - NULL, interface_disconnect_result, data); -} + if (p2p_service_params->wfd_ies) + data->registration = true; + + ret = supplicant_dbus_property_set(SUPPLICANT_PATH, + SUPPLICANT_INTERFACE, "WFDIEs", + DBUS_TYPE_ARRAY_AS_STRING + DBUS_TYPE_BYTE_AS_STRING, + widi_ies_params, + interface_p2p_service_result, + data, NULL); + if (ret < 0 && ret != -EINPROGRESS) { + dbus_free(data); + return ret; + } + return -EINPROGRESS; +} static const char *g_supplicant_rule0 = "type=signal," "path=" DBUS_PATH_DBUS "," @@ -3700,6 +7293,18 @@ static const char *g_supplicant_rule4 = "type=signal," "interface=" SUPPLICANT_INTERFACE ".BSS"; static const char *g_supplicant_rule5 = "type=signal," "interface=" SUPPLICANT_INTERFACE ".Network"; +#if !defined TIZEN_EXT +static const char *g_supplicant_rule6 = "type=signal," + "interface=" SUPPLICANT_INTERFACE ".Interface.P2PDevice"; +static const char *g_supplicant_rule7 = "type=signal," + "interface=" SUPPLICANT_INTERFACE ".Peer"; +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) { @@ -3710,7 +7315,7 @@ static void invoke_introspect_method(void) DBUS_INTERFACE_INTROSPECTABLE, "Introspect"); - if (message == NULL) + if (!message) return; dbus_message_set_no_reply(message, TRUE); @@ -3721,11 +7326,11 @@ static void invoke_introspect_method(void) int g_supplicant_register(const GSupplicantCallbacks *callbacks) { connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); - if (connection == NULL) + if (!connection) return -EIO; - if (dbus_connection_add_filter(connection, - g_supplicant_filter, NULL, NULL) == FALSE) { + if (!dbus_connection_add_filter(connection, g_supplicant_filter, + NULL, NULL)) { dbus_connection_unref(connection); connection = NULL; return -EIO; @@ -3739,6 +7344,14 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks) bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); + peer_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, + NULL, NULL); + group_mapping = g_hash_table_new_full(g_str_hash, g_str_equal, + 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); @@ -3748,14 +7361,27 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks) dbus_bus_add_match(connection, g_supplicant_rule3, NULL); dbus_bus_add_match(connection, g_supplicant_rule4, NULL); dbus_bus_add_match(connection, g_supplicant_rule5, NULL); +#if defined TIZEN_EXT + dbus_bus_add_match(connection, + "type=signal,interface=org.tizen.system.deviced.PowerOff," + "member=ChangeState", NULL); +#endif +#if !defined TIZEN_EXT + dbus_bus_add_match(connection, g_supplicant_rule6, NULL); + 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, - SUPPLICANT_SERVICE, NULL) == TRUE) { + SUPPLICANT_SERVICE, NULL)) { system_available = TRUE; supplicant_dbus_property_get_all(SUPPLICANT_PATH, SUPPLICANT_INTERFACE, - service_property, NULL); + service_property, NULL, NULL); } else invoke_introspect_method(); @@ -3781,14 +7407,22 @@ static void unregister_remove_interface(gpointer key, gpointer value, SUPPLICANT_INTERFACE, "RemoveInterface", unregister_interface_remove_params, - NULL, interface->path); + NULL, interface->path, NULL); } void g_supplicant_unregister(const GSupplicantCallbacks *callbacks) { SUPPLICANT_DBG(""); - if (connection != NULL) { + 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); + dbus_bus_remove_match(connection, g_supplicant_rule6, NULL); +#endif dbus_bus_remove_match(connection, g_supplicant_rule5, NULL); dbus_bus_remove_match(connection, g_supplicant_rule4, NULL); dbus_bus_remove_match(connection, g_supplicant_rule3, NULL); @@ -3801,22 +7435,37 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks) g_supplicant_filter, NULL); } - if (bss_mapping != 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; } - if (system_available == TRUE) - callback_system_killed(); + if (peer_mapping) { + g_hash_table_destroy(peer_mapping); + peer_mapping = NULL; + } - if (interface_table != NULL) { + if (group_mapping) { + g_hash_table_destroy(group_mapping); + group_mapping = NULL; + } + + if (interface_table) { g_hash_table_foreach(interface_table, unregister_remove_interface, NULL); g_hash_table_destroy(interface_table); interface_table = NULL; } - if (connection != NULL) { + if (system_available) + callback_system_killed(); + + if (connection) { dbus_connection_unref(connection); connection = NULL; }