summaryrefslogtreecommitdiff
path: root/gsupplicant
diff options
context:
space:
mode:
Diffstat (limited to 'gsupplicant')
-rw-r--r--gsupplicant/gsupplicant.h11
-rw-r--r--gsupplicant/supplicant.c671
2 files changed, 574 insertions, 108 deletions
diff --git a/gsupplicant/gsupplicant.h b/gsupplicant/gsupplicant.h
index 187dc654..db61595b 100644
--- a/gsupplicant/gsupplicant.h
+++ b/gsupplicant/gsupplicant.h
@@ -142,7 +142,12 @@ struct _GSupplicantSSID {
const char *eap;
const char *passphrase;
const char *identity;
+ const char *anonymous_identity;
const char *ca_cert_path;
+ const char *subject_match;
+ const char *altsubject_match;
+ const char *domain_suffix_match;
+ const char *domain_match;
const char *client_cert_path;
const char *private_key_path;
const char *private_key_passphrase;
@@ -341,16 +346,22 @@ struct _GSupplicantCallbacks {
void (*p2p_support) (GSupplicantInterface *interface);
void (*scan_started) (GSupplicantInterface *interface);
void (*scan_finished) (GSupplicantInterface *interface);
+ void (*ap_create_fail) (GSupplicantInterface *interface);
void (*network_added) (GSupplicantNetwork *network);
void (*network_removed) (GSupplicantNetwork *network);
void (*network_changed) (GSupplicantNetwork *network,
const char *property);
+ void (*network_associated) (GSupplicantNetwork *network);
void (*peer_found) (GSupplicantPeer *peer);
void (*peer_lost) (GSupplicantPeer *peer);
void (*peer_changed) (GSupplicantPeer *peer,
GSupplicantPeerState state);
void (*peer_request) (GSupplicantPeer *peer);
void (*debug) (const char *str);
+ void (*disconnect_reasoncode)(GSupplicantInterface *interface,
+ int reasoncode);
+ void (*assoc_status_code)(GSupplicantInterface *interface,
+ int reasoncode);
};
typedef struct _GSupplicantCallbacks GSupplicantCallbacks;
diff --git a/gsupplicant/supplicant.c b/gsupplicant/supplicant.c
index cd91f952..4f790122 100644
--- a/gsupplicant/supplicant.c
+++ b/gsupplicant/supplicant.c
@@ -143,6 +143,7 @@ static GHashTable *bss_mapping;
static GHashTable *peer_mapping;
static GHashTable *group_mapping;
static GHashTable *pending_peer_connection;
+static GHashTable *config_file_table;
struct _GSupplicantWpsCredentials {
unsigned char ssid[32];
@@ -150,6 +151,13 @@ struct _GSupplicantWpsCredentials {
char *key;
};
+struct added_network_information {
+ char * ssid;
+ GSupplicantSecurity security;
+ char * passphrase;
+ char * private_passphrase;
+};
+
struct _GSupplicantInterface {
char *path;
char *network_path;
@@ -163,6 +171,7 @@ struct _GSupplicantInterface {
unsigned int max_scan_ssids;
bool p2p_support;
bool p2p_finding;
+ bool ap_create_in_progress;
dbus_bool_t ready;
GSupplicantState state;
dbus_bool_t scanning;
@@ -177,10 +186,11 @@ struct _GSupplicantInterface {
GHashTable *network_table;
GHashTable *peer_table;
GHashTable *group_table;
- GHashTable *net_mapping;
GHashTable *bss_mapping;
void *data;
const char *pending_peer_path;
+ GSupplicantNetwork *current_network;
+ struct added_network_information network_info;
};
struct g_supplicant_bss {
@@ -249,12 +259,53 @@ struct _GSupplicantGroup {
GSList *members;
};
+struct interface_data {
+ GSupplicantInterface *interface;
+ char *path; /* Interface path cannot be taken from interface (above) as
+ * it might have been freed already.
+ */
+ GSupplicantInterfaceCallback callback;
+ void *user_data;
+ bool network_remove_in_progress;
+ GSupplicantSSID *ssid;
+};
+
+struct interface_create_data {
+ char *ifname;
+ char *driver;
+ char *bridge;
+ GSupplicantInterface *interface;
+ GSupplicantInterfaceCallback callback;
+ void *user_data;
+};
+
+struct interface_connect_data {
+ GSupplicantInterface *interface;
+ char *path;
+ GSupplicantInterfaceCallback callback;
+ void *user_data;
+ union {
+ GSupplicantSSID *ssid;
+ GSupplicantPeerParams *peer;
+ };
+};
+
+struct interface_scan_data {
+ GSupplicantInterface *interface;
+ char *path;
+ GSupplicantInterfaceCallback callback;
+ GSupplicantScanParams *scan_params;
+ void *user_data;
+};
+
+static int network_remove(struct interface_data *data);
+
static inline void debug(const char *format, ...)
{
char str[256];
va_list ap;
- if (!callbacks_pointer->debug)
+ if (!callbacks_pointer || !callbacks_pointer->debug)
return;
va_start(ap, format);
@@ -346,6 +397,70 @@ static GSupplicantState string2state(const char *state)
return G_SUPPLICANT_STATE_UNKNOWN;
}
+static bool compare_network_parameters(GSupplicantInterface *interface,
+ GSupplicantSSID *ssid)
+{
+ 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)
@@ -432,6 +547,17 @@ static void callback_scan_started(GSupplicantInterface *interface)
callbacks_pointer->scan_started(interface);
}
+static void callback_ap_create_fail(GSupplicantInterface *interface)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->ap_create_fail)
+ return;
+
+ callbacks_pointer->ap_create_fail(interface);
+}
+
static void callback_scan_finished(GSupplicantInterface *interface)
{
if (!callbacks_pointer)
@@ -477,6 +603,17 @@ static void callback_network_changed(GSupplicantNetwork *network,
callbacks_pointer->network_changed(network, property);
}
+static void callback_network_associated(GSupplicantNetwork *network)
+{
+ if (!callbacks_pointer)
+ return;
+
+ if (!callbacks_pointer->network_associated)
+ return;
+
+ callbacks_pointer->network_associated(network);
+}
+
static void callback_peer_found(GSupplicantPeer *peer)
{
if (!callbacks_pointer)
@@ -524,6 +661,33 @@ static void callback_peer_request(GSupplicantPeer *peer)
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;
@@ -540,7 +704,6 @@ static void remove_interface(gpointer data)
GSupplicantInterface *interface = data;
g_hash_table_destroy(interface->bss_mapping);
- g_hash_table_destroy(interface->net_mapping);
g_hash_table_destroy(interface->network_table);
g_hash_table_destroy(interface->peer_table);
g_hash_table_destroy(interface->group_table);
@@ -568,6 +731,7 @@ static void remove_interface(gpointer data)
g_free(interface->ifname);
g_free(interface->driver);
g_free(interface->bridge);
+ remove_network_information(interface);
g_free(interface);
}
@@ -613,6 +777,7 @@ static void remove_peer(gpointer data)
g_free(peer->path);
g_free(peer->name);
g_free(peer->identifier);
+ g_free(peer->widi_ies);
g_free(peer);
}
@@ -790,20 +955,59 @@ static void interface_capability(const char *key, DBusMessageIter *iter,
key, dbus_message_iter_get_arg_type(iter));
}
+struct set_apscan_data
+{
+ unsigned int ap_scan;
+ GSupplicantInterface *interface;
+};
+
static void set_apscan(DBusMessageIter *iter, void *user_data)
{
- unsigned int ap_scan = *(unsigned int *)user_data;
+ struct set_apscan_data *data = user_data;
+ unsigned int ap_scan = data->ap_scan;
dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ap_scan);
}
+static void set_apscan_complete(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct set_apscan_data *data = user_data;
+ GSupplicantInterface *interface = data->interface;
+
+ if (error) {
+ interface->ap_create_in_progress = false;
+ SUPPLICANT_DBG("Set AP scan error %s", error);
+ goto error;
+ }
+
+ interface->ap_create_in_progress = true;
+error:
+ dbus_free(data);
+}
+
int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
unsigned int ap_scan)
{
- return supplicant_dbus_property_set(interface->path,
+ struct set_apscan_data *data;
+ int ret;
+
+ data = dbus_malloc0(sizeof(*data));
+
+ if (!data)
+ return -ENOMEM;
+
+ data->ap_scan = ap_scan;
+ data->interface = interface;
+
+ ret = supplicant_dbus_property_set(interface->path,
SUPPLICANT_INTERFACE ".Interface",
- "ApScan", DBUS_TYPE_UINT32_AS_STRING,
- set_apscan, NULL, &ap_scan, NULL);
+ "ApScan", DBUS_TYPE_UINT32_AS_STRING,
+ set_apscan, set_apscan_complete, data, NULL);
+ if (ret < 0)
+ dbus_free(data);
+
+ return ret;
}
void g_supplicant_interface_set_data(GSupplicantInterface *interface,
@@ -1269,10 +1473,6 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data)
if (g_strcmp0(path, "/") == 0)
return;
- network = g_hash_table_lookup(interface->net_mapping, path);
- if (network)
- return;
-
network = g_try_new0(GSupplicantNetwork, 1);
if (!network)
return;
@@ -1298,19 +1498,8 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data)
static void interface_network_removed(DBusMessageIter *iter, void *user_data)
{
- GSupplicantInterface *interface = user_data;
- GSupplicantNetwork *network;
- const char *path = NULL;
-
- dbus_message_iter_get_basic(iter, &path);
- if (!path)
- return;
-
- network = g_hash_table_lookup(interface->net_mapping, path);
- if (!network)
- return;
-
- g_hash_table_remove(interface->net_mapping, path);
+ SUPPLICANT_DBG("");
+ return;
}
static char *create_name(unsigned char *ssid, int ssid_len)
@@ -1381,7 +1570,7 @@ static char *create_group(struct g_supplicant_bss *bss)
return g_string_free(str, FALSE);
}
-static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
+static int add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
{
GSupplicantInterface *interface = bss->interface;
GSupplicantNetwork *network;
@@ -1391,7 +1580,7 @@ static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
SUPPLICANT_DBG("New group created: %s", group);
if (!group)
- return;
+ return -ENOMEM;
network = g_hash_table_lookup(interface->network_table, group);
if (network) {
@@ -1404,7 +1593,7 @@ static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
network = g_try_new0(GSupplicantNetwork, 1);
if (!network) {
g_free(group);
- return;
+ return -ENOMEM;
}
network->interface = interface;
@@ -1440,7 +1629,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");
@@ -1450,6 +1644,8 @@ done:
g_hash_table_replace(network->bss_table, bss->path, bss);
g_hash_table_replace(bss_mapping, bss->path, interface);
+
+ return 0;
}
static void bss_rates(DBusMessageIter *iter, void *user_data)
@@ -1851,7 +2047,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,
@@ -1870,7 +2067,8 @@ static void interface_bss_added_without_keys(DBusMessageIter *iter,
bss_property, bss, NULL);
bss_compute_security(bss);
- add_or_replace_bss_to_network(bss);
+ if (add_or_replace_bss_to_network(bss) < 0)
+ SUPPLICANT_DBG("add_or_replace_bss_to_network failed");
}
static void update_signal(gpointer key, gpointer value,
@@ -1896,6 +2094,75 @@ 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;
@@ -1930,10 +2197,37 @@ static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
static void set_config_methods(DBusMessageIter *iter, void *user_data)
{
- const char *config_methods = "push_button";
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, user_data);
+}
+
+static void wps_property(const char *key, DBusMessageIter *iter,
+ void *user_data)
+{
+ GSupplicantInterface *interface = user_data;
+
+ if (!interface)
+ return;
+
+ SUPPLICANT_DBG("key: %s", key);
+
+ if (g_strcmp0(key, "ConfigMethods") == 0) {
+ const char *config_methods = "push_button", *str = NULL;
+
+ dbus_message_iter_get_basic(iter, &str);
+ if (str && strlen(str) > 0) {
+ /* It was already set at wpa_s level, don't modify it. */
+ SUPPLICANT_DBG("%s", str);
+ return;
+ }
+
+ supplicant_dbus_property_set(interface->path,
+ SUPPLICANT_INTERFACE ".Interface.WPS",
+ "ConfigMethods", DBUS_TYPE_STRING_AS_STRING,
+ set_config_methods, NULL, &config_methods, NULL);
+
+ SUPPLICANT_DBG("No value. Set %s", config_methods);
+ }
- dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
- &config_methods);
}
static void interface_property(const char *key, DBusMessageIter *iter,
@@ -1962,11 +2256,9 @@ static void interface_property(const char *key, DBusMessageIter *iter,
debug_strvalmap("Mode capability", mode_capa_map,
interface->mode_capa);
-
- supplicant_dbus_property_set(interface->path,
+ supplicant_dbus_property_get_all(interface->path,
SUPPLICANT_INTERFACE ".Interface.WPS",
- "ConfigMethods", DBUS_TYPE_STRING_AS_STRING,
- set_config_methods, NULL, NULL, NULL);
+ wps_property, interface, interface);
if (interface->ready)
callback_interface_added(interface);
@@ -1988,6 +2280,14 @@ static void interface_property(const char *key, DBusMessageIter *iter,
interface->state = string2state(str);
callback_interface_state(interface);
}
+
+ if (interface->ap_create_in_progress) {
+ if (interface->state == G_SUPPLICANT_STATE_DISCONNECTED)
+ callback_ap_create_fail(interface);
+
+ interface->ap_create_in_progress = false;
+ }
+
if (interface->state == G_SUPPLICANT_STATE_DISABLED)
interface->ready = FALSE;
else
@@ -2035,8 +2335,17 @@ static void interface_property(const char *key, DBusMessageIter *iter,
g_free(interface->bridge);
interface->bridge = g_strdup(str);
}
+ } else if (g_strcmp0(key, "ConfigFile") == 0) {
+ const char *str = NULL;
+
+ dbus_message_iter_get_basic(iter, &str);
+ if (str && strlen(str) > 0 && interface->ifname) {
+ SUPPLICANT_DBG("New {%s, %s}", interface->ifname, str);
+ g_hash_table_replace(config_file_table,
+ g_strdup(interface->ifname), g_strdup(str));
+ }
} else if (g_strcmp0(key, "CurrentBSS") == 0) {
- interface_bss_added_without_keys(iter, interface);
+ interface_current_bss(interface, iter);
} else if (g_strcmp0(key, "CurrentNetwork") == 0) {
interface_network_added(iter, interface);
} else if (g_strcmp0(key, "BSSs") == 0) {
@@ -2048,9 +2357,22 @@ static void interface_property(const char *key, DBusMessageIter *iter,
} 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)
@@ -2108,8 +2430,6 @@ static GSupplicantInterface *interface_alloc(const char *path)
g_str_equal, NULL, remove_peer);
interface->group_table = g_hash_table_new_full(g_str_hash,
g_str_equal, NULL, remove_group);
- interface->net_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
- NULL, NULL);
interface->bss_mapping = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, NULL);
@@ -2122,6 +2442,7 @@ static void interface_added(DBusMessageIter *iter, void *user_data)
{
GSupplicantInterface *interface;
const char *path = NULL;
+ bool properties_appended = GPOINTER_TO_UINT(user_data);
SUPPLICANT_DBG("");
@@ -2140,18 +2461,20 @@ static void interface_added(DBusMessageIter *iter, void *user_data)
if (!interface)
return;
+ if (!properties_appended) {
+ supplicant_dbus_property_get_all(path,
+ SUPPLICANT_INTERFACE ".Interface",
+ interface_property, interface,
+ interface);
+ return;
+ }
+
dbus_message_iter_next(iter);
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
supplicant_dbus_property_foreach(iter, interface_property,
interface);
interface_property(NULL, NULL, interface);
- return;
}
-
- supplicant_dbus_property_get_all(path,
- SUPPLICANT_INTERFACE ".Interface",
- interface_property, interface,
- interface);
}
static void interface_removed(DBusMessageIter *iter, void *user_data)
@@ -2254,6 +2577,7 @@ static void signal_name_owner_changed(const char *path, DBusMessageIter *iter)
g_hash_table_remove_all(bss_mapping);
g_hash_table_remove_all(peer_mapping);
g_hash_table_remove_all(group_mapping);
+ g_hash_table_remove_all(config_file_table);
g_hash_table_remove_all(interface_table);
callback_system_killed();
}
@@ -2281,7 +2605,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)
@@ -2445,11 +2769,22 @@ static void signal_bss_changed(const char *path, DBusMessageIter *iter)
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;
}
+ /* Consider only property changes of the connected BSS */
+ if (network == interface->current_network && bss != network->best_bss)
+ return;
+
if (bss->signal == network->signal)
return;
@@ -2619,7 +2954,7 @@ static void peer_groups_relation(DBusMessageIter *iter, void *user_data)
if (!group)
return;
- elem = g_slist_find_custom(data->old_groups, str, g_str_equal);
+ elem = g_slist_find_custom(data->old_groups, str, (GCompareFunc)g_strcmp0);
if (elem) {
data->old_groups = g_slist_remove_link(data->old_groups, elem);
peer->groups = g_slist_concat(elem, peer->groups);
@@ -3233,6 +3568,7 @@ int g_supplicant_set_country(const char *alpha2,
const void *user_data)
{
struct supplicant_regdom *regdom;
+ int ret;
SUPPLICANT_DBG("Country setting %s", alpha2);
@@ -3247,10 +3583,15 @@ int g_supplicant_set_country(const char *alpha2,
regdom->alpha2 = alpha2;
regdom->user_data = user_data;
- return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
+ ret = supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
"Country", DBUS_TYPE_STRING_AS_STRING,
country_params, country_result,
regdom, NULL);
+ if (ret < 0) {
+ dbus_free(regdom);
+ SUPPLICANT_DBG("Unable to set Country configuration");
+ }
+ return ret;
}
int g_supplicant_interface_set_country(GSupplicantInterface *interface,
@@ -3259,6 +3600,7 @@ int g_supplicant_interface_set_country(GSupplicantInterface *interface,
void *user_data)
{
struct supplicant_regdom *regdom;
+ int ret;
regdom = dbus_malloc0(sizeof(*regdom));
if (!regdom)
@@ -3268,11 +3610,17 @@ int g_supplicant_interface_set_country(GSupplicantInterface *interface,
regdom->alpha2 = alpha2;
regdom->user_data = user_data;
- return supplicant_dbus_property_set(interface->path,
+ ret = supplicant_dbus_property_set(interface->path,
SUPPLICANT_INTERFACE ".Interface",
"Country", DBUS_TYPE_STRING_AS_STRING,
country_params, country_result,
regdom, NULL);
+ if (ret < 0) {
+ dbus_free(regdom);
+ SUPPLICANT_DBG("Unable to set Country configuration");
+ }
+
+ return ret;
}
bool g_supplicant_interface_has_p2p(GSupplicantInterface *interface)
@@ -3412,43 +3760,6 @@ GSupplicantPeer *g_supplicant_interface_peer_lookup(GSupplicantInterface *interf
return peer;
}
-struct interface_data {
- GSupplicantInterface *interface;
- char *path; /* Interface path cannot be taken from interface (above) as
- * it might have been freed already.
- */
- GSupplicantInterfaceCallback callback;
- void *user_data;
-};
-
-struct interface_create_data {
- char *ifname;
- char *driver;
- char *bridge;
- GSupplicantInterface *interface;
- GSupplicantInterfaceCallback callback;
- void *user_data;
-};
-
-struct interface_connect_data {
- GSupplicantInterface *interface;
- char *path;
- GSupplicantInterfaceCallback callback;
- union {
- GSupplicantSSID *ssid;
- GSupplicantPeerParams *peer;
- };
- void *user_data;
-};
-
-struct interface_scan_data {
- GSupplicantInterface *interface;
- char *path;
- GSupplicantInterfaceCallback callback;
- GSupplicantScanParams *scan_params;
- void *user_data;
-};
-
static void interface_create_data_free(struct interface_create_data *data)
{
g_free(data->ifname);
@@ -3540,6 +3851,7 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data)
{
struct interface_create_data *data = user_data;
DBusMessageIter dict;
+ char *config_file = NULL;
SUPPLICANT_DBG("");
@@ -3556,6 +3868,14 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data)
supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
DBUS_TYPE_STRING, &data->bridge);
+ config_file = g_hash_table_lookup(config_file_table, data->ifname);
+ if (config_file) {
+ SUPPLICANT_DBG("[%s] ConfigFile %s", data->ifname, config_file);
+
+ supplicant_dbus_dict_append_basic(&dict, "ConfigFile",
+ DBUS_TYPE_STRING, &config_file);
+ }
+
supplicant_dbus_dict_close(iter, &dict);
}
@@ -3674,6 +3994,7 @@ static void interface_remove_result(const char *error,
if (error) {
err = -EIO;
+ SUPPLICANT_DBG("error: %s", error);
goto done;
}
@@ -3967,7 +4288,7 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface,
static int parse_supplicant_error(DBusMessageIter *iter)
{
- int err = -ECANCELED;
+ int err = -ECONNABORTED;
char *key;
if (!iter)
@@ -4041,9 +4362,10 @@ static void interface_add_network_result(const char *error,
SUPPLICANT_DBG("PATH: %s", path);
- g_free(interface->network_path);
interface->network_path = g_strdup(path);
+ store_network_information(interface, data->ssid);
+
supplicant_dbus_method_call(data->interface->path,
SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
interface_select_network_params,
@@ -4321,6 +4643,30 @@ static void add_network_security_eap(DBusMessageIter *dict,
supplicant_dbus_dict_append_basic(dict, "identity",
DBUS_TYPE_STRING,
&ssid->identity);
+ 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);
}
@@ -4507,10 +4853,18 @@ 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("");
- if (error)
+
+ 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);
@@ -4580,7 +4934,10 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
void *user_data)
{
struct interface_connect_data *data;
- int ret;
+ struct interface_data *intf_data;
+ int ret = 0;
+
+ SUPPLICANT_DBG("");
if (!interface)
return -EINVAL;
@@ -4609,12 +4966,58 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
SUPPLICANT_INTERFACE ".Interface.WPS",
"ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
wps_process_credentials, wps_start, data, interface);
- } else
- ret = supplicant_dbus_method_call(interface->path,
- SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
- interface_add_network_params,
- interface_add_network_result, data,
- interface);
+ } else {
+ /* By the time there is a request for connect and the network
+ * path is not NULL it means that connman has not removed the
+ * previous network pointer. This can happen in the case AP
+ * deauthenticated client and connman does not remove the
+ * previously connected network pointer. This causes supplicant
+ * to reallocate the memory for struct wpa_ssid again even if it
+ * is the same SSID. This causes memory usage of wpa_supplicnat
+ * to go high. The idea here is that if the previously connected
+ * network is not removed at the time of next connection attempt
+ * check if the network path is not NULL. In case it is non-NULL
+ * first remove the network and then once removal is successful, add
+ * the network.
+ */
+
+ if (interface->network_path != NULL) {
+ g_free(data->path);
+ dbus_free(data);
+
+ /*
+ * If this add network is for the same network for
+ * which wpa_supplicant already has a profile then do
+ * not need to add another profile. Only if the
+ * profile that needs to get added is different from
+ * what is there in wpa_s delete the current one. A
+ * network is identified by its SSID, security_type
+ * and passphrase (private passphrase in case security
+ * type is 802.11x).
+ */
+ if (compare_network_parameters(interface, ssid)) {
+ return -EALREADY;
+ }
+
+ intf_data = dbus_malloc0(sizeof(*intf_data));
+ if (!intf_data)
+ return -ENOMEM;
+
+ intf_data->interface = interface;
+ intf_data->path = g_strdup(interface->path);
+ intf_data->callback = callback;
+ intf_data->ssid = ssid;
+ intf_data->user_data = user_data;
+ intf_data->network_remove_in_progress = TRUE;
+ network_remove(intf_data);
+ } else {
+ 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);
@@ -4629,22 +5032,47 @@ static void network_remove_result(const char *error,
DBusMessageIter *iter, void *user_data)
{
struct interface_data *data = user_data;
+ struct interface_connect_data *connect_data;
int result = 0;
SUPPLICANT_DBG("");
if (error) {
result = -EIO;
+ SUPPLICANT_DBG("error: %s", error);
+
if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
error) == 0)
result = -ECONNABORTED;
}
- g_free(data->path);
+ g_free(data->interface->network_path);
+ data->interface->network_path = NULL;
- if (data->callback)
- data->callback(result, data->interface, data->user_data);
+ remove_network_information(data->interface);
+
+ if (data->network_remove_in_progress == TRUE) {
+ data->network_remove_in_progress = FALSE;
+ connect_data = dbus_malloc0(sizeof(*connect_data));
+ if (!connect_data)
+ return;
+
+ connect_data->interface = data->interface;
+ connect_data->path = g_strdup(data->path);
+ connect_data->callback = data->callback;
+ connect_data->ssid = data->ssid;
+ connect_data->user_data = data->user_data;
+ 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);
}
@@ -4680,25 +5108,31 @@ static void interface_disconnect_result(const char *error,
if (error) {
result = -EIO;
+ SUPPLICANT_DBG("error: %s", error);
+
if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
error) == 0)
result = -ECONNABORTED;
}
- if (result < 0 && data->callback) {
- data->callback(result, data->interface, data->user_data);
- data->callback = NULL;
- }
-
/* If we are disconnecting from previous WPS successful
* association. i.e.: it did not went through AddNetwork,
* and interface->network_path was never set. */
if (!data->interface->network_path) {
+ if (data->callback)
+ data->callback(result, data->interface,
+ data->user_data);
+
g_free(data->path);
dbus_free(data);
return;
}
+ if (result < 0 && data->callback) {
+ data->callback(result, data->interface, data->user_data);
+ data->callback = NULL;
+ }
+
if (result != -ECONNABORTED) {
if (network_remove(data) < 0) {
g_free(data->path);
@@ -4845,8 +5279,10 @@ static void interface_p2p_connect_result(const char *error,
SUPPLICANT_DBG("");
- if (error)
+ if (error) {
+ SUPPLICANT_DBG("error: %s", error);
err = parse_supplicant_error(iter);
+ }
if (data->callback)
data->callback(err, data->interface, data->user_data);
@@ -4904,6 +5340,9 @@ int g_supplicant_interface_p2p_connect(GSupplicantInterface *interface,
return -ENOTSUP;
data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
data->interface = interface;
data->path = g_strdup(interface->path);
data->peer = peer_params;
@@ -5048,6 +5487,9 @@ int g_supplicant_interface_p2p_add_service(GSupplicantInterface *interface,
return -ENOTSUP;
data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
data->registration = true;
data->interface = interface;
data->service = p2p_service_params;
@@ -5078,6 +5520,9 @@ int g_supplicant_interface_p2p_del_service(GSupplicantInterface *interface,
return -ENOTSUP;
data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
data->interface = interface;
data->service = p2p_service_params;
@@ -5163,6 +5608,9 @@ int g_supplicant_set_widi_ies(GSupplicantP2PServiceParams *p2p_service_params,
return -EFAULT;
data = dbus_malloc0(sizeof(*data));
+ if (!data)
+ return -ENOMEM;
+
data->service = p2p_service_params;
data->callback = callback;
data->user_data = user_data;
@@ -5253,6 +5701,8 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks)
NULL, NULL);
pending_peer_connection = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, NULL);
+ config_file_table = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
supplicant_dbus_setup(connection);
@@ -5321,6 +5771,11 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
g_supplicant_filter, NULL);
}
+ if (config_file_table) {
+ g_hash_table_destroy(config_file_table);
+ config_file_table = NULL;
+ }
+
if (bss_mapping) {
g_hash_table_destroy(bss_mapping);
bss_mapping = NULL;