wifi/iwd: merge branch 'balrog-kun/iwd-known-networks'
https://github.com/NetworkManager/NetworkManager/pull/183
This commit is contained in:
@@ -2804,6 +2804,7 @@ static EAPMethodsTable eap_methods_table[] = {
|
||||
{ "sim", need_secrets_sim, NULL },
|
||||
{ "gtc", need_secrets_password, verify_identity },
|
||||
{ "otp", NULL, NULL }, // FIXME: implement
|
||||
{ "external", NULL, NULL },
|
||||
{ NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
@@ -2812,7 +2813,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
|
||||
{
|
||||
NMSetting8021x *self = NM_SETTING_802_1X (setting);
|
||||
NMSetting8021xPrivate *priv = NM_SETTING_802_1X_GET_PRIVATE (self);
|
||||
const char *valid_eap[] = { "leap", "md5", "tls", "peap", "ttls", "sim", "fast", "pwd", NULL };
|
||||
const char *valid_eap[] = { "leap", "md5", "tls", "peap", "ttls", "sim", "fast", "pwd", "external", NULL };
|
||||
GSList *iter;
|
||||
|
||||
if (error)
|
||||
|
@@ -448,33 +448,12 @@ deactivate_async (NMDevice *device,
|
||||
G_DBUS_CALL_FLAGS_NONE, -1, cancellable, disconnect_cb, ctx);
|
||||
}
|
||||
|
||||
static NMIwdNetworkSecurity
|
||||
get_connection_iwd_security (NMConnection *connection)
|
||||
{
|
||||
NMSettingWirelessSecurity *s_wireless_sec;
|
||||
const char *key_mgmt = NULL;
|
||||
|
||||
s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
|
||||
if (!s_wireless_sec)
|
||||
return NM_IWD_NETWORK_SECURITY_NONE;
|
||||
|
||||
key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);
|
||||
nm_assert (key_mgmt);
|
||||
|
||||
if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x"))
|
||||
return NM_IWD_NETWORK_SECURITY_WEP;
|
||||
|
||||
if (!strcmp (key_mgmt, "wpa-psk"))
|
||||
return NM_IWD_NETWORK_SECURITY_PSK;
|
||||
|
||||
nm_assert (!strcmp (key_mgmt, "wpa-eap"));
|
||||
return NM_IWD_NETWORK_SECURITY_8021X;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_connection_known_network (NMConnection *connection)
|
||||
{
|
||||
NMSettingWireless *s_wireless;
|
||||
NMIwdNetworkSecurity security;
|
||||
gboolean security_ok;
|
||||
GBytes *ssid;
|
||||
gs_free char *ssid_utf8 = NULL;
|
||||
|
||||
@@ -487,9 +466,13 @@ is_connection_known_network (NMConnection *connection)
|
||||
return FALSE;
|
||||
|
||||
ssid_utf8 = _nm_utils_ssid_to_utf8 (ssid);
|
||||
|
||||
security = nm_wifi_connection_get_iwd_security (connection, &security_ok);
|
||||
if (!security_ok)
|
||||
return FALSE;
|
||||
|
||||
return nm_iwd_manager_is_known_network (nm_iwd_manager_get (),
|
||||
ssid_utf8,
|
||||
get_connection_iwd_security (connection));
|
||||
ssid_utf8, security);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -543,7 +526,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError
|
||||
/* 8021x networks can only be used if they've been provisioned on the IWD side and
|
||||
* thus are Known Networks.
|
||||
*/
|
||||
if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (!is_connection_known_network (connection)) {
|
||||
nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||
"802.1x profile is not a known network");
|
||||
@@ -587,7 +570,7 @@ check_connection_available (NMDevice *device,
|
||||
/* 8021x networks can only be used if they've been provisioned on the IWD side and
|
||||
* thus are Known Networks.
|
||||
*/
|
||||
if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (!is_connection_known_network (connection)) {
|
||||
nm_utils_error_set_literal (error, NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||
"network is not known to iwd");
|
||||
@@ -731,7 +714,7 @@ complete_connection (NMDevice *device,
|
||||
/* 8021x networks can only be used if they've been provisioned on the IWD side and
|
||||
* thus are Known Networks.
|
||||
*/
|
||||
if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (!is_connection_known_network (connection)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
@@ -772,6 +755,32 @@ complete_connection (NMDevice *device,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_variant_boolean (GVariant *v, const char *property)
|
||||
{
|
||||
if (!v || !g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)) {
|
||||
nm_log_warn (LOGD_DEVICE | LOGD_WIFI,
|
||||
"Property %s not cached or not boolean type", property);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return g_variant_get_boolean (v);
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_variant_state (GVariant *v)
|
||||
{
|
||||
if (!v || !g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)) {
|
||||
nm_log_warn (LOGD_DEVICE | LOGD_WIFI,
|
||||
"State property not cached or not a string");
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
return g_variant_get_string (v, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
|
||||
{
|
||||
@@ -783,7 +792,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
|
||||
return FALSE;
|
||||
|
||||
value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Powered");
|
||||
return g_variant_get_boolean (value);
|
||||
return get_variant_boolean (value, "Powered");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -835,7 +844,7 @@ can_auto_connect (NMDevice *device,
|
||||
/* 8021x networks can only be used if they've been provisioned on the IWD side and
|
||||
* thus are Known Networks.
|
||||
*/
|
||||
if (get_connection_iwd_security (connection) == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (nm_wifi_connection_get_iwd_security (connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
if (!is_connection_known_network (connection))
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1305,9 +1314,6 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data)
|
||||
ssid_utf8);
|
||||
nm_device_activate_schedule_stage3_ip_config_start (device);
|
||||
|
||||
nm_iwd_manager_network_connected (nm_iwd_manager_get (), ssid_utf8,
|
||||
get_connection_iwd_security (connection));
|
||||
|
||||
return;
|
||||
|
||||
failed:
|
||||
@@ -1756,7 +1762,8 @@ state_changed (NMDeviceIwd *self, const char *new_state)
|
||||
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
|
||||
|
||||
return;
|
||||
}
|
||||
} else if (nm_streq (new_state, "unknown"))
|
||||
return;
|
||||
|
||||
_LOGE (LOGD_WIFI, "State %s unknown", new_state);
|
||||
}
|
||||
@@ -1802,13 +1809,13 @@ properties_changed (GDBusProxy *proxy, GVariant *changed_properties,
|
||||
g_variant_get (changed_properties, "a{sv}", &iter);
|
||||
while (g_variant_iter_next (iter, "{&sv}", &key, &value)) {
|
||||
if (!strcmp (key, "State"))
|
||||
state_changed (self, g_variant_get_string (value, NULL));
|
||||
state_changed (self, get_variant_state (value));
|
||||
|
||||
if (!strcmp (key, "Scanning"))
|
||||
scanning_changed (self, g_variant_get_boolean (value));
|
||||
scanning_changed (self, get_variant_boolean (value, "Scanning"));
|
||||
|
||||
if (!strcmp (key, "Powered"))
|
||||
powered_changed (self, g_variant_get_boolean (value));
|
||||
powered_changed (self, get_variant_boolean (value, "Powered"));
|
||||
|
||||
g_variant_unref (value);
|
||||
}
|
||||
@@ -1849,12 +1856,12 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object)
|
||||
priv->dbus_proxy = G_DBUS_PROXY (interface);
|
||||
|
||||
value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "Scanning");
|
||||
priv->scanning = g_variant_get_boolean (value);
|
||||
priv->scanning = get_variant_boolean (value, "Scanning");
|
||||
g_variant_unref (value);
|
||||
priv->scan_requested = FALSE;
|
||||
|
||||
value = g_dbus_proxy_get_cached_property (priv->dbus_proxy, "State");
|
||||
state_changed (self, g_variant_get_string (value, NULL));
|
||||
state_changed (self, get_variant_state (value));
|
||||
g_variant_unref (value);
|
||||
|
||||
g_signal_connect (priv->dbus_proxy, "g-properties-changed",
|
||||
|
@@ -29,13 +29,21 @@
|
||||
#include "nm-core-internal.h"
|
||||
#include "nm-manager.h"
|
||||
#include "nm-device-iwd.h"
|
||||
#include "nm-wifi-utils.h"
|
||||
#include "nm-utils/nm-random-utils.h"
|
||||
#include "settings/nm-settings.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
const char *name;
|
||||
NMIwdNetworkSecurity security;
|
||||
char buf[0];
|
||||
} KnownNetworkId;
|
||||
|
||||
typedef struct {
|
||||
GDBusProxy *known_network;
|
||||
NMSettingsConnection *mirror_connection;
|
||||
} KnownNetworkData;
|
||||
|
||||
typedef struct {
|
||||
@@ -45,7 +53,7 @@ typedef struct {
|
||||
GDBusObjectManager *object_manager;
|
||||
guint agent_id;
|
||||
char *agent_path;
|
||||
GSList *known_networks;
|
||||
GHashTable *known_networks;
|
||||
} NMIwdManagerPrivate;
|
||||
|
||||
struct _NMIwdManager {
|
||||
@@ -83,6 +91,36 @@ G_DEFINE_TYPE (NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void mirror_8021x_connection_take_and_delete (NMSettingsConnection *sett_conn);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const char *
|
||||
get_variant_string_or_null (GVariant *v)
|
||||
{
|
||||
if (!v)
|
||||
return NULL;
|
||||
|
||||
if ( !g_variant_is_of_type (v, G_VARIANT_TYPE_STRING)
|
||||
&& !g_variant_is_of_type (v, G_VARIANT_TYPE_OBJECT_PATH))
|
||||
return NULL;
|
||||
|
||||
return g_variant_get_string (v, NULL);
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_property_string_or_null (GDBusProxy *proxy, const char *property)
|
||||
{
|
||||
gs_unref_variant GVariant *value = NULL;
|
||||
|
||||
if (!proxy || !property)
|
||||
return NULL;
|
||||
|
||||
value = g_dbus_proxy_get_cached_property (proxy, property);
|
||||
|
||||
return get_variant_string_or_null (value);
|
||||
}
|
||||
|
||||
static void
|
||||
agent_dbus_method_cb (GDBusConnection *connection,
|
||||
const char *sender, const char *object_path,
|
||||
@@ -95,7 +133,6 @@ agent_dbus_method_cb (GDBusConnection *connection,
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
const char *network_path, *device_path, *ifname;
|
||||
gs_unref_object GDBusInterface *network = NULL, *device_obj = NULL;
|
||||
gs_unref_variant GVariant *value = NULL;
|
||||
int ifindex;
|
||||
NMDevice *device;
|
||||
gs_free char *name_owner = NULL;
|
||||
@@ -113,9 +150,8 @@ agent_dbus_method_cb (GDBusConnection *connection,
|
||||
network = g_dbus_object_manager_get_interface (priv->object_manager,
|
||||
network_path,
|
||||
NM_IWD_NETWORK_INTERFACE);
|
||||
value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (network), "Device");
|
||||
device_path = g_variant_get_string (value, NULL);
|
||||
|
||||
device_path = get_property_string_or_null (G_DBUS_PROXY (network), "Device");
|
||||
if (!device_path) {
|
||||
_LOGD ("agent-request: device not cached for network %s in IWD Agent request",
|
||||
network_path);
|
||||
@@ -125,10 +161,8 @@ agent_dbus_method_cb (GDBusConnection *connection,
|
||||
device_obj = g_dbus_object_manager_get_interface (priv->object_manager,
|
||||
device_path,
|
||||
NM_IWD_DEVICE_INTERFACE);
|
||||
g_variant_unref (value);
|
||||
value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (device_obj), "Name");
|
||||
ifname = g_variant_get_string (value, NULL);
|
||||
|
||||
ifname = get_property_string_or_null (G_DBUS_PROXY (device_obj), "Name");
|
||||
if (!ifname) {
|
||||
_LOGD ("agent-request: name not cached for device %s in IWD Agent request",
|
||||
device_path);
|
||||
@@ -251,38 +285,68 @@ register_agent (NMIwdManager *self)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static KnownNetworkId *
|
||||
known_network_id_new (const char *name, NMIwdNetworkSecurity security)
|
||||
{
|
||||
KnownNetworkId *id;
|
||||
gsize strsize = strlen (name) + 1;
|
||||
|
||||
id = g_malloc (sizeof (KnownNetworkId) + strsize);
|
||||
id->name = id->buf;
|
||||
id->security = security;
|
||||
memcpy (id->buf, name, strsize);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static guint
|
||||
known_network_id_hash (KnownNetworkId *id)
|
||||
{
|
||||
NMHashState h;
|
||||
|
||||
nm_hash_init (&h, 1947951703u);
|
||||
nm_hash_update_val (&h, id->security);
|
||||
nm_hash_update_str (&h, id->name);
|
||||
return nm_hash_complete (&h);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
known_network_id_equal (KnownNetworkId *a, KnownNetworkId *b)
|
||||
{
|
||||
return a->security == b->security
|
||||
&& nm_streq (a->name, b->name);
|
||||
}
|
||||
|
||||
static void
|
||||
set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface,
|
||||
known_network_data_free (KnownNetworkData *network)
|
||||
{
|
||||
if (!network)
|
||||
return;
|
||||
|
||||
g_object_unref (network->known_network);
|
||||
mirror_8021x_connection_take_and_delete (network->mirror_connection);
|
||||
g_slice_free (KnownNetworkData, network);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
set_device_dbus_object (NMIwdManager *self, GDBusProxy *proxy,
|
||||
GDBusObject *object)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
GDBusProxy *proxy;
|
||||
GVariant *value;
|
||||
const char *ifname;
|
||||
int ifindex;
|
||||
NMDevice *device;
|
||||
|
||||
if (!priv->running)
|
||||
return;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_PROXY (interface));
|
||||
|
||||
proxy = G_DBUS_PROXY (interface);
|
||||
|
||||
if (strcmp (g_dbus_proxy_get_interface_name (proxy),
|
||||
NM_IWD_DEVICE_INTERFACE))
|
||||
return;
|
||||
|
||||
value = g_dbus_proxy_get_cached_property (proxy, "Name");
|
||||
if (!value) {
|
||||
ifname = get_property_string_or_null (proxy, "Name");
|
||||
if (!ifname) {
|
||||
_LOGE ("Name not cached for Device at %s",
|
||||
g_dbus_proxy_get_object_path (proxy));
|
||||
return;
|
||||
}
|
||||
|
||||
ifname = g_variant_get_string (value, NULL);
|
||||
ifindex = if_nametoindex (ifname);
|
||||
g_variant_unref (value);
|
||||
|
||||
if (!ifindex) {
|
||||
_LOGE ("if_nametoindex failed for Name %s for Device at %s: %i",
|
||||
@@ -299,13 +363,183 @@ set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface,
|
||||
nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object);
|
||||
}
|
||||
|
||||
/* Create an in-memory NMConnection for a WPA2-Enterprise network that
|
||||
* has been preprovisioned with an IWD config file so that NM autoconnect
|
||||
* mechanism and the clients know this networks needs no additional EAP
|
||||
* configuration from the user. Only do this if no existing connection
|
||||
* SSID and security type match that network yet.
|
||||
*/
|
||||
static NMSettingsConnection *
|
||||
mirror_8021x_connection (NMIwdManager *self,
|
||||
const char *name)
|
||||
{
|
||||
NMSettings *settings = NM_SETTINGS_GET;
|
||||
NMSettingsConnection *const*iter;
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
NMSettingsConnection *settings_connection;
|
||||
char uuid[37];
|
||||
NMSetting *setting;
|
||||
GError *error = NULL;
|
||||
gs_unref_bytes GBytes *new_ssid = NULL;
|
||||
|
||||
for (iter = nm_settings_get_connections (settings, NULL); *iter; iter++) {
|
||||
NMSettingsConnection *sett_conn = *iter;
|
||||
NMConnection *conn = nm_settings_connection_get_connection (sett_conn);
|
||||
NMIwdNetworkSecurity security;
|
||||
gs_free char *ssid_name = NULL;
|
||||
NMSettingWireless *s_wifi;
|
||||
|
||||
security = nm_wifi_connection_get_iwd_security (conn, NULL);
|
||||
if (security != NM_IWD_NETWORK_SECURITY_8021X)
|
||||
continue;
|
||||
|
||||
s_wifi = nm_connection_get_setting_wireless (conn);
|
||||
if (!s_wifi)
|
||||
continue;
|
||||
|
||||
ssid_name = _nm_utils_ssid_to_utf8 (nm_setting_wireless_get_ssid (s_wifi));
|
||||
|
||||
/* We already have an NMSettingsConnection matching this
|
||||
* KnownNetwork, whether it's saved or an in-memory connection
|
||||
* potentially created by ourselves. Nothing to do here.
|
||||
*/
|
||||
if (nm_streq (ssid_name, name))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connection = nm_simple_connection_new ();
|
||||
|
||||
setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_CONNECTION,
|
||||
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
|
||||
NM_SETTING_CONNECTION_ID, name,
|
||||
NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid),
|
||||
NM_SETTING_CONNECTION_READ_ONLY, TRUE,
|
||||
NULL));
|
||||
nm_connection_add_setting (connection, setting);
|
||||
|
||||
new_ssid = g_bytes_new (name, strlen (name));
|
||||
setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_WIRELESS,
|
||||
NM_SETTING_WIRELESS_SSID, new_ssid,
|
||||
NM_SETTING_WIRELESS_MODE, NM_SETTING_WIRELESS_MODE_INFRA,
|
||||
NULL));
|
||||
nm_connection_add_setting (connection, setting);
|
||||
|
||||
setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_WIRELESS_SECURITY,
|
||||
NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
|
||||
NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
|
||||
NULL));
|
||||
nm_connection_add_setting (connection, setting);
|
||||
|
||||
setting = NM_SETTING (g_object_new (NM_TYPE_SETTING_802_1X, NULL));
|
||||
nm_setting_802_1x_add_eap_method (NM_SETTING_802_1X (setting), "external");
|
||||
nm_connection_add_setting (connection, setting);
|
||||
|
||||
if (!nm_connection_normalize (connection, NULL, NULL, NULL))
|
||||
return NULL;
|
||||
|
||||
settings_connection = nm_settings_add_connection (settings, connection,
|
||||
FALSE, &error);
|
||||
if (!settings_connection) {
|
||||
_LOGW ("failed to add a mirror NMConnection for IWD's Known Network '%s': %s",
|
||||
name, error->message);
|
||||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nm_settings_connection_set_flags (settings_connection,
|
||||
NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED |
|
||||
NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED,
|
||||
TRUE);
|
||||
return settings_connection;
|
||||
}
|
||||
|
||||
static void
|
||||
mirror_8021x_connection_take_and_delete (NMSettingsConnection *sett_conn)
|
||||
{
|
||||
NMSettingsConnectionIntFlags flags;
|
||||
|
||||
if (!sett_conn)
|
||||
return;
|
||||
|
||||
flags = nm_settings_connection_get_flags (sett_conn);
|
||||
|
||||
/* If connection has not been saved since we created it
|
||||
* in interface_added it too can be removed now. */
|
||||
if (NM_FLAGS_HAS (flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED))
|
||||
nm_settings_connection_delete (sett_conn, NULL);
|
||||
|
||||
g_object_unref (sett_conn);
|
||||
}
|
||||
|
||||
static void
|
||||
interface_added (GDBusObjectManager *object_manager, GDBusObject *object,
|
||||
GDBusInterface *interface, gpointer user_data)
|
||||
{
|
||||
NMIwdManager *self = user_data;
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
GDBusProxy *proxy;
|
||||
const char *iface_name;
|
||||
|
||||
set_device_dbus_object (self, interface, object);
|
||||
if (!priv->running)
|
||||
return;
|
||||
|
||||
g_return_if_fail (G_IS_DBUS_PROXY (interface));
|
||||
|
||||
proxy = G_DBUS_PROXY (interface);
|
||||
iface_name = g_dbus_proxy_get_interface_name (proxy);
|
||||
|
||||
if (nm_streq (iface_name, NM_IWD_DEVICE_INTERFACE)) {
|
||||
set_device_dbus_object (self, proxy, object);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nm_streq (iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) {
|
||||
KnownNetworkId *id;
|
||||
KnownNetworkData *data;
|
||||
NMIwdNetworkSecurity security;
|
||||
const char *type_str, *name;
|
||||
NMSettingsConnection *sett_conn = NULL;
|
||||
|
||||
type_str = get_property_string_or_null (proxy, "Type");
|
||||
name = get_property_string_or_null (proxy, "Name");
|
||||
if (!type_str || !name)
|
||||
return;
|
||||
|
||||
if (nm_streq (type_str, "open"))
|
||||
security = NM_IWD_NETWORK_SECURITY_NONE;
|
||||
else if (nm_streq (type_str, "psk"))
|
||||
security = NM_IWD_NETWORK_SECURITY_PSK;
|
||||
else if (nm_streq (type_str, "8021x"))
|
||||
security = NM_IWD_NETWORK_SECURITY_8021X;
|
||||
else
|
||||
return;
|
||||
|
||||
id = known_network_id_new (name, security);
|
||||
|
||||
data = g_hash_table_lookup (priv->known_networks, id);
|
||||
if (data)
|
||||
g_free (id);
|
||||
else {
|
||||
data = g_slice_new0 (KnownNetworkData);
|
||||
data->known_network = g_object_ref (proxy);
|
||||
g_hash_table_insert (priv->known_networks, id, data);
|
||||
}
|
||||
|
||||
if (security == NM_IWD_NETWORK_SECURITY_8021X) {
|
||||
sett_conn = mirror_8021x_connection (self, name);
|
||||
|
||||
if ( sett_conn
|
||||
&& sett_conn != data->mirror_connection) {
|
||||
NMSettingsConnection *sett_conn_old = data->mirror_connection;
|
||||
|
||||
data->mirror_connection = nm_g_object_ref (sett_conn);
|
||||
mirror_8021x_connection_take_and_delete (sett_conn_old);
|
||||
}
|
||||
} else
|
||||
mirror_8021x_connection_take_and_delete (g_steal_pointer (&data->mirror_connection));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -313,15 +547,41 @@ interface_removed (GDBusObjectManager *object_manager, GDBusObject *object,
|
||||
GDBusInterface *interface, gpointer user_data)
|
||||
{
|
||||
NMIwdManager *self = user_data;
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
GDBusProxy *proxy;
|
||||
const char *iface_name;
|
||||
|
||||
/*
|
||||
* TODO: we may need to save the GDBusInterface or GDBusObject
|
||||
* pointer in the hash table because we may be no longer able to
|
||||
* access the Name property or map the name to ifindex with
|
||||
* if_nametoindex at this point.
|
||||
*/
|
||||
g_return_if_fail (G_IS_DBUS_PROXY (interface));
|
||||
|
||||
set_device_dbus_object (self, interface, NULL);
|
||||
proxy = G_DBUS_PROXY (interface);
|
||||
iface_name = g_dbus_proxy_get_interface_name (proxy);
|
||||
|
||||
if (nm_streq (iface_name, NM_IWD_DEVICE_INTERFACE)) {
|
||||
set_device_dbus_object (self, proxy, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nm_streq (iface_name, NM_IWD_KNOWN_NETWORK_INTERFACE)) {
|
||||
KnownNetworkId id;
|
||||
const char *type_str;
|
||||
|
||||
type_str = get_property_string_or_null (proxy, "Type");
|
||||
id.name = get_property_string_or_null (proxy, "Name");
|
||||
if (!type_str || !id.name)
|
||||
return;
|
||||
|
||||
if (nm_streq (type_str, "open"))
|
||||
id.security = NM_IWD_NETWORK_SECURITY_NONE;
|
||||
else if (nm_streq (type_str, "psk"))
|
||||
id.security = NM_IWD_NETWORK_SECURITY_PSK;
|
||||
else if (nm_streq (type_str, "8021x"))
|
||||
id.security = NM_IWD_NETWORK_SECURITY_8021X;
|
||||
else
|
||||
return;
|
||||
|
||||
g_hash_table_remove (priv->known_networks, &id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -341,108 +601,16 @@ object_added (NMIwdManager *self, GDBusObject *object)
|
||||
GList *interfaces, *iter;
|
||||
|
||||
interfaces = g_dbus_object_get_interfaces (object);
|
||||
|
||||
for (iter = interfaces; iter; iter = iter->next) {
|
||||
GDBusInterface *interface = G_DBUS_INTERFACE (iter->data);
|
||||
|
||||
set_device_dbus_object (self, interface, object);
|
||||
interface_added (NULL, object, interface, self);
|
||||
}
|
||||
|
||||
g_list_free_full (interfaces, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
known_network_free (KnownNetworkData *network)
|
||||
{
|
||||
g_free (network->name);
|
||||
g_free (network);
|
||||
}
|
||||
|
||||
static void
|
||||
list_known_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data)
|
||||
{
|
||||
NMIwdManager *self = user_data;
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *variant = NULL;
|
||||
GVariantIter *networks, *props;
|
||||
|
||||
variant = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (source), res,
|
||||
G_VARIANT_TYPE ("(aa{sv})"),
|
||||
&error);
|
||||
if (!variant) {
|
||||
_LOGE ("ListKnownNetworks() failed: %s", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free);
|
||||
priv->known_networks = NULL;
|
||||
|
||||
g_variant_get (variant, "(aa{sv})", &networks);
|
||||
|
||||
while (g_variant_iter_next (networks, "a{sv}", &props)) {
|
||||
const char *key;
|
||||
const char *name = NULL;
|
||||
const char *type = NULL;
|
||||
GVariant *val;
|
||||
KnownNetworkData *network_data;
|
||||
|
||||
while (g_variant_iter_next (props, "{&sv}", &key, &val)) {
|
||||
if (!strcmp (key, "Name"))
|
||||
name = g_variant_get_string (val, NULL);
|
||||
|
||||
if (!strcmp (key, "Type"))
|
||||
type = g_variant_get_string (val, NULL);
|
||||
|
||||
g_variant_unref (val);
|
||||
}
|
||||
|
||||
if (!name || !type)
|
||||
goto next;
|
||||
|
||||
network_data = g_new (KnownNetworkData, 1);
|
||||
network_data->name = g_strdup (name);
|
||||
if (!strcmp (type, "open"))
|
||||
network_data->security = NM_IWD_NETWORK_SECURITY_NONE;
|
||||
else if (!strcmp (type, "psk"))
|
||||
network_data->security = NM_IWD_NETWORK_SECURITY_PSK;
|
||||
else if (!strcmp (type, "8021x"))
|
||||
network_data->security = NM_IWD_NETWORK_SECURITY_8021X;
|
||||
|
||||
priv->known_networks = g_slist_append (priv->known_networks,
|
||||
network_data);
|
||||
|
||||
next:
|
||||
g_variant_iter_free (props);
|
||||
}
|
||||
|
||||
g_variant_iter_free (networks);
|
||||
|
||||
/* For completness we may want to call nm_device_emit_recheck_auto_activate
|
||||
* and nm_device_recheck_available_connections for all affected devices
|
||||
* now but the ListKnownNetworks call should have been really fast,
|
||||
* faster than any scan on any newly created devices could have happened.
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
update_known_networks (NMIwdManager *self)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
GDBusInterface *known_networks_if;
|
||||
|
||||
known_networks_if = g_dbus_object_manager_get_interface (priv->object_manager,
|
||||
"/",
|
||||
NM_IWD_KNOWN_NETWORKS_INTERFACE);
|
||||
|
||||
g_dbus_proxy_call (G_DBUS_PROXY (known_networks_if),
|
||||
"ListKnownNetworks",
|
||||
g_variant_new ("()"),
|
||||
G_DBUS_CALL_FLAGS_NONE, -1,
|
||||
priv->cancellable, list_known_networks_cb, self);
|
||||
|
||||
g_object_unref (known_networks_if);
|
||||
}
|
||||
|
||||
static void prepare_object_manager (NMIwdManager *self);
|
||||
|
||||
static void
|
||||
@@ -492,28 +660,14 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data)
|
||||
objects = g_dbus_object_manager_get_objects (priv->object_manager);
|
||||
for (iter = objects; iter; iter = iter->next) {
|
||||
GDBusObject *object = G_DBUS_OBJECT (iter->data);
|
||||
GDBusInterface *interface;
|
||||
GDBusProxy *proxy;
|
||||
GVariant *value;
|
||||
gs_unref_object GDBusInterface *interface = NULL;
|
||||
const char *obj_ifname;
|
||||
|
||||
interface = g_dbus_object_get_interface (object,
|
||||
NM_IWD_DEVICE_INTERFACE);
|
||||
if (!interface)
|
||||
continue;
|
||||
obj_ifname = get_property_string_or_null ((GDBusProxy *) interface, "Name");
|
||||
|
||||
proxy = G_DBUS_PROXY (interface);
|
||||
value = g_dbus_proxy_get_cached_property (proxy, "Name");
|
||||
if (!value) {
|
||||
g_object_unref (interface);
|
||||
continue;
|
||||
}
|
||||
|
||||
obj_ifname = g_variant_get_string (value, NULL);
|
||||
g_variant_unref (value);
|
||||
g_object_unref (interface);
|
||||
|
||||
if (strcmp (nm_device_get_iface (device), obj_ifname))
|
||||
if (!obj_ifname || strcmp (nm_device_get_iface (device), obj_ifname))
|
||||
continue;
|
||||
|
||||
nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device), object);
|
||||
@@ -535,7 +689,7 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data)
|
||||
object_manager = g_dbus_object_manager_client_new_for_bus_finish (result, &error);
|
||||
if (object_manager == NULL) {
|
||||
_LOGE ("failed to acquire IWD Object Manager: Wi-Fi will not be available (%s)",
|
||||
NM_G_ERROR_MSG (error));
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
@@ -549,11 +703,13 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data)
|
||||
|
||||
connection = g_dbus_object_manager_client_get_connection (G_DBUS_OBJECT_MANAGER_CLIENT (object_manager));
|
||||
|
||||
priv->agent_id = iwd_agent_export (connection, self,
|
||||
&priv->agent_path, &error);
|
||||
priv->agent_id = iwd_agent_export (connection,
|
||||
self,
|
||||
&priv->agent_path,
|
||||
&error);
|
||||
if (!priv->agent_id) {
|
||||
_LOGE ("failed to export the IWD Agent: PSK/8021x WiFi networks will not work: %s",
|
||||
NM_G_ERROR_MSG (error));
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
@@ -567,6 +723,8 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data)
|
||||
g_signal_connect (priv->object_manager, "interface-removed",
|
||||
G_CALLBACK (interface_removed), self);
|
||||
|
||||
g_hash_table_remove_all (priv->known_networks);
|
||||
|
||||
objects = g_dbus_object_manager_get_objects (object_manager);
|
||||
for (iter = objects; iter; iter = iter->next)
|
||||
object_added (self, G_DBUS_OBJECT (iter->data));
|
||||
@@ -575,8 +733,6 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data)
|
||||
|
||||
if (priv->agent_id)
|
||||
register_agent (self);
|
||||
|
||||
update_known_networks (self);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,32 +754,9 @@ nm_iwd_manager_is_known_network (NMIwdManager *self, const char *name,
|
||||
NMIwdNetworkSecurity security)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
const GSList *iter;
|
||||
KnownNetworkId kn_id = { name, security };
|
||||
|
||||
for (iter = priv->known_networks; iter; iter = g_slist_next (iter)) {
|
||||
const KnownNetworkData *network = iter->data;
|
||||
|
||||
if (!strcmp (network->name, name) && network->security == security)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nm_iwd_manager_network_connected (NMIwdManager *self, const char *name,
|
||||
NMIwdNetworkSecurity security)
|
||||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
KnownNetworkData *network_data;
|
||||
|
||||
if (nm_iwd_manager_is_known_network (self, name, security))
|
||||
return;
|
||||
|
||||
network_data = g_new (KnownNetworkData, 1);
|
||||
network_data->name = g_strdup (name);
|
||||
network_data->security = security;
|
||||
priv->known_networks = g_slist_append (priv->known_networks, network_data);
|
||||
return g_hash_table_contains (priv->known_networks, &kn_id);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -642,6 +775,11 @@ nm_iwd_manager_init (NMIwdManager *self)
|
||||
|
||||
priv->cancellable = g_cancellable_new ();
|
||||
|
||||
priv->known_networks = g_hash_table_new_full ((GHashFunc) known_network_id_hash,
|
||||
(GEqualFunc) known_network_id_equal,
|
||||
g_free,
|
||||
(GDestroyNotify) known_network_data_free);
|
||||
|
||||
prepare_object_manager (self);
|
||||
}
|
||||
|
||||
@@ -673,8 +811,7 @@ dispose (GObject *object)
|
||||
|
||||
nm_clear_g_cancellable (&priv->cancellable);
|
||||
|
||||
g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free);
|
||||
priv->known_networks = NULL;
|
||||
nm_clear_pointer (&priv->known_networks, g_hash_table_destroy);
|
||||
|
||||
if (priv->manager) {
|
||||
g_signal_handlers_disconnect_by_data (priv->manager, self);
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#define __NETWORKMANAGER_IWD_MANAGER_H__
|
||||
|
||||
#include "devices/nm-device.h"
|
||||
#include "nm-wifi-utils.h"
|
||||
|
||||
#define NM_IWD_BUS_TYPE G_BUS_TYPE_SYSTEM
|
||||
#define NM_IWD_SERVICE "net.connman.iwd"
|
||||
@@ -33,16 +34,9 @@
|
||||
#define NM_IWD_AGENT_INTERFACE "net.connman.iwd.Agent"
|
||||
#define NM_IWD_WSC_INTERFACE \
|
||||
"net.connman.iwd.WiFiSimpleConfiguration"
|
||||
#define NM_IWD_KNOWN_NETWORKS_INTERFACE "net.connman.iwd.KnownNetworks"
|
||||
#define NM_IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork"
|
||||
#define NM_IWD_SIGNAL_AGENT_INTERFACE "net.connman.iwd.SignalLevelAgent"
|
||||
|
||||
typedef enum {
|
||||
NM_IWD_NETWORK_SECURITY_NONE,
|
||||
NM_IWD_NETWORK_SECURITY_WEP,
|
||||
NM_IWD_NETWORK_SECURITY_PSK,
|
||||
NM_IWD_NETWORK_SECURITY_8021X,
|
||||
} NMIwdNetworkSecurity;
|
||||
|
||||
#define NM_TYPE_IWD_MANAGER (nm_iwd_manager_get_type ())
|
||||
#define NM_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IWD_MANAGER, NMIwdManager))
|
||||
#define NM_IWD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IWD_MANAGER, NMIwdManagerClass))
|
||||
@@ -59,7 +53,5 @@ NMIwdManager *nm_iwd_manager_get (void);
|
||||
|
||||
gboolean nm_iwd_manager_is_known_network (NMIwdManager *self, const char *name,
|
||||
NMIwdNetworkSecurity security);
|
||||
void nm_iwd_manager_network_connected (NMIwdManager *self, const char *name,
|
||||
NMIwdNetworkSecurity security);
|
||||
|
||||
#endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */
|
||||
|
@@ -815,3 +815,36 @@ nm_wifi_utils_is_manf_default_ssid (GBytes *ssid)
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NMIwdNetworkSecurity
|
||||
nm_wifi_connection_get_iwd_security (NMConnection *connection,
|
||||
gboolean *mapped)
|
||||
{
|
||||
NMSettingWirelessSecurity *s_wireless_sec;
|
||||
const char *key_mgmt = NULL;
|
||||
|
||||
if (!nm_connection_get_setting_wireless (connection))
|
||||
goto error;
|
||||
|
||||
NM_SET_OUT (mapped, TRUE);
|
||||
|
||||
s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
|
||||
if (!s_wireless_sec)
|
||||
return NM_IWD_NETWORK_SECURITY_NONE;
|
||||
|
||||
key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec);
|
||||
nm_assert (key_mgmt);
|
||||
|
||||
if (NM_IN_STRSET (key_mgmt, "none", "ieee8021x"))
|
||||
return NM_IWD_NETWORK_SECURITY_WEP;
|
||||
|
||||
if (nm_streq (key_mgmt, "wpa-psk"))
|
||||
return NM_IWD_NETWORK_SECURITY_PSK;
|
||||
|
||||
if (nm_streq (key_mgmt, "wpa-eap"))
|
||||
return NM_IWD_NETWORK_SECURITY_8021X;
|
||||
|
||||
error:
|
||||
NM_SET_OUT (mapped, FALSE);
|
||||
return NM_IWD_NETWORK_SECURITY_NONE;
|
||||
}
|
||||
|
@@ -27,6 +27,13 @@
|
||||
#include "nm-setting-wireless-security.h"
|
||||
#include "nm-setting-8021x.h"
|
||||
|
||||
typedef enum {
|
||||
NM_IWD_NETWORK_SECURITY_NONE,
|
||||
NM_IWD_NETWORK_SECURITY_WEP,
|
||||
NM_IWD_NETWORK_SECURITY_PSK,
|
||||
NM_IWD_NETWORK_SECURITY_8021X,
|
||||
} NMIwdNetworkSecurity;
|
||||
|
||||
gboolean nm_wifi_utils_complete_connection (GBytes *ssid,
|
||||
const char *bssid,
|
||||
NM80211Mode mode,
|
||||
@@ -41,4 +48,7 @@ guint32 nm_wifi_utils_level_to_quality (int val);
|
||||
|
||||
gboolean nm_wifi_utils_is_manf_default_ssid (GBytes *ssid);
|
||||
|
||||
NMIwdNetworkSecurity nm_wifi_connection_get_iwd_security (NMConnection *connection,
|
||||
gboolean *mapped);
|
||||
|
||||
#endif /* __NM_WIFI_UTILS_H__ */
|
||||
|
@@ -1001,6 +1001,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
|
||||
guint32 frag, hdrs;
|
||||
gs_free char *frag_str = NULL;
|
||||
NMSetting8021xAuthFlags phase1_auth_flags;
|
||||
nm_auto_free_gstring GString *eap_str = NULL;
|
||||
|
||||
g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE);
|
||||
g_return_val_if_fail (setting != NULL, FALSE);
|
||||
@@ -1037,20 +1038,38 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self,
|
||||
priv->ap_scan = 0;
|
||||
}
|
||||
|
||||
if (!ADD_STRING_LIST_VAL (self, setting, 802_1x, eap_method, eap_methods, "eap", ' ', TRUE, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
/* Check EAP method for special handling: PEAP + GTC, FAST */
|
||||
/* Build the "eap" option string while we check for EAP methods needing
|
||||
* special handling: PEAP + GTC, FAST, external */
|
||||
eap_str = g_string_new (NULL);
|
||||
num_eap = nm_setting_802_1x_get_num_eap_methods (setting);
|
||||
for (i = 0; i < num_eap; i++) {
|
||||
const char *method = nm_setting_802_1x_get_eap_method (setting, i);
|
||||
|
||||
if (method && (strcasecmp (method, "fast") == 0)) {
|
||||
if (nm_streq (method, "fast")) {
|
||||
fast = TRUE;
|
||||
priv->fast_required = TRUE;
|
||||
}
|
||||
|
||||
if (nm_streq (method, "external")) {
|
||||
if (num_eap == 1) {
|
||||
g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG,
|
||||
"Connection settings managed externally to NM, connection"
|
||||
" cannot be used with wpa_supplicant");
|
||||
return FALSE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (eap_str->len)
|
||||
g_string_append_c (eap_str, ' ');
|
||||
g_string_append (eap_str, method);
|
||||
}
|
||||
|
||||
g_string_ascii_up (eap_str);
|
||||
if ( eap_str->len
|
||||
&& !nm_supplicant_config_add_option (self, "eap", eap_str->str, -1, NULL, error))
|
||||
return FALSE;
|
||||
|
||||
/* Adjust the fragment size according to MTU, but do not set it higher than 1280-14
|
||||
* for better compatibility */
|
||||
hdrs = 14; /* EAPOL + EAP-TLS */
|
||||
|
Reference in New Issue
Block a user