#endif
#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <glib.h>
#include <gdbus.h>
-#define CONNMAN_API_SUBJECT_TO_CHANGE
-#include <connman/log.h>
-
#include "dbus.h"
#include "gsupplicant.h"
static GHashTable *interface_table;
static GHashTable *bss_mapping;
+struct _GSupplicantWpsCredentials {
+ unsigned char ssid[32];
+ unsigned int ssid_len;
+ char *key;
+};
+
struct _GSupplicantInterface {
char *path;
+ char *network_path;
unsigned int keymgmt_capa;
unsigned int authalg_capa;
unsigned int proto_capa;
char *ifname;
char *driver;
char *bridge;
+ struct _GSupplicantWpsCredentials wps_cred;
+ GSupplicantWpsState wps_state;
GHashTable *network_table;
GHashTable *net_mapping;
GHashTable *bss_mapping;
dbus_int16_t signal;
GSupplicantMode mode;
GSupplicantSecurity security;
+ dbus_bool_t wps;
GHashTable *bss_table;
GHashTable *config_table;
};
dbus_bool_t ieee8021x;
};
+static inline void debug(const char *format, ...)
+{
+ char str[256];
+ va_list ap;
+
+ if (callbacks_pointer->debug == NULL)
+ return;
+
+ va_start(ap, format);
+
+ if (vsnprintf(str, sizeof(str), format, ap) > 0)
+ callbacks_pointer->debug(str);
+
+ va_end(ap);
+}
+
+#define SUPPLICANT_DBG(fmt, arg...) \
+ debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg);
+
static GSupplicantMode string2mode(const char *mode)
{
if (mode == NULL)
case G_SUPPLICANT_MODE_UNKNOWN:
break;
case G_SUPPLICANT_MODE_INFRA:
- return "infra";
+ return "managed";
case G_SUPPLICANT_MODE_IBSS:
return "adhoc";
}
static void callback_interface_added(GSupplicantInterface *interface)
{
- DBG("");
+ SUPPLICANT_DBG("");
if (callbacks_pointer == NULL)
return;
callback_interface_removed(interface);
+ g_free(interface->wps_cred.key);
g_free(interface->path);
+ g_free(interface->network_path);
g_free(interface->ifname);
g_free(interface->driver);
g_free(interface->bridge);
g_hash_table_destroy(network->config_table);
+ g_free(network->path);
g_free(network->group);
g_free(network->name);
g_free(network);
for (i = 0; map[i].str != NULL; i++) {
if (val & map[i].val)
- DBG("%s: %s", label, map[i].str);
+ SUPPLICANT_DBG("%s: %s", label, map[i].str);
}
}
supplicant_dbus_array_foreach(iter,
interface_capability_mode, interface);
else
- DBG("key %s type %c",
+ SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
}
interface->data = data;
}
-const void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
+void *g_supplicant_interface_get_data(GSupplicantInterface *interface)
{
if (interface == NULL)
return NULL;
return interface->state;
}
+const char *g_supplicant_interface_get_wps_key(GSupplicantInterface *interface)
+{
+ if (interface == NULL)
+ return NULL;
+
+ return (const char *)interface->wps_cred.key;
+}
+
+const void *g_supplicant_interface_get_wps_ssid(GSupplicantInterface *interface,
+ unsigned int *ssid_len)
+{
+ if (ssid_len == NULL)
+ return NULL;
+
+ if (interface == NULL || interface->wps_cred.ssid == NULL) {
+ *ssid_len = 0;
+ return NULL;
+ }
+
+ *ssid_len = interface->wps_cred.ssid_len;
+ return interface->wps_cred.ssid;
+}
+
+GSupplicantWpsState g_supplicant_interface_get_wps_state(
+ GSupplicantInterface *interface)
+{
+ if (interface == NULL)
+ return G_SUPPLICANT_WPS_STATE_UNKNOWN;
+
+ return interface->wps_state;
+}
+
GSupplicantInterface *g_supplicant_network_get_interface(
GSupplicantNetwork *network)
{
return network->signal;
}
+dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network)
+{
+ if (network == NULL)
+ return FALSE;
+
+ return network->wps;
+}
+
static void merge_network(GSupplicantNetwork *network)
{
GString *str;
mode = g_hash_table_lookup(network->config_table, "mode");
key_mgmt = g_hash_table_lookup(network->config_table, "key_mgmt");
- DBG("ssid %s mode %s", ssid, mode);
+ SUPPLICANT_DBG("ssid %s mode %s", ssid, mode);
if (ssid != NULL)
ssid_len = strlen(ssid);
g_string_append_printf(str, "%02x", ssid[i]);
if (g_strcmp0(mode, "0") == 0)
- g_string_append_printf(str, "_infra");
+ g_string_append_printf(str, "_managed");
else if (g_strcmp0(mode, "1") == 0)
g_string_append_printf(str, "_adhoc");
group = g_string_free(str, FALSE);
- DBG("%s", group);
+ SUPPLICANT_DBG("%s", group);
g_free(group);
g_strdup(key), g_strdup(str));
}
} else
- DBG("key %s type %c",
+ SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
}
GSupplicantNetwork *network;
const char *path = NULL;
- DBG("");
+ SUPPLICANT_DBG("");
dbus_message_iter_get_basic(iter, &path);
if (path == NULL)
}
supplicant_dbus_property_get_all(path,
- SUPPLICANT_INTERFACE ".Interface.Network",
+ SUPPLICANT_INTERFACE ".Network",
network_property, network);
}
memcpy(network->ssid, bss->ssid, bss->ssid_len);
network->signal = bss->signal;
+ network->wps = FALSE;
+ if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0)
+ network->wps = TRUE;
+
network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
NULL, remove_bss);
}
+static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size,
+ unsigned int type)
+{
+ unsigned int len = 0;
+
+ while (len + 4 < ie_size) {
+ unsigned int hi = ie[len];
+ unsigned int lo = ie[len + 1];
+ unsigned int tmp_type = (hi << 8) + lo;
+ unsigned int v_len = 0;
+
+ /* hi and lo are used to recreate an unsigned int
+ * based on 2 8bits length unsigned int. */
+
+ hi = ie[len + 2];
+ lo = ie[len + 3];
+ v_len = (hi << 8) + lo;
+
+ if (tmp_type == type) {
+ unsigned int ret_value = 0;
+ unsigned char *value = (unsigned char *)&ret_value;
+
+ SUPPLICANT_DBG("IE: match type 0x%x", type);
+
+ /* Verifying length relevance */
+ if (v_len > sizeof(unsigned int) ||
+ len + 4 + v_len > ie_size)
+ break;
+
+ memcpy(value, ie + len + 4, v_len);
+
+ SUPPLICANT_DBG("returning 0x%x", ret_value);
+ return ret_value;
+ }
+
+ len += v_len + 4;
+ }
+
+ SUPPLICANT_DBG("returning 0");
+ return 0;
+}
+
+static void bss_process_ies(DBusMessageIter *iter, void *user_data)
+{
+ struct g_supplicant_bss *bss = user_data;
+ const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
+ unsigned char *ie, *ie_end;
+ DBusMessageIter array;
+ int ie_len;
+
+#define WMM_WPA1_WPS_INFO 221
+#define WPS_INFO_MIN_LEN 6
+#define WPS_VERSION_TLV 0x104A
+#define WPS_STATE_TLV 0x1044
+#define WPS_VERSION 0x10
+
+ dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
+
+ if (ie == NULL || ie_len < 2)
+ return;
+
+ for (ie_end = ie+ie_len; ie+ie[1]+1 <= ie_end; ie += ie[1]+2) {
+ if (ie[0] != WMM_WPA1_WPS_INFO || ie[1] < WPS_INFO_MIN_LEN ||
+ memcmp(ie+2, WPS_OUI, sizeof(WPS_OUI)) != 0)
+ continue;
+
+ SUPPLICANT_DBG("IE: match WPS_OUI");
+
+ if (get_tlv(&ie[6], ie[1],
+ WPS_VERSION_TLV) == WPS_VERSION &&
+ get_tlv(&ie[6], ie[1],
+ WPS_STATE_TLV) != 0)
+ bss->keymgmt |= G_SUPPLICANT_KEYMGMT_WPS;
+ }
+}
static void bss_property(const char *key, DBusMessageIter *iter,
void *user_data)
if (bss->interface == NULL)
return;
- DBG("key %s", key);
+ SUPPLICANT_DBG("key %s", key);
if (key == NULL) {
if (bss->ieee8021x == TRUE)
G_SUPPLICANT_KEYMGMT_WPA_FT_PSK |
G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
bss->psk = TRUE;
- } else
- DBG("key %s type %c",
+ } else if (g_strcmp0(key, "IEs") == 0)
+ bss_process_ies(iter, bss);
+ else
+ SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
}
-static void interface_bss_added(DBusMessageIter *iter, void *user_data)
+static struct g_supplicant_bss *interface_bss_added(DBusMessageIter *iter,
+ void *user_data)
{
GSupplicantInterface *interface = user_data;
GSupplicantNetwork *network;
struct g_supplicant_bss *bss;
const char *path = NULL;
- DBG("");
+ SUPPLICANT_DBG("");
dbus_message_iter_get_basic(iter, &path);
if (path == NULL)
- return;
+ return NULL;
if (g_strcmp0(path, "/") == 0)
- return;
+ return NULL;
- DBG("%s", path);
+ SUPPLICANT_DBG("%s", path);
network = g_hash_table_lookup(interface->bss_mapping, path);
if (network != NULL) {
bss = g_hash_table_lookup(network->bss_table, path);
if (bss != NULL)
- return;
+ return NULL;
}
bss = g_try_new0(struct g_supplicant_bss, 1);
if (bss == NULL)
- return;
+ return NULL;
bss->interface = interface;
bss->path = g_strdup(path);
+ return bss;
+}
+
+static void interface_bss_added_with_keys(DBusMessageIter *iter,
+ void *user_data)
+{
+ struct g_supplicant_bss *bss;
+
+ SUPPLICANT_DBG("");
+
+ bss = interface_bss_added(iter, user_data);
+ if (bss == NULL)
+ return;
+
dbus_message_iter_next(iter);
- if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
- supplicant_dbus_property_foreach(iter, bss_property, bss);
- bss_property(NULL, NULL, bss);
+
+ if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_INVALID)
return;
- }
- supplicant_dbus_property_get_all(path,
- SUPPLICANT_INTERFACE ".Interface.BSS",
+ supplicant_dbus_property_foreach(iter, bss_property, bss);
+ bss_property(NULL, NULL, bss);
+}
+
+static void interface_bss_added_without_keys(DBusMessageIter *iter,
+ void *user_data)
+{
+ struct g_supplicant_bss *bss;
+
+ SUPPLICANT_DBG("");
+
+ bss = interface_bss_added(iter, user_data);
+ if (bss == NULL)
+ return;
+
+ supplicant_dbus_property_get_all(bss->path,
+ SUPPLICANT_INTERFACE ".BSS",
bss_property, bss);
}
if (interface == NULL)
return;
- DBG("%s", key);
+ SUPPLICANT_DBG("%s", key);
if (key == NULL) {
debug_strvalmap("KeyMgmt capability", keymgmt_map,
callback_interface_state(interface);
}
- DBG("state %s (%d)", str, interface->state);
+ SUPPLICANT_DBG("state %s (%d)", str, interface->state);
} else if (g_strcmp0(key, "Scanning") == 0) {
dbus_bool_t scanning = FALSE;
const char *str = NULL;
dbus_message_iter_get_basic(iter, &str);
- if (str != NULL)
+ if (str != NULL) {
+ g_free(interface->ifname);
interface->ifname = g_strdup(str);
+ }
} else if (g_strcmp0(key, "Driver") == 0) {
const char *str = NULL;
dbus_message_iter_get_basic(iter, &str);
- if (str != NULL)
+ if (str != NULL) {
+ g_free(interface->driver);
interface->driver = g_strdup(str);
+ }
} else if (g_strcmp0(key, "BridgeIfname") == 0) {
const char *str = NULL;
dbus_message_iter_get_basic(iter, &str);
- if (str != NULL)
+ if (str != NULL) {
+ g_free(interface->bridge);
interface->bridge = g_strdup(str);
+ }
} else if (g_strcmp0(key, "CurrentBSS") == 0) {
- interface_bss_added(iter, interface);
+ interface_bss_added_without_keys(iter, interface);
} else if (g_strcmp0(key, "CurrentNetwork") == 0) {
interface_network_added(iter, interface);
} else if (g_strcmp0(key, "BSSs") == 0) {
- supplicant_dbus_array_foreach(iter, interface_bss_added,
+ supplicant_dbus_array_foreach(iter, interface_bss_added_without_keys,
interface);
} else if (g_strcmp0(key, "Blobs") == 0) {
/* Nothing */
supplicant_dbus_array_foreach(iter, interface_network_added,
interface);
} else
- DBG("key %s type %c",
+ SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
}
+static void scan_network_update(DBusMessageIter *iter, void *user_data)
+{
+ GSupplicantInterface *interface = user_data;
+ GSupplicantNetwork *network;
+ char *path;
+
+ if (iter == NULL)
+ return;
+
+ dbus_message_iter_get_basic(iter, &path);
+
+ if (path == NULL)
+ return;
+
+ if (g_strcmp0(path, "/") == 0)
+ return;
+
+ /* Update the network details based on scan BSS data */
+ network = g_hash_table_lookup(interface->bss_mapping, path);
+ if (network != NULL)
+ callback_network_added(network);
+}
+
+static void scan_bss_data(const char *key, DBusMessageIter *iter,
+ void *user_data)
+{
+ GSupplicantInterface *interface = user_data;
+
+ if (iter)
+ supplicant_dbus_array_foreach(iter, scan_network_update,
+ interface);
+
+ if (interface->scan_callback != NULL)
+ interface->scan_callback(0, interface, interface->scan_data);
+
+ interface->scan_callback = NULL;
+ interface->scan_data = NULL;
+}
+
static GSupplicantInterface *interface_alloc(const char *path)
{
GSupplicantInterface *interface;
GSupplicantInterface *interface;
const char *path = NULL;
- DBG("");
+ SUPPLICANT_DBG("");
dbus_message_iter_get_basic(iter, &path);
if (path == NULL)
if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INVALID) {
supplicant_dbus_property_foreach(iter, interface_property,
interface);
- DBG("NULL prop");
interface_property(NULL, NULL, interface);
- DBG("DONE");
return;
}
debug_level = i;
break;
}
- DBG("Debug level %d", debug_level);
+ SUPPLICANT_DBG("Debug level %d", debug_level);
} else if (g_strcmp0(key, "DebugTimestamp") == 0) {
dbus_message_iter_get_basic(iter, &debug_timestamp);
- DBG("Debug timestamp %u", debug_timestamp);
+ SUPPLICANT_DBG("Debug timestamp %u", debug_timestamp);
} else if (g_strcmp0(key, "DebugShowKeys") == 0) {
dbus_message_iter_get_basic(iter, &debug_showkeys);
- DBG("Debug show keys %u", debug_showkeys);
+ SUPPLICANT_DBG("Debug show keys %u", debug_showkeys);
} else if (g_strcmp0(key, "Interfaces") == 0) {
supplicant_dbus_array_foreach(iter, interface_added, NULL);
} else if (g_strcmp0(key, "EapMethods") == 0) {
supplicant_dbus_array_foreach(iter, eap_method, NULL);
debug_strvalmap("EAP method", eap_method_map, eap_methods);
+ } else if (g_strcmp0(key, "Country") == 0) {
+ const char *country = NULL;
+
+ dbus_message_iter_get_basic(iter, &country);
+ SUPPLICANT_DBG("Country %s", country);
} else
- DBG("key %s type %c",
+ SUPPLICANT_DBG("key %s type %c",
key, dbus_message_iter_get_arg_type(iter));
}
{
const char *name = NULL, *old = NULL, *new = NULL;
- DBG("");
+ SUPPLICANT_DBG("");
if (g_strcmp0(path, DBUS_PATH_DBUS) != 0)
return;
static void signal_properties_changed(const char *path, DBusMessageIter *iter)
{
- DBG("");
+ SUPPLICANT_DBG("");
if (g_strcmp0(path, SUPPLICANT_PATH) != 0)
return;
static void signal_interface_added(const char *path, DBusMessageIter *iter)
{
- DBG("path %s %s", path, SUPPLICANT_PATH);
+ SUPPLICANT_DBG("path %s %s", path, SUPPLICANT_PATH);
if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
interface_added(iter, NULL);
static void signal_interface_removed(const char *path, DBusMessageIter *iter)
{
- DBG("");
+ SUPPLICANT_DBG("");
if (g_strcmp0(path, SUPPLICANT_PATH) == 0)
interface_removed(iter, NULL);
{
GSupplicantInterface *interface;
- DBG("");
+ SUPPLICANT_DBG("");
interface = g_hash_table_lookup(interface_table, path);
if (interface == NULL)
GSupplicantInterface *interface;
dbus_bool_t success = FALSE;
- DBG("");
+ SUPPLICANT_DBG("");
interface = g_hash_table_lookup(interface_table, path);
if (interface == NULL)
dbus_message_iter_get_basic(iter, &success);
- if (interface->scan_callback != NULL) {
- int result = 0;
+ /*
+ * 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)
+ interface->scan_callback(-EIO, interface,
+ interface->scan_data);
- if (success == FALSE)
- result = -EIO;
+ interface->scan_callback = NULL;
+ interface->scan_data = NULL;
- interface->scan_callback(result, interface,
- interface->scan_data);
+ return;
}
- interface->scan_callback = NULL;
- interface->scan_data = NULL;
+ supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface",
+ "BSSs", scan_bss_data, interface);
}
static void signal_bss_added(const char *path, DBusMessageIter *iter)
{
GSupplicantInterface *interface;
- DBG("");
+ SUPPLICANT_DBG("");
interface = g_hash_table_lookup(interface_table, path);
if (interface == NULL)
return;
- interface_bss_added(iter, interface);
+ interface_bss_added_with_keys(iter, interface);
}
static void signal_bss_removed(const char *path, DBusMessageIter *iter)
{
GSupplicantInterface *interface;
- DBG("");
+ SUPPLICANT_DBG("");
interface = g_hash_table_lookup(interface_table, path);
if (interface == NULL)
{
GSupplicantInterface *interface;
- DBG("");
+ SUPPLICANT_DBG("");
interface = g_hash_table_lookup(interface_table, path);
if (interface == NULL)
{
GSupplicantInterface *interface;
- DBG("");
+ SUPPLICANT_DBG("");
interface = g_hash_table_lookup(interface_table, path);
if (interface == NULL)
GSupplicantNetwork *network;
struct g_supplicant_bss *bss;
- DBG("");
+ SUPPLICANT_DBG("");
interface = g_hash_table_lookup(bss_mapping, path);
if (interface == NULL)
supplicant_dbus_property_foreach(iter, bss_property, bss);
}
+static void wps_credentials(const char *key, DBusMessageIter *iter,
+ void *user_data)
+{
+ GSupplicantInterface *interface = user_data;
+
+ if (key == NULL)
+ return;
+
+ SUPPLICANT_DBG("key %s", key);
+
+ if (g_strcmp0(key, "Key") == 0) {
+ DBusMessageIter array;
+ unsigned char *key;
+ int key_len;
+
+ dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &key, &key_len);
+
+ g_free(interface->wps_cred.key);
+ interface->wps_cred.key = g_try_malloc0(
+ sizeof(char) * key_len+1);
+
+ if (interface->wps_cred.key == NULL)
+ return;
+
+ memcpy(interface->wps_cred.key, key, sizeof(char) * key_len);
+
+ SUPPLICANT_DBG("WPS key present");
+ } else if (g_strcmp0(key, "SSID") == 0) {
+ DBusMessageIter array;
+ unsigned char *ssid;
+ int ssid_len;
+
+ dbus_message_iter_recurse(iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
+
+ if (ssid_len > 0 && ssid_len < 33) {
+ memcpy(interface->wps_cred.ssid, ssid, ssid_len);
+ interface->wps_cred.ssid_len = ssid_len;
+ } else {
+ memset(interface->wps_cred.ssid, 0, 32);
+ interface->wps_cred.ssid_len = 0;
+ }
+ }
+}
+
+static void signal_wps_credentials(const char *path, DBusMessageIter *iter)
+{
+ GSupplicantInterface *interface;
+
+ SUPPLICANT_DBG("");
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (interface == NULL)
+ return;
+
+ supplicant_dbus_property_foreach(iter, wps_credentials, interface);
+}
+
+static void wps_event_args(const char *key, DBusMessageIter *iter,
+ void *user_data)
+{
+ GSupplicantInterface *interface = user_data;
+
+ if (key == NULL || interface == NULL)
+ return;
+
+ SUPPLICANT_DBG("Arg Key %s", key);
+}
+
+static void signal_wps_event(const char *path, DBusMessageIter *iter)
+{
+ GSupplicantInterface *interface;
+ const char *name = NULL;
+
+ SUPPLICANT_DBG("");
+
+ interface = g_hash_table_lookup(interface_table, path);
+ if (interface == NULL)
+ return;
+
+ dbus_message_iter_get_basic(iter, &name);
+
+ SUPPLICANT_DBG("Name: %s", name);
+
+ if (g_strcmp0(name, "success") == 0)
+ interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
+ else if (g_strcmp0(name, "failed") == 0)
+ interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
+ else
+ interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
+
+ if (!dbus_message_iter_has_next(iter))
+ return;
+
+ dbus_message_iter_next(iter);
+
+ supplicant_dbus_property_foreach(iter, wps_event_args, interface);
+}
+
static struct {
const char *interface;
const char *member;
{ SUPPLICANT_INTERFACE ".Interface", "NetworkAdded", signal_network_added },
{ SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved", signal_network_removed },
- { SUPPLICANT_INTERFACE ".Interface.BSS", "PropertiesChanged", signal_bss_changed },
+ { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed },
+
+ { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
+ { SUPPLICANT_INTERFACE ".Interface.WPS", "Event", signal_wps_event },
{ }
};
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
+struct supplicant_regdom {
+ GSupplicantCountryCallback callback;
+ const void *user_data;
+};
+
+static void country_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_regdom *regdom = user_data;
+ char *alpha2;
+
+ SUPPLICANT_DBG("Country setting result");
+
+ if (user_data == NULL)
+ return;
+
+ if (error == NULL) {
+ alpha2 = (char *)regdom->user_data;
+ } else {
+ SUPPLICANT_DBG("Country setting failure %s", error);
+ alpha2 = NULL;
+ }
+
+ if (regdom->callback)
+ regdom->callback(alpha2);
+
+ g_free(regdom);
+}
+
+static void country_params(DBusMessageIter *iter, void *user_data)
+{
+ struct supplicant_regdom *regdom = user_data;
+ const char *country;
+
+ country = regdom->user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &country);
+}
+
+int g_supplicant_set_country(const char *alpha2,
+ GSupplicantCountryCallback callback,
+ const void *user_data)
+{
+ struct supplicant_regdom *regdom;
+
+ SUPPLICANT_DBG("Country setting %s", alpha2);
+
+ if (system_available == FALSE)
+ return -EFAULT;
+
+ regdom = dbus_malloc0(sizeof(*regdom));
+ if (regdom == NULL)
+ return -ENOMEM;
+
+ regdom->callback = callback;
+ regdom->user_data = user_data;
+
+ return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
+ "Country", DBUS_TYPE_STRING_AS_STRING,
+ country_params, country_result,
+ regdom);
+}
+
struct interface_data {
GSupplicantInterface *interface;
GSupplicantInterfaceCallback callback;
const char *path = NULL;
int err;
- DBG("");
+ SUPPLICANT_DBG("");
if (error != NULL) {
- connman_error("error %s", error);
+ g_critical("error %s", error);
err = -EIO;
goto done;
}
struct interface_create_data *data = user_data;
DBusMessageIter dict;
- DBG("");
+ SUPPLICANT_DBG("");
supplicant_dbus_dict_open(iter, &dict);
const char *path = NULL;
int err;
- DBG("");
+ SUPPLICANT_DBG("");
if (error != NULL) {
- connman_error("error %s", error);
+ SUPPLICANT_DBG("Interface not created yet");
err = -EIO;
goto create;
}
goto done;
}
- DBG("Creating interface");
+ SUPPLICANT_DBG("Creating interface");
err = supplicant_dbus_method_call(SUPPLICANT_PATH,
SUPPLICANT_INTERFACE,
{
struct interface_create_data *data = user_data;
- DBG("");
+ SUPPLICANT_DBG("");
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &data->ifname);
}
{
struct interface_create_data *data;
- DBG("ifname %s", ifname);
+ SUPPLICANT_DBG("ifname %s", ifname);
if (ifname == NULL)
return -EINVAL;
goto done;
}
- g_hash_table_remove(interface_table, data->interface->path);
+ /*
+ * The gsupplicant interface is already freed by the InterfaceRemoved
+ * signal callback. Simply invoke the interface_data callback.
+ */
err = 0;
done:
if (data->callback != NULL)
- data->callback(err, data->interface, data->user_data);
+ data->callback(err, NULL, data->user_data);
dbus_free(data);
}
if (interface->scanning == TRUE)
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;
+ case G_SUPPLICANT_STATE_UNKNOWN:
+ case G_SUPPLICANT_STATE_DISCONNECTED:
+ case G_SUPPLICANT_STATE_INACTIVE:
+ case G_SUPPLICANT_STATE_SCANNING:
+ case G_SUPPLICANT_STATE_COMPLETED:
+ break;
+ }
+
data = dbus_malloc0(sizeof(*data));
if (data == NULL)
return -ENOMEM;
static void interface_select_network_result(const char *error,
DBusMessageIter *iter, void *user_data)
{
- DBG("");
+ struct interface_connect_data *data = user_data;
+
+ SUPPLICANT_DBG("");
+
+ g_free(data->ssid);
+ dbus_free(data);
}
static void interface_select_network_params(DBusMessageIter *iter,
void *user_data)
{
- char *path = user_data;
+ struct interface_connect_data *data = user_data;
+ GSupplicantInterface *interface = data->interface;
- dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+ 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;
- char *path = NULL;
+ GSupplicantInterface *interface = data->interface;
+ const char *path;
if (error != NULL)
- goto done;
+ goto error;
dbus_message_iter_get_basic(iter, &path);
if (path == NULL)
- goto done;
+ goto error;
- DBG("PATH: %s", path);
+ 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, path);
+ interface_select_network_result, data);
-done:
- dbus_free(data);
+ return;
+
+error:
+ g_free(interface->network_path);
+ interface->network_path = NULL;
+ g_free(data->ssid);
+ g_free(data);
}
static void add_network_security_wep(DBusMessageIter *dict,
&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 == NULL)
+ return;
+
+ if (ssid->private_key_path == NULL)
+ return;
+
+ if (ssid->private_key_passphrase == NULL)
+ return;
+
+ 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);
+ 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);
+}
+
+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 required
+ * When setting it, we need in addition
+ * The Client private key file
+ * The Client private key file password
+ */
+ if (ssid->passphrase == NULL)
+ return;
+
+ if (ssid->ca_cert_path == NULL)
+ return;
+
+ if (ssid->phase2_auth == NULL)
+ return;
+
+ if (ssid->client_cert_path) {
+ if (ssid->private_key_path == NULL)
+ return;
+
+ if (ssid->private_key_passphrase == NULL)
+ return;
+
+ 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);
+
+ supplicant_dbus_dict_append_basic(dict, "private_key_passwd",
+ DBUS_TYPE_STRING,
+ &ssid->private_key_passphrase);
+
+ }
+
+ 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_dbus_dict_append_basic(dict, "password",
+ DBUS_TYPE_STRING,
+ &ssid->passphrase);
+
+ 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);
+}
+
+static void add_network_security_eap(DBusMessageIter *dict,
+ GSupplicantSSID *ssid)
+{
+ char *eap_value;
+
+ if (ssid->eap == NULL || ssid->identity == NULL)
+ 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) {
+ add_network_security_peap(dict, ssid);
+ } else
+ return;
+
+ eap_value = g_ascii_strup(ssid->eap, -1);
+
+ supplicant_dbus_dict_append_basic(dict, "eap",
+ DBUS_TYPE_STRING,
+ &eap_value);
+ supplicant_dbus_dict_append_basic(dict, "identity",
+ DBUS_TYPE_STRING,
+ &ssid->identity);
+
+ g_free(eap_value);
+}
+
static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
{
char *key_mgmt;
break;
case G_SUPPLICANT_SECURITY_IEEE8021X:
key_mgmt = "WPA-EAP";
+ add_network_security_eap(dict, ssid);
break;
}
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;
+
+ SUPPLICANT_DBG("");
+ if (error != NULL)
+ SUPPLICANT_DBG("error: %s", error);
+
+ 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 != NULL) {
+ 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);
+
+ 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 != NULL) {
+ SUPPLICANT_DBG("error: %s", error);
+ g_free(data->ssid);
+ dbus_free(data);
+ return;
+ }
+
+ supplicant_dbus_method_call(data->interface->path,
+ SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
+ interface_add_wps_params,
+ interface_wps_start_result, data);
+}
+
+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);
+}
+
+
int g_supplicant_interface_connect(GSupplicantInterface *interface,
GSupplicantSSID *ssid,
GSupplicantInterfaceCallback callback,
data->ssid = ssid;
data->user_data = user_data;
- ret = supplicant_dbus_method_call(interface->path,
+ 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)
return ret;
return -EINPROGRESS;
}
-static void interface_disconnect_result(const char *error,
+static void network_remove_result(const char *error,
DBusMessageIter *iter, void *user_data)
{
struct interface_data *data = user_data;
int result = 0;
- DBG("");
+ SUPPLICANT_DBG("");
if (error != NULL)
result = -EIO;
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("");
+
+ return supplicant_dbus_method_call(interface->path,
+ SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
+ network_remove_params, network_remove_result, data);
+}
+
+static void interface_disconnect_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct interface_data *data = user_data;
+
+ SUPPLICANT_DBG("");
+
+ if (error != NULL && data->callback != NULL)
+ data->callback(-EIO, data->interface, data->user_data);
+
+ network_remove(data);
+}
+
int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
GSupplicantInterfaceCallback callback,
void *user_data)
{
struct interface_data *data;
- DBG("");
+ SUPPLICANT_DBG("");
if (interface == NULL)
return -EINVAL;
static const char *g_supplicant_rule3 = "type=signal,"
"interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
static const char *g_supplicant_rule4 = "type=signal,"
- "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
+ "interface=" SUPPLICANT_INTERFACE ".BSS";
static const char *g_supplicant_rule5 = "type=signal,"
- "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
-static const char *g_supplicant_rule6 = "type=signal,"
- "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
+ "interface=" SUPPLICANT_INTERFACE ".Network";
-int g_supplicant_register(const GSupplicantCallbacks *callbacks)
+static void invoke_introspect_method(void)
{
- DBG("");
+ DBusMessage *message;
+
+ message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
+ SUPPLICANT_PATH,
+ DBUS_INTERFACE_INTROSPECTABLE,
+ "Introspect");
+
+ if (message == NULL)
+ return;
+ dbus_message_set_no_reply(message, TRUE);
+ dbus_connection_send(connection, message, NULL);
+ dbus_message_unref(message);
+}
+
+int g_supplicant_register(const GSupplicantCallbacks *callbacks)
+{
connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
if (connection == NULL)
return -EIO;
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);
- dbus_bus_add_match(connection, g_supplicant_rule6, NULL);
dbus_connection_flush(connection);
if (dbus_bus_name_has_owner(connection,
supplicant_dbus_property_get_all(SUPPLICANT_PATH,
SUPPLICANT_INTERFACE,
service_property, NULL);
- }
+ } else
+ invoke_introspect_method();
return 0;
}
void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
{
- DBG("");
+ SUPPLICANT_DBG("");
if (connection != NULL) {
- dbus_bus_remove_match(connection, g_supplicant_rule6, NULL);
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);
bss_mapping = NULL;
}
+ if (system_available == TRUE)
+ callback_system_killed();
+
if (interface_table != NULL) {
g_hash_table_foreach(interface_table,
unregister_remove_interface, NULL);
interface_table = NULL;
}
- if (system_available == TRUE)
- callback_system_killed();
-
if (connection != NULL) {
dbus_connection_unref(connection);
connection = NULL;