dbus_int16_t signal;
GSupplicantMode mode;
GSupplicantSecurity security;
+ dbus_bool_t rsn_selected;
+ unsigned int wpa_keymgmt;
+ unsigned int wpa_pairwise;
+ unsigned int wpa_group;
+ unsigned int rsn_keymgmt;
+ unsigned int rsn_pairwise;
+ unsigned int rsn_group;
unsigned int keymgmt;
- unsigned int pairwise;
- unsigned int group;
dbus_bool_t privacy;
dbus_bool_t psk;
dbus_bool_t ieee8021x;
if (g_str_equal(state, "unknown") == TRUE)
return G_SUPPLICANT_STATE_UNKNOWN;
+ else if (g_str_equal(state, "interface_disabled") == TRUE)
+ return G_SUPPLICANT_STATE_DISABLED;
else if (g_str_equal(state, "disconnected") == TRUE)
return G_SUPPLICANT_STATE_DISCONNECTED;
else if (g_str_equal(state, "inactive") == TRUE)
g_hash_table_destroy(interface->net_mapping);
g_hash_table_destroy(interface->network_table);
+ if (interface->scan_callback != NULL) {
+ SUPPLICANT_DBG("call interface %p callback %p scanning %d",
+ interface, interface->scan_callback,
+ interface->scanning);
+
+ interface->scan_callback(-EIO, interface, interface->scan_data);
+ interface->scan_callback = NULL;
+ interface->scan_data = NULL;
+
+ if (interface->scanning == TRUE) {
+ interface->scanning = FALSE;
+ callback_scan_finished(interface);
+ }
+ }
+
callback_interface_removed(interface);
g_free(interface->wps_cred.key);
dbus_int32_t max_scan_ssid;
dbus_message_iter_get_basic(iter, &max_scan_ssid);
+ if (max_scan_ssid < 1)
+ max_scan_ssid = 1;
interface->max_scan_ssids = max_scan_ssid;
} else
if (interface == NULL)
return 0;
- if (interface->max_scan_ssids == 0)
- return WPAS_MAX_SCAN_SSIDS;
-
return interface->max_scan_ssids;
}
network->frequency = bss->frequency;
network->best_bss = bss;
- network->wps = FALSE;
- if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) {
- network->wps = TRUE;
-
- network->wps_capabilities |= bss->wps_capabilities;
- }
-
SUPPLICANT_DBG("New network %s created", network->name);
network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
callback_network_added(network);
done:
+ /* We update network's WPS properties if only bss provides WPS. */
+ if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) {
+ network->wps = TRUE;
+ network->wps_capabilities |= bss->wps_capabilities;
+ }
+
if (bss->signal > network->signal) {
network->signal = bss->signal;
network->best_bss = bss;
static void bss_keymgmt(DBusMessageIter *iter, void *user_data)
{
- struct g_supplicant_bss *bss = user_data;
+ unsigned int *keymgmt = user_data;
const char *str = NULL;
int i;
for (i = 0; keymgmt_map[i].str != NULL; i++)
if (strcmp(str, keymgmt_map[i].str) == 0) {
- bss->keymgmt |= keymgmt_map[i].val;
+ SUPPLICANT_DBG("Keymgmt: %s", str);
+ *keymgmt |= keymgmt_map[i].val;
break;
}
}
static void bss_group(DBusMessageIter *iter, void *user_data)
{
- struct g_supplicant_bss *bss = user_data;
+ unsigned int *group = user_data;
const char *str = NULL;
int i;
for (i = 0; group_map[i].str != NULL; i++)
if (strcmp(str, group_map[i].str) == 0) {
- bss->group |= group_map[i].val;
+ SUPPLICANT_DBG("Group: %s", str);
+ *group |= group_map[i].val;
break;
}
}
static void bss_pairwise(DBusMessageIter *iter, void *user_data)
{
- struct g_supplicant_bss *bss = user_data;
+ unsigned int *pairwise = user_data;
const char *str = NULL;
int i;
for (i = 0; pairwise_map[i].str != NULL; i++)
if (strcmp(str, pairwise_map[i].str) == 0) {
- bss->pairwise |= pairwise_map[i].val;
+ SUPPLICANT_DBG("Pairwise: %s", str);
+ *pairwise |= pairwise_map[i].val;
break;
}
}
static void bss_wpa(const char *key, DBusMessageIter *iter,
void *user_data)
{
- if (g_strcmp0(key, "KeyMgmt") == 0)
- supplicant_dbus_array_foreach(iter, bss_keymgmt, user_data);
- else if (g_strcmp0(key, "Group") == 0)
- supplicant_dbus_array_foreach(iter, bss_group, user_data);
- else if (g_strcmp0(key, "Pairwise") == 0)
- supplicant_dbus_array_foreach(iter, bss_pairwise, user_data);
+ struct g_supplicant_bss *bss = user_data;
+ unsigned int value = 0;
+
+ SUPPLICANT_DBG("Key: %s", key);
+
+ if (g_strcmp0(key, "KeyMgmt") == 0) {
+ supplicant_dbus_array_foreach(iter, bss_keymgmt, &value);
+
+ if (bss->rsn_selected == TRUE)
+ 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)
+ 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)
+ bss->rsn_pairwise = value;
+ else
+ bss->wpa_pairwise = value;
+ }
}
static unsigned int get_tlv(unsigned char *ie, unsigned int ie_size,
if (ie == NULL || ie_len < 2)
return;
+ bss->wps_capabilities = 0;
+ bss->keymgmt = 0;
+
for (ie_end = ie + ie_len; ie < ie_end && ie + ie[1] + 1 <= ie_end;
ie += ie[1] + 2) {
static void bss_compute_security(struct g_supplicant_bss *bss)
{
+ /*
+ * Combining RSN and WPA keymgmt
+ * We combine it since parsing IEs might have set something for WPS. */
+ bss->keymgmt |= bss->rsn_keymgmt | bss->wpa_keymgmt;
+
+ bss->ieee8021x = FALSE;
+ bss->psk = FALSE;
+
+ if (bss->keymgmt &
+ (G_SUPPLICANT_KEYMGMT_WPA_EAP |
+ G_SUPPLICANT_KEYMGMT_WPA_FT_EAP |
+ G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
+ bss->ieee8021x = TRUE;
+
+ if (bss->keymgmt &
+ (G_SUPPLICANT_KEYMGMT_WPA_PSK |
+ G_SUPPLICANT_KEYMGMT_WPA_FT_PSK |
+ G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
+ bss->psk = TRUE;
+
if (bss->ieee8021x == TRUE)
bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
else if (bss->psk == TRUE)
dbus_message_iter_get_basic(iter, &privacy);
bss->privacy = privacy;
- } else if ((g_strcmp0(key, "RSN") == 0) ||
- (g_strcmp0(key, "WPA") == 0)) {
- supplicant_dbus_property_foreach(iter, bss_wpa, bss);
+ } else if (g_strcmp0(key, "RSN") == 0) {
+ bss->rsn_selected = TRUE;
- if (bss->keymgmt &
- (G_SUPPLICANT_KEYMGMT_WPA_EAP |
- G_SUPPLICANT_KEYMGMT_WPA_FT_EAP |
- G_SUPPLICANT_KEYMGMT_WPA_EAP_256))
- bss->ieee8021x = TRUE;
+ supplicant_dbus_property_foreach(iter, bss_wpa, bss);
+ } else if (g_strcmp0(key, "WPA") == 0) {
+ bss->rsn_selected = FALSE;
- if (bss->keymgmt &
- (G_SUPPLICANT_KEYMGMT_WPA_PSK |
- G_SUPPLICANT_KEYMGMT_WPA_FT_PSK |
- G_SUPPLICANT_KEYMGMT_WPA_PSK_256))
- bss->psk = TRUE;
+ supplicant_dbus_property_foreach(iter, bss_wpa, bss);
} else if (g_strcmp0(key, "IEs") == 0)
bss_process_ies(iter, bss);
else
debug_strvalmap("Mode capability", mode_capa_map,
interface->mode_capa);
- interface->ready = TRUE;
callback_interface_added(interface);
return;
}
interface->state = string2state(str);
callback_interface_state(interface);
}
+ if (interface->state == G_SUPPLICANT_STATE_DISABLED)
+ interface->ready = FALSE;
+ else
+ interface->ready = TRUE;
SUPPLICANT_DBG("state %s (%d)", str, interface->state);
} else if (g_strcmp0(key, "Scanning") == 0) {
/* Security change policy:
* - we first copy the current bss into a new one with
* its own pointer (path)
- * - we remove the current bss related nework which will
+ * - we remove the current bss related network which will
* tell the plugin about such removal. This is done due
* to the fact that a security change means a group change
* so a complete network change.
if (g_strcmp0(key, "Key") == 0) {
DBusMessageIter array;
- unsigned char *key;
+ unsigned char *key_val;
int key_len;
dbus_message_iter_recurse(iter, &array);
- dbus_message_iter_get_fixed_array(&array, &key, &key_len);
+ dbus_message_iter_get_fixed_array(&array, &key_val, &key_len);
g_free(interface->wps_cred.key);
interface->wps_cred.key = g_try_malloc0(
- sizeof(char) * key_len+1);
+ sizeof(char) * key_len + 1);
if (interface->wps_cred.key == NULL)
return;
- memcpy(interface->wps_cred.key, key, sizeof(char) * key_len);
+ memcpy(interface->wps_cred.key, key_val,
+ sizeof(char) * key_len);
SUPPLICANT_DBG("WPS key present");
} else if (g_strcmp0(key, "SSID") == 0) {
struct supplicant_regdom {
GSupplicantCountryCallback callback;
+ const char *alpha2;
const void *user_data;
};
DBusMessageIter *iter, void *user_data)
{
struct supplicant_regdom *regdom = user_data;
- char *alpha2;
+ int result = 0;
SUPPLICANT_DBG("Country setting result");
if (user_data == NULL)
return;
- if (error == NULL) {
- alpha2 = (char *)regdom->user_data;
- } else {
+ if (error != NULL) {
SUPPLICANT_DBG("Country setting failure %s", error);
- alpha2 = NULL;
+ result = -EINVAL;
}
if (regdom->callback)
- regdom->callback(alpha2);
+ regdom->callback(result, regdom->alpha2,
+ (void *) regdom->user_data);
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);
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+ ®dom->alpha2);
}
int g_supplicant_set_country(const char *alpha2,
return -ENOMEM;
regdom->callback = callback;
+ regdom->alpha2 = alpha2;
regdom->user_data = user_data;
return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
regdom);
}
+int g_supplicant_interface_set_country(GSupplicantInterface *interface,
+ GSupplicantCountryCallback callback,
+ const char *alpha2,
+ void *user_data)
+{
+ struct supplicant_regdom *regdom;
+
+ regdom = dbus_malloc0(sizeof(*regdom));
+ if (regdom == NULL)
+ return -ENOMEM;
+
+ regdom->callback = callback;
+ regdom->alpha2 = alpha2;
+ regdom->user_data = user_data;
+
+ return supplicant_dbus_property_set(interface->path,
+ SUPPLICANT_INTERFACE ".Interface",
+ "Country", DBUS_TYPE_STRING_AS_STRING,
+ country_params, country_result,
+ regdom);
+}
+
struct interface_data {
GSupplicantInterface *interface;
GSupplicantInterfaceCallback callback;
void *user_data;
};
+struct interface_autoscan_data {
+ GSupplicantInterface *interface;
+ GSupplicantInterfaceCallback callback;
+ const char *autoscan_params;
+ void *user_data;
+};
+
static void interface_create_property(const char *key, DBusMessageIter *iter,
void *user_data)
{
SUPPLICANT_DBG("");
if (error != NULL) {
- g_critical("error %s", error);
+ g_warning("error %s", error);
err = -EIO;
goto done;
}
if (error != NULL) {
SUPPLICANT_DBG("Interface not created yet");
- err = -EIO;
goto create;
}
DBusMessageIter *iter, void *user_data)
{
struct interface_scan_data *data = user_data;
+ int err = 0;
if (error != NULL) {
SUPPLICANT_DBG("error %s", error);
+ err = -EIO;
+ }
+
+ /* A non ready interface cannot send/receive anything */
+ if (data->interface->ready == FALSE)
+ err = -ENOLINK;
+ if (err != 0) {
if (data->callback != NULL)
- data->callback(-EIO, data->interface, data->user_data);
+ data->callback(err, data->interface, data->user_data);
} else {
data->interface->scan_callback = data->callback;
data->interface->scan_data = data->user_data;
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:
return ret;
}
+static void interface_autoscan_result(const char *error,
+ DBusMessageIter *iter, void *user_data)
+{
+ struct interface_autoscan_data *data = user_data;
+ int err = 0;
+
+ if (error != NULL) {
+ SUPPLICANT_DBG("error %s", error);
+ err = -EIO;
+ }
+
+ if (data != NULL && data->callback != NULL)
+ data->callback(err, data->interface, data->user_data);
+
+ dbus_free(data);
+}
+
+static void interface_autoscan_params(DBusMessageIter *iter, void *user_data)
+{
+ struct interface_autoscan_data *data = user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+ &data->autoscan_params);
+}
+
+int g_supplicant_interface_autoscan(GSupplicantInterface *interface,
+ const char *autoscan_data,
+ GSupplicantInterfaceCallback callback,
+ void *user_data)
+{
+ struct interface_autoscan_data *data;
+ int ret;
+
+ data = dbus_malloc0(sizeof(*data));
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->interface = interface;
+ data->callback = callback;
+ data->autoscan_params = autoscan_data;
+ data->user_data = user_data;
+
+ 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 ret;
+}
+
static int parse_supplicant_error(DBusMessageIter *iter)
{
int err = -ECANCELED;
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) == TRUE)
- supplicant_dbus_property_append_fixed_array(dict,
- "psk", DBUS_TYPE_BYTE,
- &ssid->passphrase, 64);
- else
- supplicant_dbus_dict_append_basic(dict, "psk",
- DBUS_TYPE_STRING,
+ if (is_psk_raw_key(ssid->passphrase) == TRUE) {
+ 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);
}
}
SUPPLICANT_DBG("");
- if (error != NULL)
+ if (error != NULL) {
result = -EIO;
+ if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
+ error) == 0)
+ result = -ECONNABORTED;
+ }
if (data->callback != NULL)
data->callback(result, data->interface, data->user_data);
DBusMessageIter *iter, void *user_data)
{
struct interface_data *data = user_data;
+ int result = 0;
SUPPLICANT_DBG("");
- if (error != NULL && data->callback != NULL)
- data->callback(-EIO, data->interface, data->user_data);
+ if (error != NULL) {
+ result = -EIO;
+ if (g_strcmp0("org.freedesktop.DBus.Error.UnknownMethod",
+ error) == 0)
+ result = -ECONNABORTED;
+ }
+
+ if (result < 0 && data->callback != NULL) {
+ 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,
return;
}
- network_remove(data);
+ if (result != -ECONNABORTED)
+ network_remove(data);
+ else
+ dbus_free(data);
}
int g_supplicant_interface_disconnect(GSupplicantInterface *interface,