close(fd);
+ if (err < 0)
+ task->range->max_qual.updated |= IW_QUAL_ALL_INVALID;
+
+ connman_info("%s {scan} capabilities 0x%02x", task->ifname,
+ task->range->scan_capa);
+
+ connman_info("%s {quality} flags 0x%02x", task->ifname,
+ task->range->max_qual.updated);
+
return err;
}
dbus_message_iter_append_basic(&array,
DBUS_TYPE_STRING, &task->ifname);
- dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+ connman_dbus_dict_open(&array, &dict);
- connman_dbus_dict_append_variant(&dict, "driver",
+ connman_dbus_dict_append_basic(&dict, "driver",
DBUS_TYPE_STRING, &driver);
- dbus_message_iter_close_container(&array, &dict);
+ connman_dbus_dict_close(&array, &dict);
if (dbus_connection_send_with_reply(connection, message,
&call, TIMEOUT) == FALSE) {
return 0;
}
+static int set_network_tls(struct connman_network *network,
+ DBusMessageIter *dict)
+{
+ const char *private_key, *client_cert, *ca_cert;
+ const char *private_key_password;
+
+ /*
+ * For TLS, we at least need a key, the client cert,
+ * and a passhprase.
+ * Server cert is optional.
+ */
+ client_cert = connman_network_get_string(network,
+ "WiFi.ClientCertFile");
+ if (client_cert == NULL)
+ return -EINVAL;
+
+ private_key = connman_network_get_string(network,
+ "WiFi.PrivateKeyFile");
+ if (private_key == NULL)
+ return -EINVAL;
+
+ private_key_password = connman_network_get_string(network,
+ "WiFi.PrivateKeyPassphrase");
+ if (private_key_password == NULL)
+ return -EINVAL;
+
+ ca_cert = connman_network_get_string(network, "WiFi.CACertFile");
+ if (ca_cert)
+ connman_dbus_dict_append_basic(dict, "ca_cert",
+ DBUS_TYPE_STRING, &ca_cert);
+
+ DBG("client cert %s private key %s", client_cert, private_key);
+
+ connman_dbus_dict_append_basic(dict, "private_key",
+ DBUS_TYPE_STRING, &private_key);
+ connman_dbus_dict_append_basic(dict, "private_key_passwd",
+ DBUS_TYPE_STRING,
+ &private_key_password);
+ connman_dbus_dict_append_basic(dict, "client_cert",
+ DBUS_TYPE_STRING, &client_cert);
+
+ return 0;
+}
+
+static int set_network_peap(struct connman_network *network,
+ DBusMessageIter *dict, const char *passphrase)
+{
+ const char *client_cert, *ca_cert, *phase2;
+ char *phase2_auth;
+
+ /*
+ * For PEAP, we at least need the sever cert, a 2nd
+ * phase authentication and a passhprase.
+ * Client cert is optional although strongly required
+ * When setting the client cert, we then need a private
+ * key as well.
+ */
+ ca_cert = connman_network_get_string(network, "WiFi.CACertFile");
+ if (ca_cert == NULL)
+ return -EINVAL;
+
+ phase2 = connman_network_get_string(network, "WiFi.Phase2");
+ if (phase2 == NULL)
+ return -EINVAL;
+
+ DBG("CA cert %s phase2 auth %s", ca_cert, phase2);
+
+ client_cert = connman_network_get_string(network,
+ "WiFi.ClientCertFile");
+ if (client_cert) {
+ const char *private_key, *private_key_password;
+
+ private_key = connman_network_get_string(network,
+ "WiFi.PrivateKeyFile");
+ if (private_key == NULL)
+ return -EINVAL;
+
+ private_key_password =
+ connman_network_get_string(network,
+ "WiFi.PrivateKeyPassphrase");
+ if (private_key_password == NULL)
+ return -EINVAL;
+
+ connman_dbus_dict_append_basic(dict, "client_cert",
+ DBUS_TYPE_STRING, &client_cert);
+
+ connman_dbus_dict_append_basic(dict, "private_key",
+ DBUS_TYPE_STRING, &private_key);
+
+ connman_dbus_dict_append_basic(dict, "private_key_passwd",
+ DBUS_TYPE_STRING,
+ &private_key_password);
+
+ DBG("client cert %s private key %s", client_cert, private_key);
+ }
+
+ phase2_auth = g_strdup_printf("\"auth=%s\"", phase2);
+
+ connman_dbus_dict_append_basic(dict, "password",
+ DBUS_TYPE_STRING, &passphrase);
+
+ connman_dbus_dict_append_basic(dict, "ca_cert",
+ DBUS_TYPE_STRING, &ca_cert);
+
+ connman_dbus_dict_append_basic(dict, "phase2",
+ DBUS_TYPE_STRING, &phase2_auth);
+
+ g_free(phase2_auth);
+
+ return 0;
+}
+
static int set_network(struct supplicant_task *task,
const unsigned char *network, int len,
const char *address, const char *security,
dbus_message_iter_init_append(message, &array);
- dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
- DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
- DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
- DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+ connman_dbus_dict_open(&array, &dict);
- connman_dbus_dict_append_variant(&dict, "scan_ssid",
+ connman_dbus_dict_append_basic(&dict, "scan_ssid",
DBUS_TYPE_UINT32, &scan_ssid);
if (network)
- connman_dbus_dict_append_array(&dict, "ssid",
+ connman_dbus_dict_append_fixed_array(&dict, "ssid",
DBUS_TYPE_BYTE, &network, len);
else if (address)
- connman_dbus_dict_append_variant(&dict, "bssid",
+ connman_dbus_dict_append_basic(&dict, "bssid",
DBUS_TYPE_STRING, &address);
- if (g_ascii_strcasecmp(security, "wpa") == 0 ||
+ if (g_ascii_strcasecmp(security, "psk") == 0 ||
+ g_ascii_strcasecmp(security, "wpa") == 0 ||
g_ascii_strcasecmp(security, "rsn") == 0) {
const char *key_mgmt = "WPA-PSK";
- connman_dbus_dict_append_variant(&dict, "key_mgmt",
+ connman_dbus_dict_append_basic(&dict, "key_mgmt",
DBUS_TYPE_STRING, &key_mgmt);
if (passphrase && strlen(passphrase) > 0)
- connman_dbus_dict_append_variant(&dict, "psk",
+ connman_dbus_dict_append_basic(&dict, "psk",
DBUS_TYPE_STRING, &passphrase);
+ } else if (g_ascii_strcasecmp(security, "ieee8021x") == 0) {
+ struct connman_network *network = task->network;
+ const char *key_mgmt = "WPA-EAP", *eap, *identity;
+ char *eap_value;
+
+ /*
+ * If our private key password is unset,
+ * we use the supplied passphrase. That is needed
+ * for PEAP where 2 passphrases (identity and client
+ * cert may have to be provided.
+ */
+ if (connman_network_get_string(network,
+ "WiFi.PrivateKeyPassphrase") == NULL)
+ connman_network_set_string(network,
+ "WiFi.PrivateKeyPassphrase",
+ passphrase);
+
+ eap = connman_network_get_string(network, "WiFi.EAP");
+ if (eap == NULL)
+ goto invalid;
+
+ /* We must have an identity for both PEAP and TLS */
+ identity = connman_network_get_string(network, "WiFi.Identity");
+ if (identity == NULL)
+ goto invalid;
+
+ DBG("key_mgmt %s eap %s identity %s", key_mgmt, eap, identity);
+
+ if (g_strcmp0(eap, "tls") == 0) {
+ int err;
+
+ err = set_network_tls(network, &dict);
+ if (err < 0) {
+ dbus_message_unref(message);
+ return err;
+ }
+ } else if (g_strcmp0(eap, "peap") == 0) {
+ int err;
+
+ err = set_network_peap(network, &dict, passphrase);
+ if (err < 0) {
+ dbus_message_unref(message);
+ return err;
+ }
+ } else {
+ connman_error("Unknown EAP %s", eap);
+ goto invalid;
+ }
+
+ /* wpa_supplicant only accepts upper case EAPs */
+ eap_value = g_ascii_strup(eap, -1);
+
+ connman_dbus_dict_append_basic(&dict, "key_mgmt",
+ DBUS_TYPE_STRING,
+ &key_mgmt);
+ connman_dbus_dict_append_basic(&dict, "eap",
+ DBUS_TYPE_STRING,
+ &eap_value);
+ connman_dbus_dict_append_basic(&dict, "identity",
+ DBUS_TYPE_STRING,
+ &identity);
+
+ g_free(eap_value);
+
} else if (g_ascii_strcasecmp(security, "wep") == 0) {
const char *key_mgmt = "NONE";
const char *auth_alg = "OPEN";
if (task->mac80211 == TRUE)
auth_alg = "OPEN SHARED";
- connman_dbus_dict_append_variant(&dict, "auth_alg",
+ connman_dbus_dict_append_basic(&dict, "auth_alg",
DBUS_TYPE_STRING, &auth_alg);
- connman_dbus_dict_append_variant(&dict, "key_mgmt",
+ connman_dbus_dict_append_basic(&dict, "key_mgmt",
DBUS_TYPE_STRING, &key_mgmt);
if (passphrase) {
key[i] = (unsigned char) strtol(tmp,
NULL, 16);
}
- connman_dbus_dict_append_array(&dict,
+ connman_dbus_dict_append_fixed_array(&dict,
"wep_key0", DBUS_TYPE_BYTE,
&key, size / 2);
free(key);
} else
- connman_dbus_dict_append_variant(&dict,
+ connman_dbus_dict_append_basic(&dict,
"wep_key0", DBUS_TYPE_STRING,
&passphrase);
- connman_dbus_dict_append_variant(&dict, "wep_tx_keyidx",
+ connman_dbus_dict_append_basic(&dict, "wep_tx_keyidx",
DBUS_TYPE_STRING, &key_index);
}
} else {
const char *key_mgmt = "NONE";
- connman_dbus_dict_append_variant(&dict, "key_mgmt",
+ connman_dbus_dict_append_basic(&dict, "key_mgmt",
DBUS_TYPE_STRING, &key_mgmt);
}
- dbus_message_iter_close_container(&array, &dict);
+ connman_dbus_dict_close(&array, &dict);
dbus_error_init(&error);
dbus_message_unref(reply);
return 0;
+
+invalid:
+ dbus_message_unref(message);
+ return -EINVAL;
}
static void scan_reply(DBusPendingCall *call, void *user_data)
dbus_message_iter_recurse(value, &array);
dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
- if (ie_len > 0) {
+ if (ie_len > 6) {
result->has_wpa = TRUE;
extract_rsn(result, ie + 6, ie_len - 6);
}
dbus_message_iter_recurse(value, &array);
dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
- if (ie_len > 0) {
+ if (ie_len > 2) {
result->has_rsn = TRUE;
extract_rsn(result, ie + 2, ie_len - 2);
}
static unsigned char calculate_strength(struct supplicant_task *task,
struct supplicant_result *result)
{
- if (task->range->max_qual.qual == 0) {
+ if (result->quality == -1 || task->range->max_qual.qual == 0) {
unsigned char strength;
if (result->level > 0)
dbus_message_iter_next(&dict);
}
+ DBG("capabilties %u frequency %d "
+ "quality %d noise %d level %d maxrate %d",
+ result.capabilities, result.frequency,
+ result.quality, result.noise,
+ result.level, result.maxrate);
+
if (result.path == NULL)
goto done;
if (result.has_8021x == TRUE)
security = "ieee8021x";
- else if (result.has_rsn == TRUE)
- security = "rsn";
- else if (result.has_wpa == TRUE)
- security = "wpa";
else if (result.has_psk == TRUE)
security = "psk";
else if (result.has_wep == TRUE)
result.ssid, result.ssid_len,
mode, security);
+ if (result.has_psk == TRUE) {
+ if (result.has_rsn == TRUE)
+ security = "rsn";
+ else if (result.has_wpa == TRUE)
+ security = "wpa";
+ }
+
network = connman_device_get_network(task->device, result.path);
if (network == NULL) {
int index;
add_network(task);
- set_network(task, ssid, ssid_len, address, security, passphrase);
+ err = set_network(task, ssid, ssid_len, address, security, passphrase);
+ if (err < 0)
+ return err;
err = select_network(task);
if (err < 0)
bssid, bssid_len);
/* carrier on */
+ connman_network_set_method(task->network,
+ CONNMAN_IPCONFIG_METHOD_DHCP);
connman_network_set_connected(task->network, TRUE);
break;
oldstate, newstate);
}
-static DBusHandlerResult supplicant_filter(DBusConnection *conn,
+static gboolean supplicant_filter(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct supplicant_task *task;
const char *member, *path;
- if (dbus_message_has_interface(msg,
- SUPPLICANT_INTF ".Interface") == FALSE)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
member = dbus_message_get_member(msg);
if (member == NULL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return TRUE;
path = dbus_message_get_path(msg);
if (path == NULL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return TRUE;
task = find_task_by_path(path);
if (task == NULL)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return TRUE;
DBG("task %p member %s", task, member);
else if (g_str_equal(member, "StateChange") == TRUE)
state_change(task, msg);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ return TRUE;
}
int supplicant_start(struct connman_device *device)
}
}
-static const char *supplicant_rule = "type=signal,"
- "interface=" SUPPLICANT_INTF ".Interface";
static guint watch;
+static guint iface_watch;
static int supplicant_create(void)
{
DBG("connection %p", connection);
- if (dbus_connection_add_filter(connection,
- supplicant_filter, NULL, NULL) == FALSE) {
- connection = connman_dbus_get_connection();
- return -EIO;
- }
-
- dbus_bus_add_match(connection, supplicant_rule, NULL);
- dbus_connection_flush(connection);
-
watch = g_dbus_add_service_watch(connection, SUPPLICANT_NAME,
supplicant_probe, supplicant_remove, NULL, NULL);
+ iface_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ SUPPLICANT_INTF ".Interface",
+ NULL, supplicant_filter,
+ NULL, NULL);
+
+ if (watch == 0 || iface_watch == 0) {
+ g_dbus_remove_watch(connection, watch);
+ g_dbus_remove_watch(connection, iface_watch);
+ return -EIO;
+ }
+
return 0;
}
DBG("connection %p", connection);
- if (watch > 0)
- g_dbus_remove_watch(connection, watch);
-
- dbus_bus_remove_match(connection, supplicant_rule, NULL);
- dbus_connection_flush(connection);
-
- dbus_connection_remove_filter(connection, supplicant_filter, NULL);
+ g_dbus_remove_watch(connection, watch);
+ g_dbus_remove_watch(connection, iface_watch);
dbus_connection_unref(connection);
connection = NULL;