#include <string.h>
#include <stdint.h>
#include <syslog.h>
+#include <ctype.h>
#include <glib.h>
#include <gdbus.h>
void *data;
};
-struct _GSupplicantNetwork {
- GSupplicantInterface *interface;
- char *path;
- char *group;
- char *name;
- unsigned char ssid[32];
- unsigned int ssid_len;
- dbus_int16_t signal;
- GSupplicantMode mode;
- GSupplicantSecurity security;
- dbus_bool_t wps;
- GHashTable *bss_table;
- GHashTable *config_table;
-};
-
struct g_supplicant_bss {
GSupplicantInterface *interface;
char *path;
dbus_bool_t ieee8021x;
};
+struct _GSupplicantNetwork {
+ GSupplicantInterface *interface;
+ char *path;
+ char *group;
+ char *name;
+ unsigned char ssid[32];
+ unsigned int ssid_len;
+ dbus_int16_t signal;
+ dbus_uint16_t frequency;
+ struct g_supplicant_bss *best_bss;
+ GSupplicantMode mode;
+ GSupplicantSecurity security;
+ dbus_bool_t wps;
+ GHashTable *bss_table;
+ GHashTable *config_table;
+};
+
static inline void debug(const char *format, ...)
{
char str[256];
callbacks_pointer->network_removed(network);
}
+static void callback_network_changed(GSupplicantNetwork *network,
+ const char *property)
+{
+ if (callbacks_pointer == NULL)
+ return;
+
+ if (callbacks_pointer->network_changed == NULL)
+ return;
+
+ callbacks_pointer->network_changed(network, property);
+}
+
static void remove_interface(gpointer data)
{
GSupplicantInterface *interface = data;
key, dbus_message_iter_get_arg_type(iter));
}
+static void set_apscan(DBusMessageIter *iter, void *user_data)
+{
+ unsigned int ap_scan = *(unsigned int *)user_data;
+
+ dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ap_scan);
+}
+
+int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
+ unsigned int ap_scan)
+{
+ return supplicant_dbus_property_set(interface->path,
+ SUPPLICANT_INTERFACE ".Interface",
+ "ApScan", DBUS_TYPE_UINT32_AS_STRING,
+ set_apscan, NULL, &ap_scan);
+}
+
void g_supplicant_interface_set_data(GSupplicantInterface *interface,
void *data)
{
return network->signal;
}
+dbus_uint16_t g_supplicant_network_get_frequency(GSupplicantNetwork *network)
+{
+ if (network == NULL)
+ return 0;
+
+ return network->frequency;
+}
+
dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network)
{
if (network == NULL)
network->ssid_len = bss->ssid_len;
memcpy(network->ssid, bss->ssid, bss->ssid_len);
network->signal = bss->signal;
+ network->frequency = bss->frequency;
+ network->best_bss = bss;
network->wps = FALSE;
if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0)
callback_network_added(network);
done:
+ if (bss->signal > network->signal) {
+ network->signal = bss->signal;
+ network->best_bss = bss;
+ callback_network_changed(network, "Signal");
+ }
+
g_hash_table_replace(interface->bss_mapping, bss->path, network);
g_hash_table_replace(network->bss_table, bss->path, bss);
if (ie == NULL || ie_len < 2)
return;
- for (ie_end = ie+ie_len; ie+ie[1]+1 <= ie_end; ie += ie[1]+2) {
+ for (ie_end = ie + ie_len; ie < ie_end && 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;
bss_property, bss);
}
+static void update_signal(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ struct g_supplicant_bss *bss = value;
+ GSupplicantNetwork *network = user_data;
+
+ if (bss->signal > network->signal) {
+ network->signal = bss->signal;
+ network->best_bss = bss;
+ }
+}
+
+static void update_network_signal(GSupplicantNetwork *network)
+{
+ if (g_hash_table_size(network->bss_table) <= 1)
+ return;
+
+ g_hash_table_foreach(network->bss_table,
+ update_signal, network);
+
+ SUPPLICANT_DBG("New network signal %d", network->signal);
+}
+
static void interface_bss_removed(DBusMessageIter *iter, void *user_data)
{
GSupplicantInterface *interface = user_data;
g_hash_table_remove(interface->bss_mapping, path);
g_hash_table_remove(network->bss_table, path);
+ update_network_signal(network);
+
if (g_hash_table_size(network->bss_table) == 0)
g_hash_table_remove(interface->network_table, network->group);
}
return;
supplicant_dbus_property_foreach(iter, bss_property, bss);
+
+ if (bss->signal == network->signal)
+ return;
+
+ /*
+ * If the new signal is lower than the SSID signal, we need
+ * to check for the new maximum.
+ */
+ if (bss->signal < network->signal) {
+ if (bss != network->best_bss)
+ return;
+ network->signal = bss->signal;
+ update_network_signal(network);
+ } else {
+ network->signal = bss->signal;
+ network->best_bss = bss;
+ }
+
+ SUPPLICANT_DBG("New network signal for %s %d dBm", network->ssid, network->signal);
+
+ callback_network_changed(network, "Signal");
}
static void wps_credentials(const char *key, DBusMessageIter *iter,
struct interface_create_data {
const char *ifname;
const char *driver;
+ const char *bridge;
GSupplicantInterface *interface;
GSupplicantInterfaceCallback callback;
void *user_data;
supplicant_dbus_dict_append_basic(&dict, "Driver",
DBUS_TYPE_STRING, &data->driver);
+ if (data->bridge != NULL)
+ supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
+ DBUS_TYPE_STRING, &data->bridge);
+
supplicant_dbus_dict_close(iter, &dict);
}
}
int g_supplicant_interface_create(const char *ifname, const char *driver,
+ const char *bridge,
GSupplicantInterfaceCallback callback,
void *user_data)
{
data->ifname = ifname;
data->driver = driver;
+ data->bridge = bridge;
data->callback = callback;
data->user_data = user_data;
interface_scan_params, interface_scan_result, data);
}
+static int parse_supplicant_error(DBusMessageIter *iter)
+{
+ int err = -ECANCELED;
+ char *key;
+
+ while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+ dbus_message_iter_get_basic(iter, &key);
+ if (strncmp(key, "psk", 4) == 0 ||
+ strncmp(key, "wep_key", 7) == 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 != NULL) {
+ SUPPLICANT_DBG("SelectNetwork error %s", error);
+ err = parse_supplicant_error(iter);
+ }
+
+ if (data->callback != NULL)
+ data->callback(err, data->interface, data->user_data);
+
g_free(data->ssid);
dbus_free(data);
}
struct interface_connect_data *data = user_data;
GSupplicantInterface *interface = data->interface;
const char *path;
+ int err;
if (error != NULL)
goto error;
return;
error:
+ SUPPLICANT_DBG("AddNetwork error %s", error);
+ err = parse_supplicant_error(iter);
+ if (data->callback != NULL)
+ data->callback(err, data->interface, data->user_data);
+
g_free(interface->network_path);
interface->network_path = NULL;
g_free(data->ssid);
}
}
+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 void add_network_security_psk(DBusMessageIter *dict,
GSupplicantSSID *ssid)
{
- if (ssid->passphrase && strlen(ssid->passphrase) > 0)
+ if (ssid->passphrase && strlen(ssid->passphrase) > 0) {
+
+ 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,
+ DBUS_TYPE_STRING,
&ssid->passphrase);
+ }
}
static void add_network_security_tls(DBusMessageIter *dict,
* The 2nd phase authentication method
* The 2nd phase passphrase
*
- * The Client certificate is optional although strongly required
+ * 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)
return;
- if (ssid->ca_cert_path == NULL)
- return;
-
if (ssid->phase2_auth == NULL)
return;
DBUS_TYPE_STRING,
&ssid->passphrase);
- supplicant_dbus_dict_append_basic(dict, "ca_cert",
+ if (ssid->ca_cert_path)
+ supplicant_dbus_dict_append_basic(dict, "ca_cert",
DBUS_TYPE_STRING,
&ssid->ca_cert_path);
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);
+}
+
static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
{
char *key_mgmt;
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;
}
static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
{
DBusMessageIter dict;
- dbus_uint32_t scan_ssid = 1;
struct interface_connect_data *data = user_data;
GSupplicantSSID *ssid = data->ssid;
supplicant_dbus_dict_open(iter, &dict);
- supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
- DBUS_TYPE_UINT32, &scan_ssid);
+ 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",