diff options
Diffstat (limited to 'src/devices')
119 files changed, 0 insertions, 71747 deletions
diff --git a/src/devices/adsl/meson.build b/src/devices/adsl/meson.build deleted file mode 100644 index 79834d7f..00000000 --- a/src/devices/adsl/meson.build +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -sources = files( - 'nm-atm-manager.c', - 'nm-device-adsl.c', -) - -libnm_device_plugin_adsl = shared_module( - 'nm-device-plugin-adsl', - sources: sources, - dependencies: daemon_nm_default_dep, - c_args: daemon_c_flags, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_plugindir, -) - -core_plugins += libnm_device_plugin_adsl - -test( - 'check-local-devices-adsl', - check_exports, - args: [libnm_device_plugin_adsl.full_path(), linker_script_devices], -) diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c deleted file mode 100644 index 8e9f555d..00000000 --- a/src/devices/adsl/nm-atm-manager.c +++ /dev/null @@ -1,271 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2013 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <gmodule.h> -#include <libudev.h> - -#include "nm-setting-adsl.h" -#include "nm-device-adsl.h" -#include "devices/nm-device-factory.h" -#include "platform/nm-platform.h" -#include "nm-udev-aux/nm-udev-utils.h" - -/*****************************************************************************/ - -#define NM_TYPE_ATM_MANAGER (nm_atm_manager_get_type()) -#define NM_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ATM_MANAGER, NMAtmManager)) -#define NM_ATM_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_ATM_MANAGER, NMAtmManagerClass)) -#define NM_IS_ATM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_ATM_MANAGER)) -#define NM_IS_ATM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_ATM_MANAGER)) -#define NM_ATM_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_ATM_MANAGER, NMAtmManagerClass)) - -typedef struct { - NMUdevClient *udev_client; - GSList * devices; -} NMAtmManagerPrivate; - -typedef struct { - NMDeviceFactory parent; - NMAtmManagerPrivate _priv; -} NMAtmManager; - -typedef struct { - NMDeviceFactoryClass parent; -} NMAtmManagerClass; - -static GType nm_atm_manager_get_type(void); - -G_DEFINE_TYPE(NMAtmManager, nm_atm_manager, NM_TYPE_DEVICE_FACTORY); - -#define NM_ATM_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMAtmManager, NM_IS_ATM_MANAGER) - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES( - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_ADSL_SETTING_NAME)); - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - return (NMDeviceFactory *) g_object_new(NM_TYPE_ATM_MANAGER, NULL); -} - -/*****************************************************************************/ - -static gboolean -dev_get_attrs(struct udev_device *udev_device, const char **out_path, char **out_driver) -{ - struct udev_device *parent = NULL; - const char * driver, *path; - - g_return_val_if_fail(udev_device != NULL, FALSE); - g_return_val_if_fail(out_path != NULL, FALSE); - g_return_val_if_fail(out_driver != NULL, FALSE); - - path = udev_device_get_syspath(udev_device); - if (!path) { - nm_log_warn(LOGD_PLATFORM, "couldn't determine device path; ignoring..."); - return FALSE; - } - - driver = udev_device_get_driver(udev_device); - if (!driver) { - /* Try the parent */ - parent = udev_device_get_parent(udev_device); - if (parent) - driver = udev_device_get_driver(parent); - } - - *out_path = path; - *out_driver = g_strdup(driver); - - return TRUE; -} - -static void -device_destroyed(gpointer user_data, GObject *dead) -{ - NMAtmManager * self = NM_ATM_MANAGER(user_data); - NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE(self); - - priv->devices = g_slist_remove(priv->devices, dead); -} - -static void -adsl_add(NMAtmManager *self, struct udev_device *udev_device) -{ - NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE(self); - const char * ifname, *sysfs_path = NULL; - char * driver = NULL; - gs_free char * atm_index_path = NULL; - int atm_index; - NMDevice * device; - - g_return_if_fail(udev_device != NULL); - - ifname = udev_device_get_sysname(udev_device); - if (!ifname) { - nm_log_warn(LOGD_PLATFORM, "failed to get device's interface name"); - return; - } - - nm_log_dbg(LOGD_PLATFORM, "(%s): found ATM device", ifname); - - atm_index_path = - g_strdup_printf("/sys/class/atm/%s/atmindex", NM_ASSERT_VALID_PATH_COMPONENT(ifname)); - atm_index = (int) nm_platform_sysctl_get_int_checked(NM_PLATFORM_GET, - NMP_SYSCTL_PATHID_ABSOLUTE(atm_index_path), - 10, - 0, - G_MAXINT, - -1); - if (atm_index < 0) { - nm_log_warn(LOGD_PLATFORM, "(%s): failed to get ATM index", ifname); - return; - } - - if (!dev_get_attrs(udev_device, &sysfs_path, &driver)) { - nm_log_warn(LOGD_PLATFORM, "(%s): failed to get ATM attributes", ifname); - return; - } - - g_assert(sysfs_path); - - device = nm_device_adsl_new(sysfs_path, ifname, driver, atm_index); - g_assert(device); - - priv->devices = g_slist_prepend(priv->devices, device); - g_object_weak_ref(G_OBJECT(device), device_destroyed, self); - - g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); - g_object_unref(device); - - g_free(driver); -} - -static void -adsl_remove(NMAtmManager *self, struct udev_device *udev_device) -{ - NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE(self); - const char * iface = udev_device_get_sysname(udev_device); - GSList * iter; - - nm_log_dbg(LOGD_PLATFORM, "(%s): removing ATM device", iface); - - for (iter = priv->devices; iter; iter = iter->next) { - NMDevice *device = iter->data; - - /* Match 'iface' not 'ip_iface' to the ATM device instead of the - * NAS bridge interface or PPPoE interface. - */ - if (g_strcmp0(nm_device_get_iface(device), iface) != 0) - continue; - - g_object_weak_unref(G_OBJECT(iter->data), device_destroyed, self); - priv->devices = g_slist_remove(priv->devices, device); - g_signal_emit_by_name(device, NM_DEVICE_REMOVED); - break; - } -} - -static void -start(NMDeviceFactory *factory) -{ - NMAtmManager * self = NM_ATM_MANAGER(factory); - NMAtmManagerPrivate * priv = NM_ATM_MANAGER_GET_PRIVATE(self); - struct udev_enumerate * enumerate; - struct udev_list_entry *devices; - - enumerate = nm_udev_client_enumerate_new(priv->udev_client); - udev_enumerate_add_match_is_initialized(enumerate); - udev_enumerate_scan_devices(enumerate); - devices = udev_enumerate_get_list_entry(enumerate); - for (; devices; devices = udev_list_entry_get_next(devices)) { - struct udev_device *udevice; - - udevice = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), - udev_list_entry_get_name(devices)); - if (udevice) { - adsl_add(self, udevice); - udev_device_unref(udevice); - } - } - udev_enumerate_unref(enumerate); -} - -static void -handle_uevent(NMUdevClient *client, struct udev_device *device, gpointer user_data) -{ - NMAtmManager *self = NM_ATM_MANAGER(user_data); - const char * subsys; - const char * ifindex; - guint64 seqnum; - const char * action; - - action = udev_device_get_action(device); - - g_return_if_fail(action != NULL); - - /* A bit paranoid */ - subsys = udev_device_get_subsystem(device); - g_return_if_fail(!g_strcmp0(subsys, "atm")); - - ifindex = udev_device_get_property_value(device, "IFINDEX"); - seqnum = udev_device_get_seqnum(device); - nm_log_dbg(LOGD_PLATFORM, - "UDEV event: action '%s' subsys '%s' device '%s' (%s); seqnum=%" G_GUINT64_FORMAT, - action, - subsys, - udev_device_get_sysname(device), - ifindex ?: "unknown", - seqnum); - - if (!strcmp(action, "add")) - adsl_add(self, device); - else if (!strcmp(action, "remove")) - adsl_remove(self, device); -} - -/*****************************************************************************/ - -static void -nm_atm_manager_init(NMAtmManager *self) -{ - NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE(self); - - priv->udev_client = nm_udev_client_new((const char *[]){"atm", NULL}, handle_uevent, self); -} - -static void -dispose(GObject *object) -{ - NMAtmManager * self = NM_ATM_MANAGER(object); - NMAtmManagerPrivate *priv = NM_ATM_MANAGER_GET_PRIVATE(self); - GSList * iter; - - for (iter = priv->devices; iter; iter = iter->next) - g_object_weak_unref(G_OBJECT(iter->data), device_destroyed, self); - nm_clear_pointer(&priv->devices, g_slist_free); - - priv->udev_client = nm_udev_client_unref(priv->udev_client); - - G_OBJECT_CLASS(nm_atm_manager_parent_class)->dispose(object); -} - -static void -nm_atm_manager_class_init(NMAtmManagerClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - object_class->dispose = dispose; - - factory_class->get_supported_types = get_supported_types; - factory_class->start = start; -} diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c deleted file mode 100644 index 32615623..00000000 --- a/src/devices/adsl/nm-device-adsl.c +++ /dev/null @@ -1,720 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Pantelis Koukousoulas <pktoss@gmail.com> - */ - -#include "nm-default.h" - -#include "nm-device-adsl.h" - -#include <sys/socket.h> -#include <linux/atmdev.h> -#include <linux/atmbr2684.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <unistd.h> -#include <stdlib.h> - -#include "nm-ip4-config.h" -#include "devices/nm-device-private.h" -#include "platform/nm-platform.h" -#include "ppp/nm-ppp-manager-call.h" -#include "ppp/nm-ppp-status.h" -#include "nm-setting-adsl.h" -#include "nm-utils.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceAdsl); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_ATM_INDEX, ); - -typedef struct { - guint carrier_poll_id; - int atm_index; - - /* PPP */ - NMPPPManager *ppp_manager; - - /* RFC 2684 bridging (PPPoE over ATM) */ - int brfd; - int nas_ifindex; - char *nas_ifname; - guint nas_update_id; - guint nas_update_count; -} NMDeviceAdslPrivate; - -struct _NMDeviceAdsl { - NMDevice parent; - NMDeviceAdslPrivate _priv; -}; - -struct _NMDeviceAdslClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceAdsl, nm_device_adsl, NM_TYPE_DEVICE) - -#define NM_DEVICE_ADSL_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceAdsl, NM_IS_DEVICE_ADSL, NMDevice) - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return (NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER - | NM_DEVICE_CAP_IS_NON_KERNEL); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingAdsl *s_adsl; - const char * protocol; - - if (!NM_DEVICE_CLASS(nm_device_adsl_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_adsl = nm_connection_get_setting_adsl(connection); - - protocol = nm_setting_adsl_get_protocol(s_adsl); - if (nm_streq0(protocol, NM_SETTING_ADSL_PROTOCOL_IPOATM)) { - /* FIXME: we don't yet support IPoATM */ - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "IPoATM protocol is not yet supported"); - return FALSE; - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingAdsl *s_adsl; - - /* - * We can't telepathically figure out the username, so if - * it wasn't given, we can't complete the connection. - */ - s_adsl = nm_connection_get_setting_adsl(connection); - if (s_adsl && !nm_setting_verify(NM_SETTING(s_adsl), NULL, error)) - return FALSE; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_ADSL_SETTING_NAME, - existing_connections, - NULL, - _("ADSL connection"), - NULL, - NULL, - FALSE); /* No IPv6 yet by default */ - return TRUE; -} - -/*****************************************************************************/ - -static gboolean -br2684_assign_vcc(NMDeviceAdsl *self, NMSettingAdsl *s_adsl) -{ - NMDeviceAdslPrivate * priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - struct sockaddr_atmpvc addr; - struct atm_backend_br2684 be; - struct atm_qos qos; - int errsv, err, bufsize = 8192; - const char * encapsulation; - gboolean is_llc; - - g_return_val_if_fail(priv->brfd == -1, FALSE); - g_return_val_if_fail(priv->nas_ifname != NULL, FALSE); - - priv->brfd = socket(PF_ATMPVC, SOCK_DGRAM | SOCK_CLOEXEC, ATM_AAL5); - if (priv->brfd < 0) { - errsv = errno; - _LOGE(LOGD_ADSL, "failed to open ATM control socket (%d)", errsv); - priv->brfd = -1; - return FALSE; - } - - err = setsockopt(priv->brfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); - if (err != 0) { - errsv = errno; - _LOGE(LOGD_ADSL, "failed to set SNDBUF option (%d)", errsv); - goto error; - } - - /* QoS */ - memset(&qos, 0, sizeof(qos)); - qos.aal = ATM_AAL5; - qos.txtp.traffic_class = ATM_UBR; - qos.txtp.max_sdu = 1524; - qos.txtp.pcr = ATM_MAX_PCR; - qos.rxtp = qos.txtp; - - err = setsockopt(priv->brfd, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)); - if (err != 0) { - errsv = errno; - _LOGE(LOGD_ADSL, "failed to set QoS (%d)", errsv); - goto error; - } - - encapsulation = nm_setting_adsl_get_encapsulation(s_adsl); - - /* VPI/VCI */ - memset(&addr, 0, sizeof(addr)); - addr.sap_family = AF_ATMPVC; - addr.sap_addr.itf = priv->atm_index; - addr.sap_addr.vpi = (guint16) nm_setting_adsl_get_vpi(s_adsl); - addr.sap_addr.vci = (int) nm_setting_adsl_get_vci(s_adsl); - - _LOGD(LOGD_ADSL, - "assigning address %d.%d.%d encapsulation %s", - priv->atm_index, - addr.sap_addr.vpi, - addr.sap_addr.vci, - encapsulation ?: "(none)"); - - err = connect(priv->brfd, (struct sockaddr *) &addr, sizeof(addr)); - if (err != 0) { - errsv = errno; - _LOGE(LOGD_ADSL, "failed to set VPI/VCI (%d)", errsv); - goto error; - } - - /* And last attach the VCC to the interface */ - is_llc = (g_strcmp0(encapsulation, "llc") == 0); - - memset(&be, 0, sizeof(be)); - be.backend_num = ATM_BACKEND_BR2684; - be.ifspec.method = BR2684_FIND_BYIFNAME; - nm_utils_ifname_cpy(be.ifspec.spec.ifname, priv->nas_ifname); - be.fcs_in = BR2684_FCSIN_NO; - be.fcs_out = BR2684_FCSOUT_NO; - be.encaps = is_llc ? BR2684_ENCAPS_LLC : BR2684_ENCAPS_VC; - err = ioctl(priv->brfd, ATM_SETBACKEND, &be); - if (err != 0) { - errsv = errno; - _LOGE(LOGD_ADSL, "failed to attach VCC (%d)", errsv); - goto error; - } - - return TRUE; - -error: - nm_close(priv->brfd); - priv->brfd = -1; - return FALSE; -} - -static void -link_changed_cb(NMPlatform * platform, - int obj_type_i, - int ifindex, - NMPlatformLink *info, - int change_type_i, - NMDeviceAdsl * self) -{ - const NMPlatformSignalChangeType change_type = change_type_i; - - if (change_type == NM_PLATFORM_SIGNAL_REMOVED) { - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - - /* This only gets called for PPPoE connections and "nas" interfaces */ - - if (priv->nas_ifindex > 0 && ifindex == priv->nas_ifindex) { - /* NAS device went away for some reason; kill the connection */ - _LOGD(LOGD_ADSL, "br2684 interface disappeared"); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BR2684_FAILED); - } - } -} - -static gboolean -pppoe_vcc_config(NMDeviceAdsl *self) -{ - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMSettingAdsl * s_adsl; - - s_adsl = nm_device_get_applied_setting(device, NM_TYPE_SETTING_ADSL); - - g_return_val_if_fail(s_adsl, FALSE); - - /* Set up the VCC */ - if (!br2684_assign_vcc(self, s_adsl)) - return FALSE; - - /* Watch for the 'nas' interface going away */ - g_signal_connect(nm_device_get_platform(device), - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK(link_changed_cb), - self); - - _LOGD(LOGD_ADSL, "ATM setup successful"); - - /* otherwise we're good for stage3 */ - nm_platform_link_set_up(nm_device_get_platform(device), priv->nas_ifindex, NULL); - - return TRUE; -} - -static gboolean -nas_update_cb(gpointer user_data) -{ - NMDeviceAdsl * self = NM_DEVICE_ADSL(user_data); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - - nm_assert(priv->nas_ifname); - - priv->nas_update_count++; - - nm_assert(priv->nas_ifindex <= 0); - priv->nas_ifindex = - nm_platform_link_get_ifindex(nm_device_get_platform(device), priv->nas_ifname); - if (priv->nas_ifindex <= 0) { - if (priv->nas_update_count <= 10) { - /* Keep waiting for it to appear */ - return G_SOURCE_CONTINUE; - } - priv->nas_update_id = 0; - _LOGW(LOGD_ADSL, - "failed to find br2684 interface %s ifindex after timeout", - priv->nas_ifname); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BR2684_FAILED); - return G_SOURCE_REMOVE; - } - - priv->nas_update_id = 0; - _LOGD(LOGD_ADSL, "using br2684 iface '%s' index %d", priv->nas_ifname, priv->nas_ifindex); - - if (!pppoe_vcc_config(self)) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BR2684_FAILED); - return G_SOURCE_REMOVE; - } - - nm_device_activate_schedule_stage2_device_config(device, TRUE); - return G_SOURCE_REMOVE; -} - -static gboolean -br2684_create_iface(NMDeviceAdsl *self) -{ - NMDeviceAdslPrivate * priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - struct atm_newif_br2684 ni; - nm_auto_close int fd = -1; - int err, errsv; - guint num = 0; - - if (nm_clear_g_source(&priv->nas_update_id)) - nm_assert_not_reached(); - - fd = socket(PF_ATMPVC, SOCK_DGRAM | SOCK_CLOEXEC, ATM_AAL5); - if (fd < 0) { - errsv = errno; - _LOGE(LOGD_ADSL, "failed to open ATM control socket (%d)", errsv); - return FALSE; - } - - memset(&ni, 0, sizeof(ni)); - ni.backend_num = ATM_BACKEND_BR2684; - ni.media = BR2684_MEDIA_ETHERNET; - ni.mtu = 1500; - - /* Loop attempting to create an interface that doesn't exist yet. The - * kernel can create one for us automatically, but due to API issues it - * cannot return that name to us. Since we want to know the name right - * away, just brute-force it. - */ - while (TRUE) { - memset(&ni.ifname, 0, sizeof(ni.ifname)); - g_snprintf(ni.ifname, sizeof(ni.ifname), "nas%u", num++); - - err = ioctl(fd, ATM_NEWBACKENDIF, &ni); - if (err != 0) { - errsv = errno; - if (errsv == EEXIST) - continue; - - _LOGW(LOGD_ADSL, "failed to create br2684 interface (%d)", errsv); - return FALSE; - } - - nm_utils_strdup_reset(&priv->nas_ifname, ni.ifname); - _LOGD(LOGD_ADSL, "waiting for br2684 iface '%s' to appear", priv->nas_ifname); - priv->nas_update_count = 0; - priv->nas_update_id = g_timeout_add(100, nas_update_cb, self); - return TRUE; - } -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceAdsl * self = NM_DEVICE_ADSL(device); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - NMSettingAdsl * s_adsl; - const char * protocol; - - s_adsl = nm_device_get_applied_setting(device, NM_TYPE_SETTING_ADSL); - - g_return_val_if_fail(s_adsl, NM_ACT_STAGE_RETURN_FAILURE); - - protocol = nm_setting_adsl_get_protocol(s_adsl); - _LOGD(LOGD_ADSL, "using ADSL protocol '%s'", protocol); - - if (nm_streq0(protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA)) { - /* PPPoA doesn't need anything special */ - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - if (nm_streq0(protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE)) { - /* PPPoE needs RFC2684 bridging before we can do PPP over it */ - if (priv->nas_ifindex <= 0) { - if (priv->nas_update_id == 0) { - if (!br2684_create_iface(self)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_BR2684_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - } - return NM_ACT_STAGE_RETURN_POSTPONE; - } - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - _LOGW(LOGD_ADSL, "unhandled ADSL protocol '%s'", protocol); - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static void -ppp_state_changed(NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - switch (status) { - case NM_PPP_STATUS_DISCONNECT: - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_PPP_DISCONNECT); - break; - case NM_PPP_STATUS_DEAD: - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); - break; - default: - break; - } -} - -static void -ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - if (!nm_device_set_ip_ifindex(device, ifindex)) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } -} - -static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_activate_ip4_state_in_conf(device)) - nm_device_activate_schedule_ip_config_result(device, AF_INET, NM_IP_CONFIG_CAST(config)); -} - -static NMActStageReturn -act_stage3_ip4_config_start(NMDevice * device, - NMIP4Config ** out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceAdsl * self = NM_DEVICE_ADSL(device); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - NMSettingAdsl * s_adsl; - NMActRequest * req; - GError * err = NULL; - const char * ppp_iface; - - req = nm_device_get_act_request(device); - - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - s_adsl = nm_device_get_applied_setting(device, NM_TYPE_SETTING_ADSL); - - g_return_val_if_fail(s_adsl, NM_ACT_STAGE_RETURN_FAILURE); - - /* PPPoE uses the NAS interface, not the ATM interface */ - if (nm_streq0(nm_setting_adsl_get_protocol(s_adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE)) { - nm_assert(priv->nas_ifname); - ppp_iface = priv->nas_ifname; - - _LOGD(LOGD_ADSL, "starting PPPoE on br2684 interface %s", priv->nas_ifname); - } else { - ppp_iface = nm_device_get_iface(device); - _LOGD(LOGD_ADSL, "starting PPPoA"); - } - - priv->ppp_manager = nm_ppp_manager_create(ppp_iface, &err); - - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); - } - - if (!priv->ppp_manager - || !nm_ppp_manager_start(priv->ppp_manager, - req, - nm_setting_adsl_get_username(s_adsl), - 30, - 0, - &err)) { - _LOGW(LOGD_ADSL, "PPP failed to start: %s", err->message); - g_error_free(err); - - g_clear_object(&priv->ppp_manager); - - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, - G_CALLBACK(ppp_state_changed), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK(ppp_ifindex_set), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), - self); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - if (addr_family == AF_INET) - return act_stage3_ip4_config_start(device, (NMIP4Config **) out_config, out_failure_reason); - - return NM_DEVICE_CLASS(nm_device_adsl_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static void -adsl_cleanup(NMDeviceAdsl *self) -{ - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - - if (priv->ppp_manager) { - g_signal_handlers_disconnect_by_func(priv->ppp_manager, - G_CALLBACK(ppp_state_changed), - self); - g_signal_handlers_disconnect_by_func(priv->ppp_manager, G_CALLBACK(ppp_ip4_config), self); - nm_ppp_manager_stop(priv->ppp_manager, NULL, NULL, NULL); - g_clear_object(&priv->ppp_manager); - } - - g_signal_handlers_disconnect_by_func(nm_device_get_platform(NM_DEVICE(self)), - G_CALLBACK(link_changed_cb), - self); - - nm_close(priv->brfd); - priv->brfd = -1; - - nm_clear_g_source(&priv->nas_update_id); - - /* FIXME: kernel has no way of explicitly deleting the 'nasX' interface yet, - * so it gets leaked. It does get destroyed when it's no longer in use, - * but we have no control over that. - */ - priv->nas_ifindex = 0; - nm_clear_g_free(&priv->nas_ifname); -} - -static void -deactivate(NMDevice *device) -{ - adsl_cleanup(NM_DEVICE_ADSL(device)); -} - -/*****************************************************************************/ - -static gboolean -carrier_update_cb(gpointer user_data) -{ - NMDeviceAdsl *self = NM_DEVICE_ADSL(user_data); - int carrier; - char * path; - - path = g_strdup_printf("/sys/class/atm/%s/carrier", - NM_ASSERT_VALID_PATH_COMPONENT(nm_device_get_iface(NM_DEVICE(self)))); - carrier = (int) nm_platform_sysctl_get_int_checked(nm_device_get_platform(NM_DEVICE(self)), - NMP_SYSCTL_PATHID_ABSOLUTE(path), - 10, - 0, - 1, - -1); - g_free(path); - - if (carrier != -1) - nm_device_set_carrier(NM_DEVICE(self), carrier); - return TRUE; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - case PROP_ATM_INDEX: - g_value_set_int(value, NM_DEVICE_ADSL_GET_PRIVATE(object)->atm_index); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - case PROP_ATM_INDEX: - /* construct-only */ - NM_DEVICE_ADSL_GET_PRIVATE(object)->atm_index = g_value_get_int(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_adsl_init(NMDeviceAdsl *self) -{} - -static void -constructed(GObject *object) -{ - NMDeviceAdsl * self = NM_DEVICE_ADSL(object); - NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE(self); - - G_OBJECT_CLASS(nm_device_adsl_parent_class)->constructed(object); - - priv->carrier_poll_id = g_timeout_add_seconds(5, carrier_update_cb, self); - - _LOGD(LOGD_ADSL, "ATM device index %d", priv->atm_index); - - g_return_if_fail(priv->atm_index >= 0); -} - -NMDevice * -nm_device_adsl_new(const char *udi, const char *iface, const char *driver, int atm_index) -{ - g_return_val_if_fail(udi != NULL, NULL); - g_return_val_if_fail(atm_index >= 0, NULL); - - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_ADSL, - NM_DEVICE_UDI, - udi, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_DRIVER, - driver, - NM_DEVICE_ADSL_ATM_INDEX, - atm_index, - NM_DEVICE_TYPE_DESC, - "ADSL", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_ADSL, - NULL); -} - -static void -dispose(GObject *object) -{ - adsl_cleanup(NM_DEVICE_ADSL(object)); - - nm_clear_g_source(&NM_DEVICE_ADSL_GET_PRIVATE(object)->carrier_poll_id); - - G_OBJECT_CLASS(nm_device_adsl_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_adsl = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_ADSL, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", - "b", - NM_DEVICE_CARRIER), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_adsl_class_init(NMDeviceAdslClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_adsl); - - device_class->connection_type_check_compatible = NM_SETTING_ADSL_SETTING_NAME; - - device_class->get_generic_capabilities = get_generic_capabilities; - - device_class->check_connection_compatible = check_connection_compatible; - device_class->complete_connection = complete_connection; - - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->deactivate = deactivate; - - obj_properties[PROP_ATM_INDEX] = - g_param_spec_int(NM_DEVICE_ADSL_ATM_INDEX, - "", - "", - -1, - G_MAXINT, - -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/adsl/nm-device-adsl.h b/src/devices/adsl/nm-device-adsl.h deleted file mode 100644 index 95740830..00000000 --- a/src/devices/adsl/nm-device-adsl.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Author: Pantelis Koukousoulas <pktoss@gmail.com> - * Copyright (C) 2009 - 2011 Red Hat Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_ADSL_H__ -#define __NETWORKMANAGER_DEVICE_ADSL_H__ - -#include "devices/nm-device.h" - -#define NM_TYPE_DEVICE_ADSL (nm_device_adsl_get_type()) -#define NM_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdsl)) -#define NM_DEVICE_ADSL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass)) -#define NM_IS_DEVICE_ADSL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_ADSL)) -#define NM_IS_DEVICE_ADSL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_ADSL)) -#define NM_DEVICE_ADSL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_ADSL, NMDeviceAdslClass)) - -#define NM_DEVICE_ADSL_ATM_INDEX "atm-index" - -typedef struct _NMDeviceAdsl NMDeviceAdsl; -typedef struct _NMDeviceAdslClass NMDeviceAdslClass; - -GType nm_device_adsl_get_type(void); - -NMDevice *nm_device_adsl_new(const char *udi, const char *iface, const char *driver, int atm_index); - -#endif /* NM_DEVICE_ADSL_H */ diff --git a/src/devices/bluetooth/meson.build b/src/devices/bluetooth/meson.build deleted file mode 100644 index 638a01a2..00000000 --- a/src/devices/bluetooth/meson.build +++ /dev/null @@ -1,60 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -sources = files( - 'nm-bluez-manager.c', - 'nm-bt-error.c', - 'nm-device-bt.c', -) - -deps = [ - daemon_nm_default_dep, - libnm_wwan_dep, -] - -if enable_bluez5_dun - sources += files('nm-bluez5-dun.c') - - deps += bluez5_dep -endif - -libnm_device_plugin_bluetooth_static = static_library( - 'nm-device-plugin-bluetooth-static', - sources: sources, - dependencies: deps, - c_args: daemon_c_flags, -) - -libnm_device_plugin_bluetooth_static_dep = declare_dependency( - link_whole: libnm_device_plugin_bluetooth_static, -) - -deps += libnm_device_plugin_bluetooth_static_dep - -libnm_device_plugin_bluetooth = shared_module( - 'nm-device-plugin-bluetooth', - dependencies: deps, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_plugindir, - install_rpath: nm_plugindir, -) - -core_plugins += libnm_device_plugin_bluetooth - -test( - 'check-local-devices-bluetooth', - check_exports, - args: [libnm_device_plugin_bluetooth.full_path(), linker_script_devices], -) - -if enable_tests - test_unit = 'nm-bt-test' - - executable( - test_unit, - 'tests/' + test_unit + '.c', - dependencies: [ libnetwork_manager_test_dep, deps ], - c_args: test_c_flags, - ) -endif diff --git a/src/devices/bluetooth/nm-bluez-common.h b/src/devices/bluetooth/nm-bluez-common.h deleted file mode 100644 index e70ec3f7..00000000 --- a/src/devices/bluetooth/nm-bluez-common.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_BLUEZ_COMMON_H__ -#define __NETWORKMANAGER_BLUEZ_COMMON_H__ - -#define BLUETOOTH_CONNECT_DUN "dun" -#define BLUETOOTH_CONNECT_NAP "nap" - -#define NM_BLUEZ_SERVICE "org.bluez" - -#define NM_BLUEZ_MANAGER_PATH "/" - -#define NM_BLUEZ5_ADAPTER_INTERFACE "org.bluez.Adapter1" -#define NM_BLUEZ5_DEVICE_INTERFACE "org.bluez.Device1" -#define NM_BLUEZ5_NETWORK_INTERFACE "org.bluez.Network1" -#define NM_BLUEZ5_NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer1" - -#define NM_BLUEZ_MANAGER_BDADDR_ADDED "bdaddr-added" -#define NM_BLUEZ_MANAGER_NETWORK_SERVER_ADDED "network-server-added" - -#endif /* NM_BLUEZ_COMMON_H */ diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c deleted file mode 100644 index df0bcbbb..00000000 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ /dev/null @@ -1,2895 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-bluez-manager.h" - -#include <signal.h> -#include <stdlib.h> -#include <gmodule.h> - -#include "nm-glib-aux/nm-dbus-aux.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-dbus-manager.h" -#include "devices/nm-device-factory.h" -#include "devices/nm-device-bridge.h" -#include "nm-setting-bluetooth.h" -#include "settings/nm-settings.h" -#include "nm-bluez-common.h" -#include "nm-device-bt.h" -#include "nm-manager.h" -#include "nm-bluez5-dun.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.h" -#include "nm-std-aux/nm-dbus-compat.h" - -/*****************************************************************************/ - -#if WITH_BLUEZ5_DUN - #define _NM_BT_CAPABILITY_SUPPORTED_DUN NM_BT_CAPABILITY_DUN -#else - #define _NM_BT_CAPABILITY_SUPPORTED_DUN NM_BT_CAPABILITY_NONE -#endif -#define _NM_BT_CAPABILITY_SUPPORTED (NM_BT_CAPABILITY_NAP | _NM_BT_CAPABILITY_SUPPORTED_DUN) - -typedef struct { - const char * bdaddr; - CList lst_head; - NMBluetoothCapabilities bt_type : 8; - char bdaddr_data[]; -} ConnDataHead; - -typedef struct { - NMSettingsConnection *sett_conn; - ConnDataHead * cdata_hd; - CList lst; -} ConnDataElem; - -typedef struct { - GCancellable * ext_cancellable; - GCancellable * int_cancellable; - NMBtVTableRegisterCallback callback; - gpointer callback_user_data; - gulong ext_cancelled_id; -} NetworkServerRegisterReqData; - -typedef struct { - GCancellable * ext_cancellable; - GCancellable * int_cancellable; - NMBluezManagerConnectCb callback; - gpointer callback_user_data; - char * device_name; - gulong ext_cancelled_id; - guint timeout_id; - guint timeout_wait_connect_id; -} DeviceConnectReqData; - -typedef struct { - const char *object_path; - - NMBluezManager *self; - - /* Fields name with "d_" prefix are purely cached values from BlueZ's - * ObjectManager D-Bus interface. There is no logic whatsoever about - * them. - */ - - CList process_change_lst; - - struct { - char *address; - } d_adapter; - - struct { - char *address; - char *name; - char *adapter; - } d_device; - - struct { - char *interface; - } d_network; - - struct { - CList lst; - char * adapter_address; - NMDevice * device_br; - NetworkServerRegisterReqData *r_req_data; - } x_network_server; - - struct { - NMSettingsConnection *panu_connection; - NMDeviceBt * device_bt; - DeviceConnectReqData *c_req_data; - NMBluez5DunContext * connect_dun_context; - gulong device_bt_signal_id; - } x_device; - - /* indicate whether the D-Bus object has the particular D-Bus interface. */ - bool d_has_adapter_iface : 1; - bool d_has_device_iface : 1; - bool d_has_network_iface : 1; - bool d_has_network_server_iface : 1; - - /* cached D-Bus properties for Device1 ("d_device*"). */ - NMBluetoothCapabilities d_device_capabilities : 6; - bool d_device_connected : 1; - bool d_device_paired : 1; - - /* cached D-Bus properties for Network1 ("d_network*"). */ - bool d_network_connected : 1; - - /* cached D-Bus properties for Adapter1 ("d_adapter*"). */ - bool d_adapter_powered : 1; - - /* properties related to device ("x_device*"). */ - NMBluetoothCapabilities x_device_connect_bt_type : 6; - bool x_device_is_usable : 1; - bool x_device_is_connected : 1; - - bool x_device_panu_connection_allow_create : 1; - - /* flag to remember last time when we checked wether the object - * was a suitable adapter that is usable to a device. */ - bool was_usable_adapter_for_device_before : 1; - - char _object_path_intern[]; -} BzDBusObj; - -typedef struct { - NMManager * manager; - NMSettings *settings; - - GDBusConnection *dbus_connection; - - NMBtVTableNetworkServer vtable_network_server; - - GCancellable *name_owner_get_cancellable; - GCancellable *get_managed_objects_cancellable; - - GHashTable *bzobjs; - - char *name_owner; - - GHashTable *conn_data_heads; - GHashTable *conn_data_elems; - - CList network_server_lst_head; - - CList process_change_lst_head; - - guint name_owner_changed_id; - - guint managed_objects_changed_id; - - guint properties_changed_id; - - guint process_change_idle_id; - - bool settings_registered : 1; -} NMBluezManagerPrivate; - -struct _NMBluezManager { - NMDeviceFactory parent; - NMBluezManagerPrivate _priv; -}; - -struct _NMBluezManagerClass { - NMDeviceFactoryClass parent; -}; - -G_DEFINE_TYPE(NMBluezManager, nm_bluez_manager, NM_TYPE_DEVICE_FACTORY); - -#define NM_BLUEZ_MANAGER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMBluezManager, NM_IS_BLUEZ_MANAGER) - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES(NM_DEVICE_FACTORY_DECLARE_LINK_TYPES( - NM_LINK_TYPE_BNEP) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_BLUETOOTH_SETTING_NAME)) - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - return (NMDeviceFactory *) g_object_new(NM_TYPE_BLUEZ_MANAGER, NULL); -} - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_BT -#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "bluez", __VA_ARGS__) - -/*****************************************************************************/ - -static NMBluetoothCapabilities -convert_uuids_to_capabilities(const char *const *strv) -{ - NMBluetoothCapabilities capabilities = NM_BT_CAPABILITY_NONE; - - if (strv) { - for (; strv[0]; strv++) { - gs_free char *s_part1 = NULL; - const char * str = strv[0]; - const char * s; - - s = strchr(str, '-'); - if (!s) - continue; - - s_part1 = g_strndup(str, s - str); - switch (_nm_utils_ascii_str_to_int64(s_part1, 16, 0, G_MAXINT, -1)) { - case 0x1103: - capabilities |= NM_BT_CAPABILITY_DUN; - break; - case 0x1116: - capabilities |= NM_BT_CAPABILITY_NAP; - break; - default: - break; - } - } - } - - return capabilities; -} - -/*****************************************************************************/ - -static void _cleanup_for_name_owner(NMBluezManager *self); -static void _connect_disconnect(NMBluezManager *self, BzDBusObj *bzobj, const char *reason); -static gboolean _bzobjs_network_server_is_usable(const BzDBusObj *bzobj, gboolean require_powered); -static gboolean _bzobjs_is_dead(const BzDBusObj *bzobj); -static gboolean _bzobjs_device_is_usable(const BzDBusObj *bzobj, - BzDBusObj ** out_adapter_bzobj, - gboolean * out_create_panu_connection); -static gboolean _bzobjs_adapter_is_usable_for_device(const BzDBusObj *bzobj); -static ConnDataHead * -_conn_track_find_head(NMBluezManager *self, NMBluetoothCapabilities bt_type, const char *bdaddr); -static void _process_change_idle_schedule(NMBluezManager *self, BzDBusObj *bzobj); -static void -_network_server_unregister_bridge(NMBluezManager *self, BzDBusObj *bzobj, const char *reason); -static gboolean _connect_timeout_wait_connected_cb(gpointer user_data); - -/*****************************************************************************/ - -static void -_dbus_call_complete_cb_nop(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - /* we don't do anything at all. The only reason to register this - * callback is so that GDBusConnection keeps the cancellable alive - * long enough until the call completes. - * - * Note that this cancellable in turn is registered via - * nm_shutdown_wait_obj_register_*(), to block shutdown until - * we are done. */ -} - -/*****************************************************************************/ - -static void -_network_server_register_req_data_complete(NetworkServerRegisterReqData *r_req_data, GError *error) -{ - nm_clear_g_signal_handler(r_req_data->ext_cancellable, &r_req_data->ext_cancelled_id); - - nm_clear_g_cancellable(&r_req_data->int_cancellable); - - if (r_req_data->callback) { - gs_free_error GError *error_cancelled = NULL; - - if (g_cancellable_set_error_if_cancelled(r_req_data->ext_cancellable, &error_cancelled)) - error = error_cancelled; - - r_req_data->callback(error, r_req_data->callback_user_data); - } - - g_object_unref(r_req_data->ext_cancellable); - nm_g_slice_free(r_req_data); -} - -static void -_device_connect_req_data_complete(DeviceConnectReqData *c_req_data, - NMBluezManager * self, - const char * device_name, - GError * error) -{ - nm_assert((!!device_name) != (!!error)); - - nm_clear_g_signal_handler(c_req_data->ext_cancellable, &c_req_data->ext_cancelled_id); - - nm_clear_g_cancellable(&c_req_data->int_cancellable); - nm_clear_g_source(&c_req_data->timeout_id); - nm_clear_g_source(&c_req_data->timeout_wait_connect_id); - - if (c_req_data->callback) { - gs_free_error GError *error_cancelled = NULL; - - if (g_cancellable_set_error_if_cancelled(c_req_data->ext_cancellable, &error_cancelled)) { - error = error_cancelled; - device_name = NULL; - } - - c_req_data->callback(self, TRUE, device_name, error, c_req_data->callback_user_data); - } - - g_object_unref(c_req_data->ext_cancellable); - nm_clear_g_free(&c_req_data->device_name); - nm_g_slice_free(c_req_data); -} - -/*****************************************************************************/ - -static BzDBusObj * -_bz_dbus_obj_new(NMBluezManager *self, const char *object_path) -{ - BzDBusObj *bzobj; - gsize l; - - nm_assert(NM_IS_BLUEZ_MANAGER(self)); - - l = strlen(object_path) + 1; - - bzobj = g_malloc(sizeof(BzDBusObj) + l); - *bzobj = (BzDBusObj){ - .object_path = bzobj->_object_path_intern, - .self = self, - .x_network_server.lst = C_LIST_INIT(bzobj->x_network_server.lst), - .process_change_lst = C_LIST_INIT(bzobj->process_change_lst), - .x_device_panu_connection_allow_create = TRUE, - }; - memcpy(bzobj->_object_path_intern, object_path, l); - - return bzobj; -} - -static void -_bz_dbus_obj_free(BzDBusObj *bzobj) -{ - nm_assert(bzobj); - nm_assert(NM_IS_BLUEZ_MANAGER(bzobj->self)); - nm_assert(!bzobj->x_network_server.device_br); - nm_assert(!bzobj->x_network_server.r_req_data); - nm_assert(!bzobj->x_device.c_req_data); - - c_list_unlink_stale(&bzobj->process_change_lst); - c_list_unlink_stale(&bzobj->x_network_server.lst); - g_free(bzobj->x_network_server.adapter_address); - g_free(bzobj->d_adapter.address); - g_free(bzobj->d_network.interface); - g_free(bzobj->d_device.address); - g_free(bzobj->d_device.name); - g_free(bzobj->d_device.adapter); - g_free(bzobj); -} - -/*****************************************************************************/ - -static const char * -_bzobj_to_string(const BzDBusObj *bzobj, char *buf, gsize len) -{ - char * buf0 = buf; - const char *prefix = ""; - gboolean device_is_usable; - gboolean create_panu_connection = FALSE; - gboolean network_server_is_usable; - char sbuf_cap[100]; - - if (len > 0) - buf[0] = '\0'; - - if (bzobj->d_has_adapter_iface) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append_str(&buf, &len, "Adapter1 {"); - if (bzobj->d_adapter.address) { - nm_utils_strbuf_append(&buf, &len, " d.address: \"%s\"", bzobj->d_adapter.address); - if (bzobj->d_adapter_powered) - nm_utils_strbuf_append_str(&buf, &len, ","); - } - if (bzobj->d_adapter_powered) - nm_utils_strbuf_append(&buf, &len, " d.powered: 1"); - nm_utils_strbuf_append_str(&buf, &len, " }"); - } - - if (bzobj->d_has_device_iface) { - const char *prefix1 = ""; - - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append_str(&buf, &len, "Device1 {"); - if (bzobj->d_device.address) { - nm_utils_strbuf_append(&buf, - &len, - "%s d.address: \"%s\"", - prefix1, - bzobj->d_device.address); - prefix1 = ","; - } - if (bzobj->d_device.name) { - nm_utils_strbuf_append(&buf, &len, "%s d.name: \"%s\"", prefix1, bzobj->d_device.name); - prefix1 = ","; - } - if (bzobj->d_device.adapter) { - nm_utils_strbuf_append(&buf, - &len, - "%s d.adapter: \"%s\"", - prefix1, - bzobj->d_device.adapter); - prefix1 = ","; - } - if (bzobj->d_device_capabilities != NM_BT_CAPABILITY_NONE) { - nm_utils_strbuf_append(&buf, - &len, - "%s d.capabilities: \"%s\"", - prefix1, - nm_bluetooth_capability_to_string(bzobj->d_device_capabilities, - sbuf_cap, - sizeof(sbuf_cap))); - prefix1 = ","; - } - if (bzobj->d_device_connected) { - nm_utils_strbuf_append(&buf, &len, "%s d.connected: 1", prefix1); - prefix1 = ","; - } - if (bzobj->d_device_paired) { - nm_utils_strbuf_append(&buf, &len, "%s d.paired: 1", prefix1); - prefix1 = ","; - } - nm_utils_strbuf_append_str(&buf, &len, " }"); - } - - network_server_is_usable = _bzobjs_network_server_is_usable(bzobj, TRUE); - - if (bzobj->d_has_network_server_iface - || network_server_is_usable != (!c_list_is_empty(&bzobj->x_network_server.lst)) - || !c_list_is_empty(&bzobj->x_network_server.lst) - || !nm_streq0(bzobj->d_has_adapter_iface ? bzobj->d_adapter.address : NULL, - bzobj->x_network_server.adapter_address) - || bzobj->x_network_server.device_br || bzobj->x_network_server.r_req_data) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - - nm_utils_strbuf_append(&buf, &len, "NetworkServer1 { "); - - if (!bzobj->d_has_network_server_iface) - nm_utils_strbuf_append(&buf, &len, " has-d-iface: 0, "); - - if (network_server_is_usable != (!c_list_is_empty(&bzobj->x_network_server.lst))) - nm_utils_strbuf_append(&buf, - &len, - "usable: %d, used: %d", - !!network_server_is_usable, - !network_server_is_usable); - else if (network_server_is_usable) - nm_utils_strbuf_append(&buf, &len, "used: 1"); - else - nm_utils_strbuf_append(&buf, &len, "usable: 0"); - - if (!nm_streq0(bzobj->d_has_adapter_iface ? bzobj->d_adapter.address : NULL, - bzobj->x_network_server.adapter_address)) { - if (bzobj->x_network_server.adapter_address) - nm_utils_strbuf_append(&buf, - &len, - ", adapter-address: \"%s\"", - bzobj->x_network_server.adapter_address); - else - nm_utils_strbuf_append(&buf, &len, ", adapter-address: <NULL>"); - } - - if (bzobj->x_network_server.device_br) - nm_utils_strbuf_append(&buf, &len, ", bridge-device: 1"); - - if (bzobj->x_network_server.r_req_data) - nm_utils_strbuf_append(&buf, &len, ", register-in-progress: 1"); - - nm_utils_strbuf_append_str(&buf, &len, " }"); - } - - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, &create_panu_connection); - - if (bzobj->d_has_network_iface || bzobj->d_network.interface || bzobj->d_network_connected - || create_panu_connection || bzobj->x_device.panu_connection - || device_is_usable != bzobj->x_device_is_usable || bzobj->x_device.device_bt - || bzobj->x_device_connect_bt_type != NM_BT_CAPABILITY_NONE - || bzobj->x_device.connect_dun_context || bzobj->x_device.c_req_data - || bzobj->x_device_is_connected != bzobj->d_network_connected) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append_str(&buf, &len, "Network1 {"); - if (bzobj->d_network.interface) - nm_utils_strbuf_append(&buf, - &len, - " d.interface: \"%s\", ", - bzobj->d_network.interface); - if (bzobj->d_network_connected) - nm_utils_strbuf_append(&buf, &len, " d.connected: %d, ", !!bzobj->d_network_connected); - if (!bzobj->d_has_network_iface) - nm_utils_strbuf_append(&buf, &len, " has-d-iface: 0, "); - if (device_is_usable != bzobj->x_device_is_usable) - nm_utils_strbuf_append(&buf, - &len, - " usable: %d, used: %d", - !!device_is_usable, - !device_is_usable); - else if (device_is_usable) - nm_utils_strbuf_append(&buf, &len, " used: 1"); - else - nm_utils_strbuf_append(&buf, &len, " usable: 0"); - - if (create_panu_connection) - nm_utils_strbuf_append(&buf, &len, ", create-panu-connection: 1"); - - if (bzobj->x_device.panu_connection) - nm_utils_strbuf_append(&buf, &len, ", has-panu-connection: 1"); - - if (bzobj->x_device.device_bt) - nm_utils_strbuf_append(&buf, &len, ", has-device: 1"); - - if (bzobj->x_device_connect_bt_type != NM_BT_CAPABILITY_NONE - || bzobj->x_device.connect_dun_context) { - nm_utils_strbuf_append( - &buf, - &len, - ", connect: %s%s", - nm_bluetooth_capability_to_string(bzobj->x_device_connect_bt_type, - sbuf_cap, - sizeof(sbuf_cap)), - bzobj->x_device.connect_dun_context ? ",with-dun-context" : ""); - } - - if (bzobj->x_device.c_req_data) - nm_utils_strbuf_append(&buf, &len, ", connecting: 1"); - - if (bzobj->x_device_is_connected != bzobj->d_network_connected) - nm_utils_strbuf_append(&buf, &len, ", connected: %d", !!bzobj->x_device_is_connected); - - nm_utils_strbuf_append_str(&buf, &len, " }"); - } - - if (_bzobjs_is_dead(bzobj)) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append_str(&buf, &len, "dead: 1"); - } - - if (!c_list_is_empty(&bzobj->process_change_lst)) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append(&buf, &len, "change-pending-on-idle: 1"); - } - - if (_bzobjs_adapter_is_usable_for_device(bzobj) - != bzobj->was_usable_adapter_for_device_before) { - nm_utils_strbuf_append_str(&buf, &len, prefix); - prefix = ", "; - nm_utils_strbuf_append(&buf, &len, "change-usable-adapter-for-device: 1"); - } - - return buf0; -} - -#define _LOG_bzobj(bzobj, context) \ - G_STMT_START \ - { \ - const BzDBusObj *const _bzobj = (bzobj); \ - char _buf[500]; \ - \ - _LOGT("change %-21s %s : { %s }", \ - (context), \ - _bzobj->object_path, \ - _bzobj_to_string(_bzobj, _buf, sizeof(_buf))); \ - } \ - G_STMT_END - -static gboolean -_bzobjs_is_dead(const BzDBusObj *bzobj) -{ - return !bzobj->d_has_adapter_iface && !bzobj->d_has_device_iface && !bzobj->d_has_network_iface - && !bzobj->d_has_network_server_iface && c_list_is_empty(&bzobj->process_change_lst); -} - -static BzDBusObj * -_bzobjs_get(NMBluezManager *self, const char *object_path) -{ - return g_hash_table_lookup(NM_BLUEZ_MANAGER_GET_PRIVATE(self)->bzobjs, &object_path); -} - -static BzDBusObj * -_bzobjs_add(NMBluezManager *self, const char *object_path) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - BzDBusObj * bzobj; - - bzobj = _bz_dbus_obj_new(self, object_path); - if (!g_hash_table_add(priv->bzobjs, bzobj)) - nm_assert_not_reached(); - return bzobj; -} - -static void -_bzobjs_del(BzDBusObj *bzobj) -{ - nm_assert(bzobj); - nm_assert(bzobj == _bzobjs_get(bzobj->self, bzobj->object_path)); - - if (!g_hash_table_remove(NM_BLUEZ_MANAGER_GET_PRIVATE(bzobj->self)->bzobjs, bzobj)) - nm_assert_not_reached(); -} - -static void -_bzobjs_del_if_dead(BzDBusObj *bzobj) -{ - if (_bzobjs_is_dead(bzobj)) - _bzobjs_del(bzobj); -} - -static BzDBusObj * -_bzobjs_init(NMBluezManager *self, BzDBusObj **inout, const char *object_path) -{ - nm_assert(NM_IS_BLUEZ_MANAGER(self)); - nm_assert(object_path); - nm_assert(inout); - - if (!*inout) { - *inout = _bzobjs_get(self, object_path); - if (!*inout) - *inout = _bzobjs_add(self, object_path); - } - - nm_assert(nm_streq((*inout)->object_path, object_path)); - nm_assert(*inout == _bzobjs_get(self, object_path)); - return *inout; -} - -static gboolean -_bzobjs_adapter_is_usable_for_device(const BzDBusObj *bzobj) -{ - return bzobj->d_has_adapter_iface && bzobj->d_adapter.address && bzobj->d_adapter_powered; -} - -static gboolean -_bzobjs_device_is_usable(const BzDBusObj *bzobj, - BzDBusObj ** out_adapter_bzobj, - gboolean * out_create_panu_connection) -{ - NMBluezManager * self; - NMBluezManagerPrivate *priv; - gboolean usable_dun = FALSE; - gboolean usable_nap = FALSE; - BzDBusObj * bzobj_adapter; - gboolean create_panu_connection = FALSE; - - if (!bzobj->d_has_device_iface - || !NM_FLAGS_ANY((NMBluetoothCapabilities) bzobj->d_device_capabilities, - _NM_BT_CAPABILITY_SUPPORTED) - || !bzobj->d_device.name || !bzobj->d_device.address || !bzobj->d_device_paired - || !bzobj->d_device.adapter) - goto out_unusable; - - self = bzobj->self; - - priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - if (!priv->settings_registered) - goto out_unusable; - - bzobj_adapter = _bzobjs_get(self, bzobj->d_device.adapter); - if (!bzobj_adapter || !_bzobjs_adapter_is_usable_for_device(bzobj_adapter)) - goto out_unusable; - -#if WITH_BLUEZ5_DUN - if (NM_FLAGS_HAS(bzobj->d_device_capabilities, NM_BT_CAPABILITY_DUN)) { - if (_conn_track_find_head(self, NM_BT_CAPABILITY_DUN, bzobj->d_device.address)) - usable_dun = TRUE; - } -#endif - - if (NM_FLAGS_HAS(bzobj->d_device_capabilities, NM_BT_CAPABILITY_NAP)) { - if (!bzobj->d_has_network_iface) - usable_nap = FALSE; - else if (_conn_track_find_head(self, NM_BT_CAPABILITY_NAP, bzobj->d_device.address)) - usable_nap = TRUE; - else if (bzobj->x_device_panu_connection_allow_create) { - /* We didn't yet try to create a connection. Presume we are going to create - * it when the time comes... */ - usable_nap = TRUE; - create_panu_connection = TRUE; - } - } - - if (!usable_dun && !usable_nap) { - if (bzobj->x_device.device_bt - && nm_device_get_state(NM_DEVICE(bzobj->x_device.device_bt)) - > NM_DEVICE_STATE_DISCONNECTED) { - /* The device is still activated... the absence of a profile does not - * render it unusable (yet). But since there is no more profile, the - * device is probably about to disconnect. */ - } else - goto out_unusable; - } - - NM_SET_OUT(out_create_panu_connection, create_panu_connection); - NM_SET_OUT(out_adapter_bzobj, bzobj_adapter); - return TRUE; - -out_unusable: - NM_SET_OUT(out_create_panu_connection, FALSE); - NM_SET_OUT(out_adapter_bzobj, NULL); - return FALSE; -} - -static gboolean -_bzobjs_device_is_connected(const BzDBusObj *bzobj) -{ - nm_assert(_bzobjs_device_is_usable(bzobj, NULL, NULL)); - - if (!bzobj->d_has_device_iface || !bzobj->d_device_connected) - return FALSE; - - if (bzobj->d_has_network_iface && bzobj->d_network_connected) - return TRUE; - if (bzobj->x_device.connect_dun_context) { - /* As long as we have a dun-context, we consider it connected. - * - * We require NMDeviceBt to try to connect to the modem, and if that fails, - * it will disconnect. */ - return TRUE; - } - return FALSE; -} - -static gboolean -_bzobjs_network_server_is_usable(const BzDBusObj *bzobj, gboolean require_powered) -{ - return bzobj->d_has_network_server_iface && bzobj->d_has_adapter_iface - && bzobj->d_adapter.address && (!require_powered || bzobj->d_adapter_powered); -} - -/*****************************************************************************/ - -static ConnDataHead * -_conn_data_head_new(NMBluetoothCapabilities bt_type, const char *bdaddr) -{ - ConnDataHead *cdata_hd; - gsize l; - - nm_assert(NM_IN_SET(bt_type, NM_BT_CAPABILITY_DUN, NM_BT_CAPABILITY_NAP)); - nm_assert(bdaddr); - - l = strlen(bdaddr) + 1; - cdata_hd = g_malloc(sizeof(ConnDataHead) + l); - *cdata_hd = (ConnDataHead){ - .bdaddr = cdata_hd->bdaddr_data, - .lst_head = C_LIST_INIT(cdata_hd->lst_head), - .bt_type = bt_type, - }; - memcpy(cdata_hd->bdaddr_data, bdaddr, l); - - nm_assert(cdata_hd->bt_type == bt_type); - - return cdata_hd; -} - -static guint -_conn_data_head_hash(gconstpointer ptr) -{ - const ConnDataHead *cdata_hd = ptr; - NMHashState h; - - nm_hash_init(&h, 520317467u); - nm_hash_update_val(&h, (NMBluetoothCapabilities) cdata_hd->bt_type); - nm_hash_update_str(&h, cdata_hd->bdaddr); - return nm_hash_complete(&h); -} - -static gboolean -_conn_data_head_equal(gconstpointer a, gconstpointer b) -{ - const ConnDataHead *cdata_hd_a = a; - const ConnDataHead *cdata_hd_b = b; - - return cdata_hd_a->bt_type == cdata_hd_b->bt_type - && nm_streq(cdata_hd_a->bdaddr, cdata_hd_b->bdaddr); -} - -static ConnDataHead * -_conn_track_find_head(NMBluezManager *self, NMBluetoothCapabilities bt_type, const char *bdaddr) -{ - ConnDataHead cdata_hd = { - .bt_type = bt_type, - .bdaddr = bdaddr, - }; - - return g_hash_table_lookup(NM_BLUEZ_MANAGER_GET_PRIVATE(self)->conn_data_heads, &cdata_hd); -} - -static ConnDataElem * -_conn_track_find_elem(NMBluezManager *self, NMSettingsConnection *sett_conn) -{ - G_STATIC_ASSERT(G_STRUCT_OFFSET(ConnDataElem, sett_conn) == 0); - - return g_hash_table_lookup(NM_BLUEZ_MANAGER_GET_PRIVATE(self)->conn_data_elems, &sett_conn); -} - -static gboolean -_conn_track_is_relevant_connection(NMConnection * connection, - NMBluetoothCapabilities *out_bt_type, - const char ** out_bdaddr) -{ - NMSettingBluetooth * s_bt; - NMBluetoothCapabilities bt_type; - const char * bdaddr; - const char * b_type; - - s_bt = nm_connection_get_setting_bluetooth(connection); - if (!s_bt) - return FALSE; - - if (!nm_connection_is_type(connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) - return FALSE; - - bdaddr = nm_setting_bluetooth_get_bdaddr(s_bt); - if (!bdaddr) - return FALSE; - - b_type = nm_setting_bluetooth_get_connection_type(s_bt); - - if (nm_streq(b_type, NM_SETTING_BLUETOOTH_TYPE_DUN)) - bt_type = NM_BT_CAPABILITY_DUN; - else if (nm_streq(b_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) - bt_type = NM_BT_CAPABILITY_NAP; - else - return FALSE; - - NM_SET_OUT(out_bt_type, bt_type); - NM_SET_OUT(out_bdaddr, bdaddr); - return TRUE; -} - -static gboolean -_conn_track_is_relevant_sett_conn(NMSettingsConnection * sett_conn, - NMBluetoothCapabilities *out_bt_type, - const char ** out_bdaddr) -{ - NMConnection *connection; - - connection = nm_settings_connection_get_connection(sett_conn); - if (!connection) - return FALSE; - - return _conn_track_is_relevant_connection(connection, out_bt_type, out_bdaddr); -} - -static gboolean -_conn_track_is_relevant_for_sett_conn(NMSettingsConnection * sett_conn, - NMBluetoothCapabilities bt_type, - const char * bdaddr) -{ - NMBluetoothCapabilities x_bt_type; - const char * x_bdaddr; - - return bdaddr && _conn_track_is_relevant_sett_conn(sett_conn, &x_bt_type, &x_bdaddr) - && x_bt_type == bt_type && nm_streq(x_bdaddr, bdaddr); -} - -static void -_conn_track_schedule_notify(NMBluezManager * self, - NMBluetoothCapabilities bt_type, - const char * bdaddr) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - GHashTableIter iter; - BzDBusObj * bzobj; - - g_hash_table_iter_init(&iter, priv->bzobjs); - while (g_hash_table_iter_next(&iter, (gpointer *) &bzobj, NULL)) { - gboolean device_is_usable; - - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, NULL); - if (bzobj->x_device_is_usable != device_is_usable) - _process_change_idle_schedule(self, bzobj); - } -} - -static void -_conn_track_update(NMBluezManager * self, - NMSettingsConnection *sett_conn, - gboolean track, - gboolean * out_changed, - gboolean * out_changed_usable, - ConnDataElem ** out_conn_data_elem) -{ - NMBluezManagerPrivate * priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - ConnDataHead * cdata_hd; - ConnDataElem * cdata_el; - ConnDataElem * cdata_el_remove = NULL; - NMBluetoothCapabilities bt_type; - const char * bdaddr; - gboolean changed = FALSE; - gboolean changed_usable = FALSE; - char sbuf_cap[100]; - - nm_assert(NM_IS_SETTINGS_CONNECTION(sett_conn)); - - cdata_el = _conn_track_find_elem(self, sett_conn); - - if (track) - track = _conn_track_is_relevant_sett_conn(sett_conn, &bt_type, &bdaddr); - - if (!track) { - cdata_el_remove = g_steal_pointer(&cdata_el); - goto out_remove; - } - - if (cdata_el) { - cdata_hd = cdata_el->cdata_hd; - if (cdata_hd->bt_type != bt_type || !nm_streq(cdata_hd->bdaddr, bdaddr)) - cdata_el_remove = g_steal_pointer(&cdata_el); - } - - if (!cdata_el) { - _LOGT("connection: track for %s, %s: %s (%s)", - nm_bluetooth_capability_to_string(bt_type, sbuf_cap, sizeof(sbuf_cap)), - bdaddr, - nm_settings_connection_get_uuid(sett_conn), - nm_settings_connection_get_id(sett_conn)); - changed = TRUE; - cdata_hd = _conn_track_find_head(self, bt_type, bdaddr); - if (!cdata_hd) { - changed_usable = TRUE; - cdata_hd = _conn_data_head_new(bt_type, bdaddr); - if (!g_hash_table_add(priv->conn_data_heads, cdata_hd)) - nm_assert_not_reached(); - _conn_track_schedule_notify(self, bt_type, bdaddr); - } - cdata_el = g_slice_new(ConnDataElem); - cdata_el->sett_conn = sett_conn; - cdata_el->cdata_hd = cdata_hd; - c_list_link_tail(&cdata_hd->lst_head, &cdata_el->lst); - if (!g_hash_table_add(priv->conn_data_elems, cdata_el)) - nm_assert_not_reached(); - } - -out_remove: - if (cdata_el_remove) { - GHashTableIter iter; - BzDBusObj * bzobj; - - _LOGT("connection: untrack for %s, %s: %s (%s)", - nm_bluetooth_capability_to_string(cdata_el_remove->cdata_hd->bt_type, - sbuf_cap, - sizeof(sbuf_cap)), - cdata_el_remove->cdata_hd->bdaddr, - nm_settings_connection_get_uuid(sett_conn), - nm_settings_connection_get_id(sett_conn)); - - g_hash_table_iter_init(&iter, priv->bzobjs); - while (g_hash_table_iter_next(&iter, (gpointer *) &bzobj, NULL)) { - if (bzobj->x_device.panu_connection == sett_conn) - bzobj->x_device.panu_connection = NULL; - } - - changed = TRUE; - cdata_hd = cdata_el_remove->cdata_hd; - c_list_unlink_stale(&cdata_el_remove->lst); - if (!g_hash_table_remove(priv->conn_data_elems, cdata_el_remove)) - nm_assert_not_reached(); - if (c_list_is_empty(&cdata_hd->lst_head)) { - changed_usable = TRUE; - _conn_track_schedule_notify(self, cdata_hd->bt_type, cdata_hd->bdaddr); - if (!g_hash_table_remove(priv->conn_data_heads, cdata_hd)) - nm_assert_not_reached(); - } - } - - NM_SET_OUT(out_changed, changed); - NM_SET_OUT(out_changed_usable, changed_usable); - NM_SET_OUT(out_conn_data_elem, cdata_el); -} - -/*****************************************************************************/ - -static void -cp_connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, NMBluezManager *self) -{ - _conn_track_update(self, sett_conn, TRUE, NULL, NULL, NULL); -} - -static void -cp_connection_updated(NMSettings * settings, - NMSettingsConnection *sett_conn, - guint update_reason_u, - NMBluezManager * self) -{ - _conn_track_update(self, sett_conn, TRUE, NULL, NULL, NULL); -} - -static void -cp_connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, NMBluezManager *self) -{ - _conn_track_update(self, sett_conn, FALSE, NULL, NULL, NULL); -} - -/*****************************************************************************/ - -static NMBluezManager * -_network_server_get_bluez_manager(const NMBtVTableNetworkServer *vtable_network_server) -{ - NMBluezManager *self; - - self = (NMBluezManager *) (((char *) vtable_network_server) - - G_STRUCT_OFFSET(NMBluezManager, _priv.vtable_network_server)); - - g_return_val_if_fail(NM_IS_BLUEZ_MANAGER(self), NULL); - - return self; -} - -static BzDBusObj * -_network_server_find_has_device(NMBluezManagerPrivate *priv, NMDevice *device) -{ - BzDBusObj *bzobj; - - c_list_for_each_entry (bzobj, &priv->network_server_lst_head, x_network_server.lst) { - if (bzobj->x_network_server.device_br == device) - return bzobj; - } - return NULL; -} - -static BzDBusObj * -_network_server_find_available(NMBluezManagerPrivate *priv, - const char * addr, - NMDevice * device_accept_busy) -{ - BzDBusObj *bzobj; - - c_list_for_each_entry (bzobj, &priv->network_server_lst_head, x_network_server.lst) { - if (bzobj->x_network_server.device_br) { - if (bzobj->x_network_server.device_br != device_accept_busy) - continue; - } - if (addr && !nm_streq(addr, bzobj->d_adapter.address)) - continue; - nm_assert(!bzobj->x_network_server.r_req_data); - return bzobj; - } - return NULL; -} - -static gboolean -_network_server_vt_is_available(const NMBtVTableNetworkServer *vtable, - const char * addr, - NMDevice * device_accept_busy) -{ - NMBluezManager * self = _network_server_get_bluez_manager(vtable); - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - return !!_network_server_find_available(priv, addr, device_accept_busy); -} - -static void -_network_server_register_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - BzDBusObj * bzobj; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source_object), res, &error); - if (!ret && nm_utils_error_is_cancelled(error)) - return; - - bzobj = user_data; - - if (!ret) { - _LOGT("NAP: [%s]: registering failed: %s", bzobj->object_path, error->message); - } else - _LOGT("NAP: [%s]: registration successful", bzobj->object_path); - - g_clear_object(&bzobj->x_network_server.r_req_data->int_cancellable); - _network_server_register_req_data_complete(g_steal_pointer(&bzobj->x_network_server.r_req_data), - error); -} - -static void -_network_server_register_cancelled_cb(GCancellable *cancellable, BzDBusObj *bzobj) -{ - _network_server_unregister_bridge(bzobj->self, bzobj, "registration cancelled"); -} - -static gboolean -_network_server_vt_register_bridge(const NMBtVTableNetworkServer *vtable, - const char * addr, - NMDevice * device, - GCancellable * cancellable, - NMBtVTableRegisterCallback callback, - gpointer callback_user_data, - GError ** error) -{ - NMBluezManager * self = _network_server_get_bluez_manager(vtable); - NMBluezManagerPrivate * priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - NetworkServerRegisterReqData *r_req_data; - BzDBusObj * bzobj; - const char * ifname; - - g_return_val_if_fail(NM_IS_DEVICE(device), FALSE); - g_return_val_if_fail(G_IS_CANCELLABLE(cancellable), FALSE); - - nm_assert(!g_cancellable_is_cancelled(cancellable)); - nm_assert(!_network_server_find_has_device(priv, device)); - - ifname = nm_device_get_iface(device); - g_return_val_if_fail(ifname, FALSE); - - g_return_val_if_fail(ifname, FALSE); - - bzobj = _network_server_find_available(priv, addr, NULL); - if (!bzobj) { - /* The device checked that a network server is available, before - * starting the activation, but for some reason it no longer is. - * Indicate that the activation should not proceed. */ - if (addr) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "adapter %s is not available for %s", - addr, - ifname); - } else { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "no adapter available for %s", - ifname); - } - return FALSE; - } - - _LOGD("NAP: [%s]: registering \"%s\" on adapter %s", - bzobj->object_path, - ifname, - bzobj->d_adapter.address); - - r_req_data = g_slice_new(NetworkServerRegisterReqData); - *r_req_data = (NetworkServerRegisterReqData){ - .int_cancellable = g_cancellable_new(), - .ext_cancellable = g_object_ref(cancellable), - .callback = callback, - .callback_user_data = callback_user_data, - .ext_cancelled_id = g_signal_connect(cancellable, - "cancelled", - G_CALLBACK(_network_server_register_cancelled_cb), - bzobj), - }; - - bzobj->x_network_server.device_br = g_object_ref(device); - bzobj->x_network_server.r_req_data = r_req_data; - - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_NETWORK_SERVER_INTERFACE, - "Register", - g_variant_new("(ss)", BLUETOOTH_CONNECT_NAP, ifname), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - bzobj->x_network_server.r_req_data->int_cancellable, - _network_server_register_cb, - bzobj); - return TRUE; -} - -static void -_network_server_unregister_bridge_complete_on_idle_cb(gpointer user_data, GCancellable *cancellable) -{ - gs_free_error GError * error = NULL; - gs_free char * reason = NULL; - NetworkServerRegisterReqData *r_req_data; - - nm_utils_user_data_unpack(user_data, &r_req_data, &reason); - - nm_utils_error_set(&error, - NM_UTILS_ERROR_UNKNOWN, - "registration was aborted due to %s", - reason); - _network_server_register_req_data_complete(r_req_data, error); -} - -static void -_network_server_unregister_bridge(NMBluezManager *self, BzDBusObj *bzobj, const char *reason) -{ - NMBluezManagerPrivate * priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - _nm_unused gs_unref_object NMDevice *device = NULL; - NetworkServerRegisterReqData * r_req_data; - - nm_assert(NM_IS_DEVICE(bzobj->x_network_server.device_br)); - - _LOGD("NAP: [%s]: unregistering \"%s\" (%s)", - bzobj->object_path, - nm_device_get_iface(bzobj->x_network_server.device_br), - reason); - - device = g_steal_pointer(&bzobj->x_network_server.device_br); - - r_req_data = g_steal_pointer(&bzobj->x_network_server.r_req_data); - - if (priv->name_owner) { - gs_unref_object GCancellable *cancellable = NULL; - - cancellable = g_cancellable_new(); - - nm_shutdown_wait_obj_register_cancellable_full( - cancellable, - g_strdup_printf("bt-unregister-nap[%s]", bzobj->object_path), - TRUE); - - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_NETWORK_SERVER_INTERFACE, - "Unregister", - g_variant_new("(s)", BLUETOOTH_CONNECT_NAP), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - cancellable, - _dbus_call_complete_cb_nop, - NULL); - } - - if (r_req_data) { - nm_clear_g_cancellable(&r_req_data->int_cancellable); - nm_utils_invoke_on_idle(r_req_data->ext_cancellable, - _network_server_unregister_bridge_complete_on_idle_cb, - nm_utils_user_data_pack(r_req_data, g_strdup(reason))); - } - - _nm_device_bridge_notify_unregister_bt_nap(device, reason); -} - -static gboolean -_network_server_vt_unregister_bridge(const NMBtVTableNetworkServer *vtable, NMDevice *device) -{ - NMBluezManager * self = _network_server_get_bluez_manager(vtable); - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - BzDBusObj * bzobj; - - g_return_val_if_fail(NM_IS_DEVICE(device), FALSE); - - bzobj = _network_server_find_has_device(priv, device); - if (bzobj) - _network_server_unregister_bridge(self, bzobj, "disconnecting"); - - return TRUE; -} - -static void -_network_server_process_change(BzDBusObj *bzobj, gboolean *out_emit_device_availability_changed) -{ - NMBluezManager * self = bzobj->self; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gboolean network_server_is_usable; - gboolean emit_device_availability_changed = FALSE; - - network_server_is_usable = _bzobjs_network_server_is_usable(bzobj, TRUE); - - if (!network_server_is_usable) { - if (!c_list_is_empty(&bzobj->x_network_server.lst)) { - emit_device_availability_changed = TRUE; - c_list_unlink(&bzobj->x_network_server.lst); - } - - nm_clear_g_free(&bzobj->x_network_server.adapter_address); - - if (bzobj->x_network_server.device_br) { - _network_server_unregister_bridge(self, - bzobj, - _bzobjs_network_server_is_usable(bzobj, FALSE) - ? "adapter disabled" - : "adapter disappeared"); - } - - } else { - if (!nm_streq0(bzobj->x_network_server.adapter_address, bzobj->d_adapter.address)) { - emit_device_availability_changed = TRUE; - g_free(bzobj->x_network_server.adapter_address); - bzobj->x_network_server.adapter_address = g_strdup(bzobj->d_adapter.address); - } - - if (c_list_is_empty(&bzobj->x_network_server.lst)) { - emit_device_availability_changed = TRUE; - c_list_link_tail(&priv->network_server_lst_head, &bzobj->x_network_server.lst); - } - } - - if (emit_device_availability_changed) - NM_SET_OUT(out_emit_device_availability_changed, TRUE); -} - -/*****************************************************************************/ - -static void -_conn_create_panu_connection(NMBluezManager *self, BzDBusObj *bzobj) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gs_unref_object NMConnection *connection = NULL; - NMSettingsConnection * added; - NMSetting * setting; - gs_free char * id = NULL; - char uuid[37]; - gs_free_error GError *error = NULL; - - nm_utils_uuid_generate_buf(uuid); - id = g_strdup_printf(_("%s Network"), bzobj->d_device.name); - - connection = nm_simple_connection_new(); - - setting = nm_setting_connection_new(); - g_object_set(setting, - NM_SETTING_CONNECTION_ID, - id, - NM_SETTING_CONNECTION_UUID, - uuid, - NM_SETTING_CONNECTION_AUTOCONNECT, - FALSE, - NM_SETTING_CONNECTION_TYPE, - NM_SETTING_BLUETOOTH_SETTING_NAME, - NULL); - nm_connection_add_setting(connection, setting); - - setting = nm_setting_bluetooth_new(); - g_object_set(setting, - NM_SETTING_BLUETOOTH_BDADDR, - bzobj->d_device.address, - NM_SETTING_BLUETOOTH_TYPE, - NM_SETTING_BLUETOOTH_TYPE_PANU, - NULL); - nm_connection_add_setting(connection, setting); - - if (!nm_connection_normalize(connection, NULL, NULL, &error)) { - _LOGE("connection: couldn't generate a connection for NAP device: %s", error->message); - g_return_if_reached(); - } - - nm_assert(_conn_track_is_relevant_connection(connection, NULL, NULL)); - - _LOGT("connection: create in-memory PANU connection %s (%s) for device \"%s\" (%s)", - uuid, - id, - bzobj->d_device.name, - bzobj->d_device.address); - - nm_settings_add_connection(priv->settings, - connection, - NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, - NM_SETTINGS_CONNECTION_ADD_REASON_NONE, - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, - &added, - &error); - if (!added) { - _LOGW("connection: couldn't add new Bluetooth connection for NAP device: '%s' (%s): %s", - id, - uuid, - error->message); - return; - } - - if (!_conn_track_is_relevant_for_sett_conn(added, NM_BT_CAPABILITY_NAP, bzobj->d_device.address) - || !_conn_track_find_elem(self, added) || bzobj->x_device.panu_connection) { - _LOGE("connection: something went wrong creating PANU connection %s (%s) for device '%s'", - uuid, - id, - bzobj->d_device.address); - g_return_if_reached(); - } - - bzobj->x_device.panu_connection = added; -} - -/*****************************************************************************/ - -static void -_device_state_changed_cb(NMDevice *device, - guint new_state_u, - guint old_state_u, - guint reason_u, - gpointer user_data) -{ - BzDBusObj *bzobj = user_data; - - if (!_bzobjs_device_is_usable(bzobj, NULL, NULL)) { - /* the device got unusable? Need to revisit it... */ - _process_change_idle_schedule(bzobj->self, bzobj); - } -} - -static void -_device_process_change(BzDBusObj *bzobj) -{ - NMBluezManager *self = bzobj->self; - gs_unref_object NMDeviceBt *device_added = NULL; - gs_unref_object NMDeviceBt *device_deleted = NULL; - gboolean device_is_usable; - gboolean create_panu_connection = FALSE; - - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, &create_panu_connection); - - if (create_panu_connection) { - bzobj->x_device_panu_connection_allow_create = FALSE; - _conn_create_panu_connection(self, bzobj); - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, NULL); - } else { - if (device_is_usable && bzobj->x_device_panu_connection_allow_create - && NM_FLAGS_HAS(bzobj->d_device_capabilities, NM_BT_CAPABILITY_NAP) - && _conn_track_find_head(self, NM_BT_CAPABILITY_NAP, bzobj->d_device.address)) { - /* We have a useable device and also a panu-connection. We block future attemps - * to generate a connection. */ - bzobj->x_device_panu_connection_allow_create = FALSE; - } - if (bzobj->x_device.panu_connection) { - if (!NM_FLAGS_HAS(nm_settings_connection_get_flags(bzobj->x_device.panu_connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)) { - /* the connection that we generated earlier still exists, but it's not longer the same - * as it was when we created it. Forget about it, so that we don't delete the profile later... */ - bzobj->x_device.panu_connection = NULL; - } else { - if (!device_is_usable - || !_conn_track_is_relevant_for_sett_conn(bzobj->x_device.panu_connection, - NM_BT_CAPABILITY_NAP, - bzobj->d_device.address)) { - _LOGT("connection: delete in-memory PANU connection %s (%s) as device %s", - nm_settings_connection_get_uuid(bzobj->x_device.panu_connection), - nm_settings_connection_get_id(bzobj->x_device.panu_connection), - !device_is_usable ? "is now unusable" : "no longer matches"); - bzobj->x_device_panu_connection_allow_create = TRUE; - nm_settings_connection_delete(g_steal_pointer(&bzobj->x_device.panu_connection), - FALSE); - } - } - } - } - - bzobj->x_device_is_connected = device_is_usable && _bzobjs_device_is_connected(bzobj); - - bzobj->x_device_is_usable = device_is_usable; - - if (bzobj->x_device.device_bt) { - const char *device_to_delete_msg; - - if (!device_is_usable) - device_to_delete_msg = "device became unusable"; - else if (!_nm_device_bt_for_same_device(bzobj->x_device.device_bt, - bzobj->object_path, - bzobj->d_device.address, - NULL, - bzobj->d_device_capabilities)) - device_to_delete_msg = "device is no longer compatible"; - else - device_to_delete_msg = NULL; - - if (device_to_delete_msg) { - nm_clear_g_signal_handler(bzobj->x_device.device_bt, - &bzobj->x_device.device_bt_signal_id); - - device_deleted = g_steal_pointer(&bzobj->x_device.device_bt); - - _LOGD("[%s]: drop device because %s", bzobj->object_path, device_to_delete_msg); - - _connect_disconnect(self, bzobj, device_to_delete_msg); - } - } - - if (device_is_usable) { - if (!bzobj->x_device.device_bt) { - bzobj->x_device.device_bt = nm_device_bt_new(self, - bzobj->object_path, - bzobj->d_device.address, - bzobj->d_device.name, - bzobj->d_device_capabilities); - device_added = g_object_ref(bzobj->x_device.device_bt); - bzobj->x_device.device_bt_signal_id = - g_signal_connect(device_added, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(_device_state_changed_cb), - bzobj); - } else - _nm_device_bt_notify_set_name(bzobj->x_device.device_bt, bzobj->d_device.name); - - _nm_device_bt_notify_set_connected(bzobj->x_device.device_bt, bzobj->x_device_is_connected); - } - - if (bzobj->x_device.c_req_data && !bzobj->x_device.c_req_data->int_cancellable - && bzobj->x_device_is_connected) { - gs_free char *device_name = g_steal_pointer(&bzobj->x_device.c_req_data->device_name); - - _device_connect_req_data_complete(g_steal_pointer(&bzobj->x_device.c_req_data), - self, - device_name, - NULL); - } - - if (device_added) - g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, device_added); - - if (device_deleted) - _nm_device_bt_notify_removed(device_deleted); -} - -/*****************************************************************************/ - -static void -_process_change_idle_all(NMBluezManager *self, gboolean *out_emit_device_availability_changed) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - BzDBusObj * bzobj; - - while ( - (bzobj = - c_list_first_entry(&priv->process_change_lst_head, BzDBusObj, process_change_lst))) { - c_list_unlink(&bzobj->process_change_lst); - - _LOG_bzobj(bzobj, "before-processing"); - - _device_process_change(bzobj); - - _network_server_process_change(bzobj, out_emit_device_availability_changed); - - _LOG_bzobj(bzobj, "after-processing"); - - _bzobjs_del_if_dead(bzobj); - } - - nm_clear_g_source(&priv->process_change_idle_id); -} - -static gboolean -_process_change_idle_cb(gpointer user_data) -{ - NMBluezManager * self = user_data; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gboolean emit_device_availability_changed = FALSE; - - _process_change_idle_all(self, &emit_device_availability_changed); - - if (emit_device_availability_changed) - nm_manager_notify_device_availability_maybe_changed(priv->manager); - - return G_SOURCE_CONTINUE; -} - -static void -_process_change_idle_schedule(NMBluezManager *self, BzDBusObj *bzobj) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - nm_c_list_move_tail(&priv->process_change_lst_head, &bzobj->process_change_lst); - if (priv->process_change_idle_id == 0) - priv->process_change_idle_id = - g_idle_add_full(G_PRIORITY_DEFAULT_IDLE + 1, _process_change_idle_cb, self, NULL); -} - -static void -_dbus_process_changes(NMBluezManager *self, BzDBusObj *bzobj, const char *log_reason) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gboolean network_server_is_usable; - gboolean adapter_is_usable_for_device; - gboolean device_is_usable; - gboolean changes = FALSE; - gboolean recheck_devices_for_adapter = FALSE; - - nm_assert(bzobj); - - _LOG_bzobj(bzobj, log_reason); - - device_is_usable = _bzobjs_device_is_usable(bzobj, NULL, NULL); - - if (bzobj->x_device_is_usable != device_is_usable) - changes = TRUE; - else if (bzobj->x_device.device_bt) { - if (!device_is_usable) - changes = TRUE; - else { - if (bzobj->x_device_is_connected != _bzobjs_device_is_connected(bzobj) - || !_nm_device_bt_for_same_device(bzobj->x_device.device_bt, - bzobj->object_path, - bzobj->d_device.address, - bzobj->d_device.name, - bzobj->d_device_capabilities)) - changes = TRUE; - } - } - - adapter_is_usable_for_device = _bzobjs_adapter_is_usable_for_device(bzobj); - if (adapter_is_usable_for_device != bzobj->was_usable_adapter_for_device_before) { - /* this function does not modify bzobj in any other cases except here. - * Usually changes are processed delayed, in the idle handler. - * - * But the bzobj->was_usable_adapter_for_device_before only exists to know whether - * we need to re-check device availability. It is correct to set the flag - * here, right before we checked. */ - bzobj->was_usable_adapter_for_device_before = adapter_is_usable_for_device; - recheck_devices_for_adapter = TRUE; - changes = TRUE; - } - - if (!changes) { - network_server_is_usable = _bzobjs_network_server_is_usable(bzobj, TRUE); - - if (network_server_is_usable != (!c_list_is_empty(&bzobj->x_network_server.lst))) - changes = TRUE; - else if (bzobj->x_network_server.device_br && !network_server_is_usable) - changes = TRUE; - else if (!nm_streq0(bzobj->d_has_adapter_iface ? bzobj->d_adapter.address : NULL, - bzobj->x_network_server.adapter_address)) - changes = TRUE; - } - - if (changes) - _process_change_idle_schedule(self, bzobj); - - if (recheck_devices_for_adapter) { - GHashTableIter iter; - BzDBusObj * bzobj2; - - /* we got a change to the availability of an adapter. We might need to recheck - * all devices that use this adapter... */ - g_hash_table_iter_init(&iter, priv->bzobjs); - while (g_hash_table_iter_next(&iter, (gpointer *) &bzobj2, NULL)) { - if (bzobj2 == bzobj) - continue; - if (!nm_streq0(bzobj2->d_device.adapter, bzobj->object_path)) - continue; - if (c_list_is_empty(&bzobj2->process_change_lst)) - _dbus_process_changes(self, bzobj2, "adapter-changed"); - else - nm_c_list_move_tail(&priv->process_change_lst_head, &bzobj2->process_change_lst); - } - } - - _bzobjs_del_if_dead(bzobj); -} - -/*****************************************************************************/ - -#define ALL_RELEVANT_INTERFACE_NAMES \ - NM_MAKE_STRV(NM_BLUEZ5_ADAPTER_INTERFACE, \ - NM_BLUEZ5_DEVICE_INTERFACE, \ - NM_BLUEZ5_NETWORK_INTERFACE, \ - NM_BLUEZ5_NETWORK_SERVER_INTERFACE) - -static gboolean -_dbus_handle_properties_changed(NMBluezManager * self, - const char * object_path, - const char * interface_name, - GVariant * changed_properties, - const char *const *invalidated_properties, - BzDBusObj ** inout_bzobj) -{ - BzDBusObj * bzobj = NULL; - gboolean changed = FALSE; - const char * property_name; - GVariant * property_value; - GVariantIter iter_prop; - gsize i; - - if (!invalidated_properties) - invalidated_properties = NM_PTRARRAY_EMPTY(const char *); - - nm_assert(g_variant_is_of_type(changed_properties, G_VARIANT_TYPE("a{sv}"))); - - if (inout_bzobj) { - bzobj = *inout_bzobj; - nm_assert(!bzobj || nm_streq(object_path, bzobj->object_path)); - } - - if (changed_properties) - g_variant_iter_init(&iter_prop, changed_properties); - - if (nm_streq(interface_name, NM_BLUEZ5_ADAPTER_INTERFACE)) { - _bzobjs_init(self, &bzobj, object_path); - if (!bzobj->d_has_adapter_iface) { - changed = TRUE; - bzobj->d_has_adapter_iface = TRUE; - } - - while (changed_properties - && g_variant_iter_next(&iter_prop, "{&sv}", &property_name, &property_value)) { - _nm_unused gs_unref_variant GVariant *property_value_free = property_value; - - if (nm_streq(property_name, "Address")) { - gs_free char *s = - g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING) - ? nm_utils_hwaddr_canonical(g_variant_get_string(property_value, NULL), - ETH_ALEN) - : NULL; - - if (!nm_streq0(bzobj->d_adapter.address, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_adapter.address); - bzobj->d_adapter.address = g_steal_pointer(&s); - } - continue; - } - if (nm_streq(property_name, "Powered")) { - bool v = g_variant_is_of_type(property_value, G_VARIANT_TYPE_BOOLEAN) - && g_variant_get_boolean(property_value); - - if (bzobj->d_adapter_powered != v) { - changed = TRUE; - bzobj->d_adapter_powered = v; - } - continue; - } - } - - for (i = 0; (property_name = invalidated_properties[i]); i++) { - if (nm_streq(property_name, "Address")) { - if (bzobj->d_adapter.address) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_adapter.address); - } - continue; - } - if (nm_streq(property_name, "Powered")) { - if (bzobj->d_adapter_powered) { - changed = TRUE; - bzobj->d_adapter_powered = FALSE; - } - continue; - } - } - - } else if (nm_streq(interface_name, NM_BLUEZ5_DEVICE_INTERFACE)) { - _bzobjs_init(self, &bzobj, object_path); - if (!bzobj->d_has_device_iface) { - changed = TRUE; - bzobj->d_has_device_iface = TRUE; - } - - while (changed_properties - && g_variant_iter_next(&iter_prop, "{&sv}", &property_name, &property_value)) { - _nm_unused gs_unref_variant GVariant *property_value_free = property_value; - - if (nm_streq(property_name, "Address")) { - gs_free char *s = - g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING) - ? nm_utils_hwaddr_canonical(g_variant_get_string(property_value, NULL), - ETH_ALEN) - : NULL; - - if (!nm_streq0(bzobj->d_device.address, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.address); - bzobj->d_device.address = g_steal_pointer(&s); - } - continue; - } - if (nm_streq(property_name, "Name")) { - const char *s = g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING) - ? g_variant_get_string(property_value, NULL) - : NULL; - - if (!nm_streq0(bzobj->d_device.name, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.name); - bzobj->d_device.name = g_strdup(s); - } - continue; - } - if (nm_streq(property_name, "Adapter")) { - const char *s = g_variant_is_of_type(property_value, G_VARIANT_TYPE_OBJECT_PATH) - ? g_variant_get_string(property_value, NULL) - : NULL; - - if (!nm_streq0(bzobj->d_device.adapter, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.adapter); - bzobj->d_device.adapter = g_strdup(s); - } - continue; - } - if (nm_streq(property_name, "UUIDs")) { - NMBluetoothCapabilities capabilities = NM_BT_CAPABILITY_NONE; - - if (g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING_ARRAY)) { - gs_free const char **s = g_variant_get_strv(property_value, NULL); - - capabilities = convert_uuids_to_capabilities(s); - } - if (bzobj->d_device_capabilities != capabilities) { - changed = TRUE; - bzobj->d_device_capabilities = capabilities; - nm_assert(bzobj->d_device_capabilities == capabilities); - } - continue; - } - if (nm_streq(property_name, "Connected")) { - bool v = g_variant_is_of_type(property_value, G_VARIANT_TYPE_BOOLEAN) - && g_variant_get_boolean(property_value); - - if (bzobj->d_device_connected != v) { - changed = TRUE; - bzobj->d_device_connected = v; - } - continue; - } - if (nm_streq(property_name, "Paired")) { - bool v = g_variant_is_of_type(property_value, G_VARIANT_TYPE_BOOLEAN) - && g_variant_get_boolean(property_value); - - if (bzobj->d_device_paired != v) { - changed = TRUE; - bzobj->d_device_paired = v; - } - continue; - } - } - - for (i = 0; (property_name = invalidated_properties[i]); i++) { - if (nm_streq(property_name, "Address")) { - if (bzobj->d_device.address) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.address); - } - continue; - } - if (nm_streq(property_name, "Name")) { - if (bzobj->d_device.name) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.name); - } - continue; - } - if (nm_streq(property_name, "Adapter")) { - if (bzobj->d_device.adapter) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.adapter); - } - continue; - } - if (nm_streq(property_name, "UUIDs")) { - if (bzobj->d_device_capabilities != NM_BT_CAPABILITY_NONE) { - changed = TRUE; - bzobj->d_device_capabilities = NM_BT_CAPABILITY_NONE; - } - continue; - } - if (nm_streq(property_name, "Connected")) { - if (bzobj->d_device_connected) { - changed = TRUE; - bzobj->d_device_connected = FALSE; - } - continue; - } - if (nm_streq(property_name, "Paired")) { - if (bzobj->d_device_paired) { - changed = TRUE; - bzobj->d_device_paired = FALSE; - } - continue; - } - } - - } else if (nm_streq(interface_name, NM_BLUEZ5_NETWORK_INTERFACE)) { - _bzobjs_init(self, &bzobj, object_path); - if (!bzobj->d_has_network_iface) { - changed = TRUE; - bzobj->d_has_network_iface = TRUE; - } - - while (changed_properties - && g_variant_iter_next(&iter_prop, "{&sv}", &property_name, &property_value)) { - _nm_unused gs_unref_variant GVariant *property_value_free = property_value; - - if (nm_streq(property_name, "Interface")) { - const char *s = g_variant_is_of_type(property_value, G_VARIANT_TYPE_STRING) - ? g_variant_get_string(property_value, NULL) - : NULL; - - if (!nm_streq0(bzobj->d_network.interface, s)) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_network.interface); - bzobj->d_network.interface = g_strdup(s); - } - continue; - } - if (nm_streq(property_name, "Connected")) { - bool v = g_variant_is_of_type(property_value, G_VARIANT_TYPE_BOOLEAN) - && g_variant_get_boolean(property_value); - - if (bzobj->d_network_connected != v) { - changed = TRUE; - bzobj->d_network_connected = v; - } - continue; - } - } - - for (i = 0; (property_name = invalidated_properties[i]); i++) { - if (nm_streq(property_name, "Interface")) { - if (bzobj->d_network.interface) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_network.interface); - } - continue; - } - if (nm_streq(property_name, "Connected")) { - if (bzobj->d_network_connected) { - changed = TRUE; - bzobj->d_network_connected = FALSE; - } - continue; - } - } - - } else if (nm_streq(interface_name, NM_BLUEZ5_NETWORK_SERVER_INTERFACE)) { - _bzobjs_init(self, &bzobj, object_path); - if (!bzobj->d_has_network_server_iface) { - changed = TRUE; - bzobj->d_has_network_server_iface = TRUE; - } - } - - nm_assert(!changed || bzobj); - - if (inout_bzobj) - *inout_bzobj = bzobj; - - return changed; -} - -static void -_dbus_handle_interface_added(NMBluezManager *self, - const char * object_path, - GVariant * ifaces, - gboolean initial_get_managed_objects) -{ - BzDBusObj * bzobj = NULL; - gboolean changed = FALSE; - const char * interface_name; - GVariant * changed_properties; - GVariantIter iter_ifaces; - - nm_assert(g_variant_is_of_type(ifaces, G_VARIANT_TYPE("a{sa{sv}}"))); - - g_variant_iter_init(&iter_ifaces, ifaces); - while (g_variant_iter_next(&iter_ifaces, "{&s@a{sv}}", &interface_name, &changed_properties)) { - _nm_unused gs_unref_variant GVariant *changed_properties_free = changed_properties; - - if (_dbus_handle_properties_changed(self, - object_path, - interface_name, - changed_properties, - NULL, - &bzobj)) - changed = TRUE; - } - - if (changed) { - _dbus_process_changes(self, - bzobj, - initial_get_managed_objects ? "dbus-init" : "dbus-iface-added"); - } -} - -static gboolean -_dbus_handle_interface_removed(NMBluezManager * self, - const char * object_path, - BzDBusObj ** inout_bzobj, - const char *const *removed_interfaces) -{ - gboolean changed = FALSE; - BzDBusObj *bzobj; - gsize i; - - if (inout_bzobj && *inout_bzobj) { - bzobj = *inout_bzobj; - nm_assert(bzobj == _bzobjs_get(self, object_path)); - } else { - bzobj = _bzobjs_get(self, object_path); - if (!bzobj) - return FALSE; - NM_SET_OUT(inout_bzobj, bzobj); - } - - for (i = 0; removed_interfaces[i]; i++) { - const char *interface_name = removed_interfaces[i]; - - if (nm_streq(interface_name, NM_BLUEZ5_ADAPTER_INTERFACE)) { - if (bzobj->d_has_adapter_iface) { - changed = TRUE; - bzobj->d_has_adapter_iface = FALSE; - } - if (bzobj->d_adapter.address) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_adapter.address); - } - if (bzobj->d_adapter_powered) { - changed = TRUE; - bzobj->d_adapter_powered = FALSE; - } - } else if (nm_streq(interface_name, NM_BLUEZ5_DEVICE_INTERFACE)) { - if (bzobj->d_has_device_iface) { - changed = TRUE; - bzobj->d_has_device_iface = FALSE; - } - if (bzobj->d_device.address) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.address); - } - if (bzobj->d_device.name) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.name); - } - if (bzobj->d_device.adapter) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_device.adapter); - } - if (bzobj->d_device_capabilities != NM_BT_CAPABILITY_NONE) { - changed = TRUE; - bzobj->d_device_capabilities = NM_BT_CAPABILITY_NONE; - } - if (bzobj->d_device_connected) { - changed = TRUE; - bzobj->d_device_connected = FALSE; - } - if (bzobj->d_device_paired) { - changed = TRUE; - bzobj->d_device_paired = FALSE; - } - } else if (nm_streq(interface_name, NM_BLUEZ5_NETWORK_INTERFACE)) { - if (bzobj->d_has_network_iface) { - changed = TRUE; - bzobj->d_has_network_iface = FALSE; - } - if (bzobj->d_network.interface) { - changed = TRUE; - nm_clear_g_free(&bzobj->d_network.interface); - } - if (bzobj->d_network_connected) { - changed = TRUE; - bzobj->d_network_connected = FALSE; - } - } else if (nm_streq(interface_name, NM_BLUEZ5_NETWORK_SERVER_INTERFACE)) { - if (bzobj->d_has_network_server_iface) { - changed = TRUE; - bzobj->d_has_network_server_iface = FALSE; - } - } - } - - return changed; -} - -static void -_dbus_managed_objects_changed_cb(GDBusConnection *connection, - const char * sender_name, - const char * arg_object_path, - const char * interface_name, - const char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMBluezManager * self = user_data; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - BzDBusObj * bzobj = NULL; - gboolean changed; - - nm_assert(nm_streq0(interface_name, DBUS_INTERFACE_OBJECT_MANAGER)); - - if (priv->get_managed_objects_cancellable) { - /* we still wait for the initial GetManagedObjects(). Ignore the event. */ - return; - } - - if (nm_streq(signal_name, "InterfacesAdded")) { - gs_unref_variant GVariant *interfaces_and_properties = NULL; - const char * object_path; - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(oa{sa{sv}})"))) - return; - - g_variant_get(parameters, "(&o@a{sa{sv}})", &object_path, &interfaces_and_properties); - - _dbus_handle_interface_added(self, object_path, interfaces_and_properties, FALSE); - return; - } - - if (nm_streq(signal_name, "InterfacesRemoved")) { - gs_free const char **interfaces = NULL; - const char * object_path; - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(oas)"))) - return; - - g_variant_get(parameters, "(&o^a&s)", &object_path, &interfaces); - - changed = _dbus_handle_interface_removed(self, object_path, &bzobj, interfaces); - if (changed) - _dbus_process_changes(self, bzobj, "dbus-iface-removed"); - return; - } -} - -static void -_dbus_properties_changed_cb(GDBusConnection *connection, - const char * sender_name, - const char * object_path, - const char * signal_interface_name, - const char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMBluezManager * self = user_data; - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - const char * interface_name; - gs_unref_variant GVariant *changed_properties = NULL; - gs_free const char ** invalidated_properties = NULL; - BzDBusObj * bzobj = NULL; - - if (priv->get_managed_objects_cancellable) { - /* we still wait for the initial GetManagedObjects(). Ignore the event. */ - return; - } - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sa{sv}as)"))) - return; - - g_variant_get(parameters, - "(&s@a{sv}^a&s)", - &interface_name, - &changed_properties, - &invalidated_properties); - - if (_dbus_handle_properties_changed(self, - object_path, - interface_name, - changed_properties, - invalidated_properties, - &bzobj)) - _dbus_process_changes(self, bzobj, "dbus-property-changed"); -} - -static void -_dbus_get_managed_objects_cb(GVariant *result, GError *error, gpointer user_data) -{ - NMBluezManager * self; - NMBluezManagerPrivate *priv; - GVariantIter iter; - const char * object_path; - GVariant * ifaces; - - if (!result && nm_utils_error_is_cancelled(error)) - return; - - self = user_data; - priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->get_managed_objects_cancellable); - - if (!result) { - _LOGT("initial GetManagedObjects() call failed: %s", error->message); - _cleanup_for_name_owner(self); - return; - } - - _LOGT("initial GetManagedObjects call succeeded"); - - g_variant_iter_init(&iter, result); - while (g_variant_iter_next(&iter, "{&o@a{sa{sv}}}", &object_path, &ifaces)) { - _nm_unused gs_unref_variant GVariant *ifaces_free = ifaces; - - _dbus_handle_interface_added(self, object_path, ifaces, TRUE); - } -} - -/*****************************************************************************/ - -static void -_cleanup_for_name_owner(NMBluezManager *self) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - gboolean emit_device_availability_changed = FALSE; - GHashTableIter iter; - BzDBusObj * bzobj; - gboolean first = TRUE; - - nm_clear_g_cancellable(&priv->get_managed_objects_cancellable); - - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->managed_objects_changed_id); - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->properties_changed_id); - - nm_clear_g_free(&priv->name_owner); - - g_hash_table_iter_init(&iter, priv->bzobjs); - while (g_hash_table_iter_next(&iter, (gpointer *) &bzobj, NULL)) { - if (first) { - first = FALSE; - _LOGT("drop all objects form D-Bus cache..."); - } - _dbus_handle_interface_removed(self, - bzobj->object_path, - &bzobj, - ALL_RELEVANT_INTERFACE_NAMES); - nm_c_list_move_tail(&priv->process_change_lst_head, &bzobj->process_change_lst); - } - _process_change_idle_all(self, &emit_device_availability_changed); - nm_assert(g_hash_table_size(priv->bzobjs) == 0); - - if (emit_device_availability_changed) - nm_manager_notify_device_availability_maybe_changed(priv->manager); -} - -static void -name_owner_changed(NMBluezManager *self, const char *owner) -{ - _nm_unused gs_unref_object NMBluezManager *self_keep_alive = g_object_ref(self); - NMBluezManagerPrivate * priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - owner = nm_str_not_empty(owner); - - if (!owner) - _LOGT("D-Bus name for bluez has no owner"); - else - _LOGT("D-Bus name for bluez has owner %s", owner); - - nm_clear_g_cancellable(&priv->name_owner_get_cancellable); - - if (nm_streq0(priv->name_owner, owner)) - return; - - _cleanup_for_name_owner(self); - - if (!owner) - return; - - priv->name_owner = g_strdup(owner); - - priv->get_managed_objects_cancellable = g_cancellable_new(); - - priv->managed_objects_changed_id = - nm_dbus_connection_signal_subscribe_object_manager(priv->dbus_connection, - priv->name_owner, - NM_BLUEZ_MANAGER_PATH, - NULL, - _dbus_managed_objects_changed_cb, - self, - NULL); - - priv->properties_changed_id = - nm_dbus_connection_signal_subscribe_properties_changed(priv->dbus_connection, - priv->name_owner, - NULL, - NULL, - _dbus_properties_changed_cb, - self, - NULL); - - nm_dbus_connection_call_get_managed_objects(priv->dbus_connection, - priv->name_owner, - NM_BLUEZ_MANAGER_PATH, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 20000, - priv->get_managed_objects_cancellable, - _dbus_get_managed_objects_cb, - self); -} - -static void -name_owner_changed_cb(GDBusConnection *connection, - const char * sender_name, - const char * object_path, - const char * interface_name, - const char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMBluezManager *self = user_data; - const char * new_owner; - - if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)"))) - return; - - g_variant_get(parameters, "(&s&s&s)", NULL, NULL, &new_owner); - - name_owner_changed(self, new_owner); -} - -static void -name_owner_get_cb(const char *name_owner, GError *error, gpointer user_data) -{ - if (name_owner || !g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - name_owner_changed(user_data, name_owner); -} - -/*****************************************************************************/ - -static void -_cleanup_all(NMBluezManager *self) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - priv->settings_registered = FALSE; - - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_added, self); - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_updated, self); - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_removed, self); - - g_hash_table_remove_all(priv->conn_data_elems); - g_hash_table_remove_all(priv->conn_data_heads); - - _cleanup_for_name_owner(self); - - nm_clear_g_cancellable(&priv->name_owner_get_cancellable); - - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); -} - -static void -start(NMDeviceFactory *factory) -{ - NMBluezManager * self; - NMBluezManagerPrivate * priv; - NMSettingsConnection *const *sett_conns; - guint n_sett_conns; - guint i; - - g_return_if_fail(NM_IS_BLUEZ_MANAGER(factory)); - - self = NM_BLUEZ_MANAGER(factory); - priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - _cleanup_all(self); - - if (!priv->dbus_connection) { - _LOGI("no D-Bus connection available"); - return; - } - - g_signal_connect(priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_ADDED, - G_CALLBACK(cp_connection_added), - self); - g_signal_connect(priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, - G_CALLBACK(cp_connection_updated), - self); - g_signal_connect(priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK(cp_connection_removed), - self); - - priv->settings_registered = TRUE; - - sett_conns = nm_settings_get_connections(priv->settings, &n_sett_conns); - for (i = 0; i < n_sett_conns; i++) - _conn_track_update(self, sett_conns[i], TRUE, NULL, NULL, NULL); - - priv->name_owner_changed_id = - nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection, - NM_BLUEZ_SERVICE, - name_owner_changed_cb, - self, - NULL); - - priv->name_owner_get_cancellable = g_cancellable_new(); - - nm_dbus_connection_call_get_name_owner(priv->dbus_connection, - NM_BLUEZ_SERVICE, - 10000, - priv->name_owner_get_cancellable, - name_owner_get_cb, - self); -} - -/*****************************************************************************/ - -static void -_connect_returned(NMBluezManager * self, - BzDBusObj * bzobj, - NMBluetoothCapabilities bt_type, - const char * device_name, - NMBluez5DunContext * dun_context, - GError * error) -{ - char sbuf_cap[100]; - - if (error) { - nm_assert(!device_name); - nm_assert(!dun_context); - - _LOGI("%s [%s]: connect failed: %s", - nm_bluetooth_capability_to_string(bzobj->x_device_connect_bt_type, - sbuf_cap, - sizeof(sbuf_cap)), - bzobj->object_path, - error->message); - - _device_connect_req_data_complete(g_steal_pointer(&bzobj->x_device.c_req_data), - self, - NULL, - error); - _connect_disconnect(self, bzobj, "cleanup after connect failure"); - return; - } - - nm_assert(bzobj->x_device_connect_bt_type == bt_type); - nm_assert(device_name); - nm_assert((bt_type == NM_BT_CAPABILITY_DUN) == (!!dun_context)); - nm_assert(bzobj->x_device.c_req_data); - - g_clear_object(&bzobj->x_device.c_req_data->int_cancellable); - - bzobj->x_device.connect_dun_context = dun_context; - - _LOGD("%s [%s]: connect successful to device %s", - nm_bluetooth_capability_to_string(bzobj->x_device_connect_bt_type, - sbuf_cap, - sizeof(sbuf_cap)), - bzobj->object_path, - device_name); - - /* we already have another over-all timer running. But after we connected the device, - * we still need to wait for bluez to acknowledge the connected state (via D-Bus, for NAP). - * For DUN profiles we likely are already fully connected by now. - * - * Anyway, schedule another timeout that is possibly shorter than the overall, original - * timeout. Now this should go down fast. */ - bzobj->x_device.c_req_data->timeout_wait_connect_id = - g_timeout_add(5000, _connect_timeout_wait_connected_cb, bzobj), - bzobj->x_device.c_req_data->device_name = g_strdup(device_name); - - if (_bzobjs_device_is_usable(bzobj, NULL, NULL) && _bzobjs_device_is_connected(bzobj)) { - /* We are now connected. Schedule the task that completes the state. */ - _process_change_idle_schedule(self, bzobj); - } -} - -#if WITH_BLUEZ5_DUN -static void -_connect_dun_notify_tty_hangup_cb(NMBluez5DunContext *context, gpointer user_data) -{ - BzDBusObj *bzobj = user_data; - - _connect_disconnect(bzobj->self, bzobj, "DUN connection hung up"); -} - -static void -_connect_dun_step2_cb(NMBluez5DunContext *context, - const char * rfcomm_dev, - GError * error, - gpointer user_data) -{ - BzDBusObj *bzobj; - - if (nm_utils_error_is_cancelled(error)) - return; - - bzobj = user_data; - - if (rfcomm_dev) { - /* We want to early notify about the rfcomm path. That is because we might still delay - * to signal full activation longer (asynchronously). But the earliest time the callback - * is invoked with the rfcomm path, we just created the device synchronously. - * - * By already notifying the caller about the path early, it avoids a race where ModemManager - * would find the modem before the bluetooth code considers the profile fully activated. */ - - nm_assert(!error); - nm_assert(bzobj->x_device.c_req_data); - - if (!g_cancellable_is_cancelled(bzobj->x_device.c_req_data->ext_cancellable)) - bzobj->x_device.c_req_data->callback(bzobj->self, - FALSE, - rfcomm_dev, - NULL, - bzobj->x_device.c_req_data->callback_user_data); - - if (!context) { - /* No context set. This means, we just got notified about the rfcomm path and need to wait - * longer, for the next callback. */ - return; - } - } - - _connect_returned(bzobj->self, bzobj, NM_BT_CAPABILITY_DUN, rfcomm_dev, context, error); -} - -static void -_connect_dun_step1_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - BzDBusObj * bzobj_adapter; - BzDBusObj * bzobj; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source_object), res, &error); - - if (!ret && nm_utils_error_is_cancelled(error)) - return; - - bzobj = user_data; - - if (error) { - _LOGT("DUN: [%s]: bluetooth device connect failed: %s", bzobj->object_path, error->message); - /* we actually ignore this error. Let's try, maybe we still can connect via DUN. */ - g_clear_error(&error); - } else - _LOGT("DUN: [%s]: bluetooth device connected successfully", bzobj->object_path); - - if (!_bzobjs_device_is_usable(bzobj, &bzobj_adapter, NULL)) { - nm_utils_error_set(&error, - NM_UTILS_ERROR_UNKNOWN, - "device %s is not usable for DUN after connect", - bzobj->object_path); - _connect_returned(bzobj->self, bzobj, NM_BT_CAPABILITY_DUN, NULL, NULL, error); - return; - } - - if (!nm_bluez5_dun_connect(bzobj_adapter->d_adapter.address, - bzobj->d_device.address, - bzobj->x_device.c_req_data->int_cancellable, - _connect_dun_step2_cb, - bzobj, - _connect_dun_notify_tty_hangup_cb, - bzobj, - &error)) { - _connect_returned(bzobj->self, bzobj, NM_BT_CAPABILITY_DUN, NULL, NULL, error); - return; - } -} -#endif - -static void -_connect_nap_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - gs_unref_variant GVariant *ret = NULL; - const char * network_iface_name = NULL; - gs_free_error GError *error = NULL; - BzDBusObj * bzobj; - - ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source_object), res, &error); - - if (!ret && nm_utils_error_is_cancelled(error)) - return; - - if (ret) - g_variant_get(ret, "(&s)", &network_iface_name); - - bzobj = user_data; - - _connect_returned(bzobj->self, bzobj, NM_BT_CAPABILITY_NAP, network_iface_name, NULL, error); -} - -static void -_connect_cancelled_cb(GCancellable *cancellable, BzDBusObj *bzobj) -{ - _connect_disconnect(bzobj->self, bzobj, "connect cancelled"); -} - -static gboolean -_connect_timeout_wait_connected_cb(gpointer user_data) -{ - BzDBusObj *bzobj = user_data; - - bzobj->x_device.c_req_data->timeout_wait_connect_id = 0; - _connect_disconnect(bzobj->self, bzobj, "timeout waiting for connected"); - return G_SOURCE_REMOVE; -} - -static gboolean -_connect_timeout_cb(gpointer user_data) -{ - BzDBusObj *bzobj = user_data; - - bzobj->x_device.c_req_data->timeout_id = 0; - _connect_disconnect(bzobj->self, bzobj, "timeout connecting"); - return G_SOURCE_REMOVE; -} - -static void -_connect_disconnect(NMBluezManager *self, BzDBusObj *bzobj, const char *reason) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - DeviceConnectReqData * c_req_data; - char sbuf_cap[100]; - gboolean bt_type; - - if (bzobj->x_device_connect_bt_type == NM_BT_CAPABILITY_NONE) { - nm_assert(!bzobj->x_device.c_req_data); - return; - } - - bt_type = bzobj->x_device_connect_bt_type; - nm_assert(NM_IN_SET(bt_type, NM_BT_CAPABILITY_DUN, NM_BT_CAPABILITY_NAP)); - bzobj->x_device_connect_bt_type = NM_BT_CAPABILITY_NONE; - - c_req_data = g_steal_pointer(&bzobj->x_device.c_req_data); - - _LOGD("%s [%s]: disconnect due to %s", - nm_bluetooth_capability_to_string(bt_type, sbuf_cap, sizeof(sbuf_cap)), - bzobj->object_path, - reason); - - if (c_req_data) - nm_clear_g_cancellable(&c_req_data->int_cancellable); - - if (bt_type == NM_BT_CAPABILITY_DUN) { - /* For DUN devices, we also called org.bluez.Device1.Connect() (because in order - * for nm_bluez5_dun_connect() to succeed, we need to be already connected *why??). - * - * But upon disconnect we don't call Disconnect() because we don't know whether somebody - * else also uses the bluetooth device for other purposes. During disconnect we only - * terminate the DUN connection, but don't disconnect entirely. I think that's the - * best we can do. */ -#if WITH_BLUEZ5_DUN - nm_clear_pointer(&bzobj->x_device.connect_dun_context, nm_bluez5_dun_disconnect); -#else - nm_assert_not_reached(); -#endif - } else { - if (priv->name_owner) { - gs_unref_object GCancellable *cancellable = NULL; - - cancellable = g_cancellable_new(); - - nm_shutdown_wait_obj_register_cancellable_full( - cancellable, - g_strdup_printf("bt-disconnect-nap[%s]", bzobj->object_path), - TRUE); - - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_NETWORK_INTERFACE, - "Disconnect", - g_variant_new("()"), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - -1, - cancellable, - _dbus_call_complete_cb_nop, - NULL); - } - } - - if (c_req_data) { - gs_free_error GError *error = NULL; - - nm_utils_error_set(&error, NM_UTILS_ERROR_UNKNOWN, "connect aborted due to %s", reason); - _device_connect_req_data_complete(c_req_data, self, NULL, error); - } -} - -gboolean -nm_bluez_manager_connect(NMBluezManager * self, - const char * object_path, - NMBluetoothCapabilities connection_bt_type, - int timeout_msec, - GCancellable * cancellable, - NMBluezManagerConnectCb callback, - gpointer callback_user_data, - GError ** error) -{ - gs_unref_object GCancellable *int_cancellable = NULL; - DeviceConnectReqData * c_req_data; - NMBluezManagerPrivate * priv; - BzDBusObj * bzobj; - char sbuf_cap[100]; - - g_return_val_if_fail(NM_IS_BLUEZ_MANAGER(self), FALSE); - g_return_val_if_fail(NM_IN_SET(connection_bt_type, NM_BT_CAPABILITY_DUN, NM_BT_CAPABILITY_NAP), - FALSE); - g_return_val_if_fail(callback, FALSE); - - nm_assert(timeout_msec > 0); - - priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - bzobj = _bzobjs_get(self, object_path); - - if (!bzobj) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "device %s does not exist", object_path); - return FALSE; - } - - if (!_bzobjs_device_is_usable(bzobj, NULL, NULL)) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "device %s is not usable", object_path); - return FALSE; - } - - if (!NM_FLAGS_ALL(bzobj->d_device_capabilities, connection_bt_type)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "device %s has not the required capabilities", - object_path); - return FALSE; - } - -#if !WITH_BLUEZ5_DUN - if (connection_bt_type == NM_BT_CAPABILITY_DUN) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "DUN is not supported"); - return FALSE; - } -#endif - - _connect_disconnect(self, bzobj, "new activation"); - - _LOGD("%s [%s]: connecting...", - nm_bluetooth_capability_to_string(connection_bt_type, sbuf_cap, sizeof(sbuf_cap)), - bzobj->object_path); - - int_cancellable = g_cancellable_new(); - -#if WITH_BLUEZ5_DUN - if (connection_bt_type == NM_BT_CAPABILITY_DUN) { - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_DEVICE_INTERFACE, - "Connect", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - timeout_msec, - int_cancellable, - _connect_dun_step1_cb, - bzobj); - } else -#endif - { - nm_assert(connection_bt_type == NM_BT_CAPABILITY_NAP); - g_dbus_connection_call(priv->dbus_connection, - priv->name_owner, - bzobj->object_path, - NM_BLUEZ5_NETWORK_INTERFACE, - "Connect", - g_variant_new("(s)", BLUETOOTH_CONNECT_NAP), - G_VARIANT_TYPE("(s)"), - G_DBUS_CALL_FLAGS_NO_AUTO_START, - timeout_msec, - int_cancellable, - _connect_nap_cb, - bzobj); - } - - c_req_data = g_slice_new(DeviceConnectReqData); - *c_req_data = (DeviceConnectReqData){ - .int_cancellable = g_steal_pointer(&int_cancellable), - .ext_cancellable = g_object_ref(cancellable), - .callback = callback, - .callback_user_data = callback_user_data, - .ext_cancelled_id = - g_signal_connect(cancellable, "cancelled", G_CALLBACK(_connect_cancelled_cb), bzobj), - .timeout_id = g_timeout_add(timeout_msec, _connect_timeout_cb, bzobj), - }; - - bzobj->x_device_connect_bt_type = connection_bt_type; - bzobj->x_device.c_req_data = c_req_data; - - return TRUE; -} - -void -nm_bluez_manager_disconnect(NMBluezManager *self, const char *object_path) -{ - BzDBusObj *bzobj; - - g_return_if_fail(NM_IS_BLUEZ_MANAGER(self)); - g_return_if_fail(object_path); - - bzobj = _bzobjs_get(self, object_path); - if (!bzobj) - return; - - _connect_disconnect(self, bzobj, "disconnected by user"); -} - -/*****************************************************************************/ - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - *out_ignore = TRUE; - g_return_val_if_fail(plink->type == NM_LINK_TYPE_BNEP, NULL); - return NULL; -} - -static gboolean -match_connection(NMDeviceFactory *factory, NMConnection *connection) -{ - const char *type = nm_connection_get_connection_type(connection); - - nm_assert(nm_streq(type, NM_SETTING_BLUETOOTH_SETTING_NAME)); - - if (_nm_connection_get_setting_bluetooth_for_nap(connection)) - return FALSE; /* handled by the bridge factory */ - - return TRUE; -} - -/*****************************************************************************/ - -static void -nm_bluez_manager_init(NMBluezManager *self) -{ - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - priv->vtable_network_server = (NMBtVTableNetworkServer){ - .is_available = _network_server_vt_is_available, - .register_bridge = _network_server_vt_register_bridge, - .unregister_bridge = _network_server_vt_unregister_bridge, - }; - - c_list_init(&priv->network_server_lst_head); - c_list_init(&priv->process_change_lst_head); - - priv->conn_data_heads = - g_hash_table_new_full(_conn_data_head_hash, _conn_data_head_equal, g_free, NULL); - priv->conn_data_elems = g_hash_table_new_full(nm_pdirect_hash, - nm_pdirect_equal, - nm_g_slice_free_fcn(ConnDataElem), - NULL); - - priv->bzobjs = g_hash_table_new_full(nm_pstr_hash, - nm_pstr_equal, - (GDestroyNotify) _bz_dbus_obj_free, - NULL); - - priv->manager = g_object_ref(NM_MANAGER_GET); - priv->settings = g_object_ref(NM_SETTINGS_GET); - priv->dbus_connection = nm_g_object_ref(NM_MAIN_DBUS_CONNECTION_GET); - - g_atomic_pointer_compare_and_exchange(&nm_bt_vtable_network_server, - NULL, - &priv->vtable_network_server); -} - -static void -dispose(GObject *object) -{ - NMBluezManager * self = NM_BLUEZ_MANAGER(object); - NMBluezManagerPrivate *priv = NM_BLUEZ_MANAGER_GET_PRIVATE(self); - - /* FIXME(shutdown): we need a nm_device_factory_stop() hook to first unregister all - * BzDBusObj instances and do necessary cleanup actions (like disconnecting devices - * or deleting panu_connection). */ - - nm_assert(c_list_is_empty(&priv->network_server_lst_head)); - nm_assert(c_list_is_empty(&priv->process_change_lst_head)); - nm_assert(priv->process_change_idle_id == 0); - - g_atomic_pointer_compare_and_exchange(&nm_bt_vtable_network_server, - &priv->vtable_network_server, - NULL); - - _cleanup_all(self); - - G_OBJECT_CLASS(nm_bluez_manager_parent_class)->dispose(object); - - g_clear_object(&priv->settings); - g_clear_object(&priv->manager); - g_clear_object(&priv->dbus_connection); - - nm_clear_pointer(&priv->bzobjs, g_hash_table_destroy); -} - -static void -nm_bluez_manager_class_init(NMBluezManagerClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - object_class->dispose = dispose; - - factory_class->get_supported_types = get_supported_types; - factory_class->create_device = create_device; - factory_class->match_connection = match_connection; - factory_class->start = start; -} diff --git a/src/devices/bluetooth/nm-bluez-manager.h b/src/devices/bluetooth/nm-bluez-manager.h deleted file mode 100644 index 40a2fcdd..00000000 --- a/src/devices/bluetooth/nm-bluez-manager.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2009 - 2019 Red Hat, Inc. - */ - -#ifndef __NM_BLUEZ_MANAGER_H__ -#define __NM_BLUEZ_MANAGER_H__ - -#define NM_TYPE_BLUEZ_MANAGER (nm_bluez_manager_get_type()) -#define NM_BLUEZ_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManager)) -#define NM_BLUEZ_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass)) -#define NM_IS_BLUEZ_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_BLUEZ_MANAGER)) -#define NM_IS_BLUEZ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_BLUEZ_MANAGER)) -#define NM_BLUEZ_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_BLUEZ_MANAGER, NMBluezManagerClass)) - -typedef struct _NMBluezManager NMBluezManager; -typedef struct _NMBluezManagerClass NMBluezManagerClass; - -GType nm_bluez_manager_get_type(void); - -typedef void (*NMBluezManagerConnectCb)( - NMBluezManager *self, - gboolean is_completed /* or else is early notification with DUN path */, - const char * device_name, - GError * error, - gpointer user_data); - -gboolean nm_bluez_manager_connect(NMBluezManager * self, - const char * object_path, - NMBluetoothCapabilities connection_bt_type, - int timeout_msec, - GCancellable * cancellable, - NMBluezManagerConnectCb callback, - gpointer callback_user_data, - GError ** error); - -void nm_bluez_manager_disconnect(NMBluezManager *self, const char *object_path); - -#endif /* __NM_BLUEZ_MANAGER_H__ */ diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c deleted file mode 100644 index 422c8516..00000000 --- a/src/devices/bluetooth/nm-bluez5-dun.c +++ /dev/null @@ -1,857 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <sys/socket.h> -#include <bluetooth/sdp.h> -#include <bluetooth/sdp_lib.h> -#include <bluetooth/rfcomm.h> -#include <net/ethernet.h> -#include <sys/ioctl.h> -#include <unistd.h> -#include <fcntl.h> - -#include "nm-bluez5-dun.h" -#include "nm-bt-error.h" -#include "NetworkManagerUtils.h" - -#define RFCOMM_FMT "/dev/rfcomm%d" - -/*****************************************************************************/ - -typedef struct { - GCancellable * cancellable; - NMBluez5DunConnectCb callback; - gpointer callback_user_data; - - sdp_session_t *sdp_session; - - GError *rfcomm_sdp_search_error; - - GSource *source; - - gint64 connect_open_tty_started_at; - - gulong cancelled_id; - - guint8 sdp_session_try_count; -} ConnectData; - -struct _NMBluez5DunContext { - const char *dst_str; - - ConnectData *cdat; - - NMBluez5DunNotifyTtyHangupCb notify_tty_hangup_cb; - gpointer notify_tty_hangup_user_data; - - char *rfcomm_tty_path; - - GSource *rfcomm_tty_poll_source; - - int rfcomm_sock_fd; - int rfcomm_tty_fd; - int rfcomm_tty_no; - int rfcomm_channel; - - bdaddr_t src; - bdaddr_t dst; - - char src_str[]; -}; - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_BT -#define _NMLOG_PREFIX_NAME "bluez" -#define _NMLOG(level, context, ...) \ - G_STMT_START \ - { \ - if (nm_logging_enabled((level), (_NMLOG_DOMAIN))) { \ - const NMBluez5DunContext *const _context = (context); \ - \ - _nm_log((level), \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - NULL, \ - "%s: DUN[%s] " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - _context->src_str _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static void _context_invoke_callback_success(NMBluez5DunContext *context); -static void _context_invoke_callback_fail_and_free(NMBluez5DunContext *context, GError *error); -static void _context_free(NMBluez5DunContext *context); -static int _connect_open_tty(NMBluez5DunContext *context); -static gboolean _connect_sdp_session_start(NMBluez5DunContext *context, GError **error); - -/*****************************************************************************/ - -NM_AUTO_DEFINE_FCN0(NMBluez5DunContext *, _nm_auto_free_context, _context_free); -#define nm_auto_free_context nm_auto(_nm_auto_free_context) - -/*****************************************************************************/ - -const char * -nm_bluez5_dun_context_get_adapter(const NMBluez5DunContext *context) -{ - return context->src_str; -} - -const char * -nm_bluez5_dun_context_get_remote(const NMBluez5DunContext *context) -{ - return context->dst_str; -} - -const char * -nm_bluez5_dun_context_get_rfcomm_dev(const NMBluez5DunContext *context) -{ - return context->rfcomm_tty_path; -} - -/*****************************************************************************/ - -static gboolean -_rfcomm_tty_poll_cb(int fd, GIOCondition condition, gpointer user_data) -{ - NMBluez5DunContext *context = user_data; - - _LOGD(context, - "receive %s%s%s signal on rfcomm file descriptor", - NM_FLAGS_HAS(condition, G_IO_ERR) ? "ERR" : "", - NM_FLAGS_ALL(condition, G_IO_HUP | G_IO_ERR) ? "," : "", - NM_FLAGS_HAS(condition, G_IO_HUP) ? "HUP" : ""); - - nm_clear_g_source_inst(&context->rfcomm_tty_poll_source); - context->notify_tty_hangup_cb(context, context->notify_tty_hangup_user_data); - return G_SOURCE_REMOVE; -} - -static gboolean -_connect_open_tty_retry_cb(gpointer user_data) -{ - NMBluez5DunContext *context = user_data; - int r; - - r = _connect_open_tty(context); - if (r >= 0) - return G_SOURCE_REMOVE; - - if (nm_utils_get_monotonic_timestamp_nsec() - > context->cdat->connect_open_tty_started_at + (30 * 100 * NM_UTILS_NSEC_PER_MSEC)) { - gs_free_error GError *error = NULL; - - nm_clear_g_source_inst(&context->cdat->source); - g_set_error(&error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "give up waiting to open %s device: %s (%d)", - context->rfcomm_tty_path, - nm_strerror_native(r), - -r); - _context_invoke_callback_fail_and_free(context, error); - return G_SOURCE_REMOVE; - } - - return G_SOURCE_CONTINUE; -} - -static int -_connect_open_tty(NMBluez5DunContext *context) -{ - int fd; - int errsv; - - fd = open(context->rfcomm_tty_path, O_RDONLY | O_NOCTTY | O_CLOEXEC); - if (fd < 0) { - errsv = NM_ERRNO_NATIVE(errno); - - if (!context->cdat->source) { - _LOGD(context, - "failed opening tty " RFCOMM_FMT ": %s (%d). Start polling...", - context->rfcomm_tty_no, - nm_strerror_native(errsv), - errsv); - context->cdat->connect_open_tty_started_at = nm_utils_get_monotonic_timestamp_nsec(); - context->cdat->source = nm_g_timeout_source_new(100, - G_PRIORITY_DEFAULT, - _connect_open_tty_retry_cb, - context, - NULL); - g_source_attach(context->cdat->source, NULL); - } - return -errsv; - } - - context->rfcomm_tty_fd = fd; - - context->rfcomm_tty_poll_source = nm_g_unix_fd_source_new(context->rfcomm_tty_fd, - G_IO_ERR | G_IO_HUP, - G_PRIORITY_DEFAULT, - _rfcomm_tty_poll_cb, - context, - NULL); - g_source_attach(context->rfcomm_tty_poll_source, NULL); - - _context_invoke_callback_success(context); - return 0; -} - -static void -_connect_create_rfcomm(NMBluez5DunContext *context) -{ - gs_free_error GError *error = NULL; - struct rfcomm_dev_req req; - int devid; - int errsv; - int r; - - _LOGD(context, "connected to %s on channel %d", context->dst_str, context->rfcomm_channel); - - /* Create an RFCOMM kernel device for the DUN channel */ - memset(&req, 0, sizeof(req)); - req.dev_id = -1; - req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP); - req.channel = context->rfcomm_channel; - memcpy(&req.src, &context->src, ETH_ALEN); - memcpy(&req.dst, &context->dst, ETH_ALEN); - devid = ioctl(context->rfcomm_sock_fd, RFCOMMCREATEDEV, &req); - if (devid < 0) { - errsv = NM_ERRNO_NATIVE(errno); - if (errsv == EBADFD) { - /* hm. We use a non-blocking socket to connect. Above getsockopt(SOL_SOCKET,SO_ERROR) indicated - * success, but still now we fail with EBADFD. I think that is a bug and we should get the - * failure during connect(). - * - * Anyway, craft a less confusing error message than - * "failed to create rfcomm device: File descriptor in bad state (77)". */ - g_set_error(&error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "unknown failure to connect to DUN device"); - } else { - g_set_error(&error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "failed to create rfcomm device: %s (%d)", - nm_strerror_native(errsv), - errsv); - } - _context_invoke_callback_fail_and_free(context, error); - return; - } - - context->rfcomm_tty_no = devid; - context->rfcomm_tty_path = g_strdup_printf(RFCOMM_FMT, devid); - - r = _connect_open_tty(context); - if (r < 0) { - /* we created the rfcomm device, but cannot yet open it. That means, we are - * not yet fully connected. However, we notify the caller about "what we learned - * so far". Note that this happens synchronously. - * - * The purpose is that once we proceed synchronously, modem-manager races with - * the detection of the modem. We want to notify the caller first about the - * device name. */ - context->cdat->callback(NULL, - context->rfcomm_tty_path, - NULL, - context->cdat->callback_user_data); - } -} - -static gboolean -_connect_socket_connect_cb(int fd, GIOCondition condition, gpointer user_data) -{ - NMBluez5DunContext *context = user_data; - gs_free_error GError *error = NULL; - int errsv = 0; - socklen_t slen = sizeof(errsv); - int r; - - nm_clear_g_source_inst(&context->cdat->source); - - r = getsockopt(context->rfcomm_sock_fd, SOL_SOCKET, SO_ERROR, &errsv, &slen); - - if (r < 0) { - errsv = errno; - g_set_error(&error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "failed to complete connecting RFCOMM socket: %s (%d)", - nm_strerror_native(errsv), - errsv); - _context_invoke_callback_fail_and_free(context, error); - return G_SOURCE_REMOVE; - } - - if (errsv != 0) { - g_set_error(&error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "failed to connect RFCOMM socket: %s (%d)", - nm_strerror_native(errsv), - errsv); - _context_invoke_callback_fail_and_free(context, error); - return G_SOURCE_REMOVE; - } - - _connect_create_rfcomm(context); - return G_SOURCE_REMOVE; -} - -static void -_connect_socket_connect(NMBluez5DunContext *context) -{ - gs_free_error GError *error = NULL; - struct sockaddr_rc sa; - int errsv; - - context->rfcomm_sock_fd = - socket(AF_BLUETOOTH, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, BTPROTO_RFCOMM); - if (context->rfcomm_sock_fd < 0) { - errsv = errno; - g_set_error(&error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "failed to create RFCOMM socket: %s (%d)", - nm_strerror_native(errsv), - errsv); - _context_invoke_callback_fail_and_free(context, error); - return; - } - - /* Connect to the remote device */ - memset(&sa, 0, sizeof(sa)); - sa.rc_family = AF_BLUETOOTH; - sa.rc_channel = 0; - memcpy(&sa.rc_bdaddr, &context->src, ETH_ALEN); - if (bind(context->rfcomm_sock_fd, (struct sockaddr *) &sa, sizeof(sa)) != 0) { - errsv = errno; - g_set_error(&error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "failed to bind socket: %s (%d)", - nm_strerror_native(errsv), - errsv); - _context_invoke_callback_fail_and_free(context, error); - return; - } - - memset(&sa, 0, sizeof(sa)); - sa.rc_family = AF_BLUETOOTH; - sa.rc_channel = context->rfcomm_channel; - memcpy(&sa.rc_bdaddr, &context->dst, ETH_ALEN); - if (connect(context->rfcomm_sock_fd, (struct sockaddr *) &sa, sizeof(sa)) != 0) { - errsv = errno; - if (errsv != EINPROGRESS) { - g_set_error(&error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "failed to connect to remote device: %s (%d)", - nm_strerror_native(errsv), - errsv); - _context_invoke_callback_fail_and_free(context, error); - return; - } - - _LOGD(context, - "connecting to %s on channel %d...", - context->dst_str, - context->rfcomm_channel); - - context->cdat->source = nm_g_unix_fd_source_new(context->rfcomm_sock_fd, - G_IO_OUT, - G_PRIORITY_DEFAULT, - _connect_socket_connect_cb, - context, - NULL); - g_source_attach(context->cdat->source, NULL); - return; - } - - _connect_create_rfcomm(context); -} - -static void -_connect_sdp_search_cb(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *user_data) -{ - NMBluez5DunContext *context = user_data; - int scanned; - int seqlen = 0; - int bytesleft = size; - uint8_t dataType; - int channel = -1; - - if (context->cdat->rfcomm_sdp_search_error || context->rfcomm_channel >= 0) - return; - - _LOGD(context, "SDP search finished with type=%d status=%d", status, type); - - /* SDP response received */ - if (status || type != SDP_SVC_SEARCH_ATTR_RSP) { - g_set_error(&context->cdat->rfcomm_sdp_search_error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "did not get a Service Discovery response"); - return; - } - - scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen); - - _LOGD(context, "SDP sequence type scanned=%d length=%d", scanned, seqlen); - - scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen); - if (!scanned || !seqlen) { - /* Short read or unknown sequence type */ - g_set_error(&context->cdat->rfcomm_sdp_search_error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "improper Service Discovery response"); - return; - } - - rsp += scanned; - bytesleft -= scanned; - do { - sdp_record_t *rec; - int recsize = 0; - sdp_list_t * protos; - - rec = sdp_extract_pdu(rsp, bytesleft, &recsize); - if (!rec) - break; - - if (!recsize) { - sdp_record_free(rec); - break; - } - - if (sdp_get_access_protos(rec, &protos) == 0) { - /* Extract the DUN channel number */ - channel = sdp_get_proto_port(protos, RFCOMM_UUID); - sdp_list_free(protos, NULL); - - _LOGD(context, "SDP channel=%d", channel); - } - sdp_record_free(rec); - - scanned += recsize; - rsp += recsize; - bytesleft -= recsize; - } while (scanned < (ssize_t) size && bytesleft > 0 && channel < 0); - - if (channel == -1) { - g_set_error(&context->cdat->rfcomm_sdp_search_error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "did not receive rfcomm-channel"); - return; - } - - context->rfcomm_channel = channel; -} - -static gboolean -_connect_sdp_search_io_cb(int fd, GIOCondition condition, gpointer user_data) -{ - NMBluez5DunContext *context = user_data; - gs_free_error GError *error = NULL; - int errsv; - - if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { - _LOGD(context, "SDP search returned with invalid IO condition 0x%x", (guint) condition); - error = g_error_new(NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "Service Discovery interrupted"); - nm_clear_g_source_inst(&context->cdat->source); - _context_invoke_callback_fail_and_free(context, error); - return G_SOURCE_REMOVE; - } - - if (sdp_process(context->cdat->sdp_session) == 0) { - _LOGD(context, "SDP search still not finished"); - return G_SOURCE_CONTINUE; - } - - nm_clear_g_source_inst(&context->cdat->source); - - if (context->rfcomm_channel < 0 && !context->cdat->rfcomm_sdp_search_error) { - errsv = sdp_get_error(context->cdat->sdp_session); - _LOGD(context, "SDP search failed: %s (%d)", nm_strerror_native(errsv), errsv); - error = g_error_new(NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "Service Discovery failed with %s (%d)", - nm_strerror_native(errsv), - errsv); - _context_invoke_callback_fail_and_free(context, error); - return G_SOURCE_REMOVE; - } - - if (context->cdat->rfcomm_sdp_search_error) { - _LOGD(context, - "SDP search failed to complete: %s", - context->cdat->rfcomm_sdp_search_error->message); - _context_invoke_callback_fail_and_free(context, context->cdat->rfcomm_sdp_search_error); - return G_SOURCE_REMOVE; - } - - nm_clear_pointer(&context->cdat->sdp_session, sdp_close); - - _connect_socket_connect(context); - - return G_SOURCE_REMOVE; -} - -static gboolean -_connect_sdp_session_start_on_idle_cb(gpointer user_data) -{ - NMBluez5DunContext *context = user_data; - gs_free_error GError *error = NULL; - - nm_clear_g_source_inst(&context->cdat->source); - - _LOGD(context, "retry starting sdp-session..."); - - if (!_connect_sdp_session_start(context, &error)) - _context_invoke_callback_fail_and_free(context, error); - - return G_SOURCE_REMOVE; -} - -static gboolean -_connect_sdp_io_cb(int fd, GIOCondition condition, gpointer user_data) -{ - NMBluez5DunContext *context = user_data; - sdp_list_t * search; - sdp_list_t * attrs; - uuid_t svclass; - uint16_t attr; - int errsv; - int fd_err = 0; - int r; - socklen_t len = sizeof(fd_err); - gs_free_error GError *error = NULL; - - nm_clear_g_source_inst(&context->cdat->source); - - _LOGD(context, "sdp-session ready to connect with fd=%d", fd); - - if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &fd_err, &len) < 0) { - errsv = NM_ERRNO_NATIVE(errno); - error = g_error_new(NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "error for getsockopt on Service Discovery socket: %s (%d)", - nm_strerror_native(errsv), - errsv); - goto done; - } - - if (fd_err != 0) { - errsv = nm_errno_native(fd_err); - - if (NM_IN_SET(errsv, ECONNREFUSED, EHOSTDOWN) - && --context->cdat->sdp_session_try_count > 0) { - /* *sigh* */ - _LOGD(context, - "sdp-session failed with %s (%d). Retry in a bit", - nm_strerror_native(errsv), - errsv); - nm_clear_g_source_inst(&context->cdat->source); - context->cdat->source = nm_g_timeout_source_new(1000, - G_PRIORITY_DEFAULT, - _connect_sdp_session_start_on_idle_cb, - context, - NULL); - g_source_attach(context->cdat->source, NULL); - return G_SOURCE_REMOVE; - } - - error = g_error_new(NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "error on Service Discovery socket: %s (%d)", - nm_strerror_native(errsv), - errsv); - goto done; - } - - if (sdp_set_notify(context->cdat->sdp_session, _connect_sdp_search_cb, context) < 0) { - /* Should not be reached, only can fail if we passed bad sdp_session. */ - error = g_error_new(NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "could not set Service Discovery notification"); - goto done; - } - - sdp_uuid16_create(&svclass, DIALUP_NET_SVCLASS_ID); - search = sdp_list_append(NULL, &svclass); - attr = SDP_ATTR_PROTO_DESC_LIST; - attrs = sdp_list_append(NULL, &attr); - - r = sdp_service_search_attr_async(context->cdat->sdp_session, - search, - SDP_ATTR_REQ_INDIVIDUAL, - attrs); - - sdp_list_free(attrs, NULL); - sdp_list_free(search, NULL); - - if (r < 0) { - errsv = nm_errno_native(sdp_get_error(context->cdat->sdp_session)); - error = g_error_new(NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "error starting Service Discovery: %s (%d)", - nm_strerror_native(errsv), - errsv); - goto done; - } - - /* Set callback responsible for update the internal SDP transaction */ - context->cdat->source = nm_g_unix_fd_source_new(fd, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - G_PRIORITY_DEFAULT, - _connect_sdp_search_io_cb, - context, - NULL); - g_source_attach(context->cdat->source, NULL); - -done: - if (error) - _context_invoke_callback_fail_and_free(context, error); - return G_SOURCE_REMOVE; -} - -/*****************************************************************************/ - -static void -_connect_cancelled_cb(GCancellable *cancellable, NMBluez5DunContext *context) -{ - gs_free_error GError *error = NULL; - - if (!g_cancellable_set_error_if_cancelled(cancellable, &error)) - g_return_if_reached(); - - _context_invoke_callback_fail_and_free(context, error); -} - -static gboolean -_connect_sdp_session_start(NMBluez5DunContext *context, GError **error) -{ - nm_assert(context->cdat); - - nm_clear_g_source_inst(&context->cdat->source); - nm_clear_pointer(&context->cdat->sdp_session, sdp_close); - - context->cdat->sdp_session = sdp_connect(&context->src, &context->dst, SDP_NON_BLOCKING); - if (!context->cdat->sdp_session) { - int errsv = nm_errno_native(errno); - - g_set_error(error, - NM_BT_ERROR, - NM_BT_ERROR_DUN_CONNECT_FAILED, - "failed to connect to the SDP server: %s (%d)", - nm_strerror_native(errsv), - errsv); - return FALSE; - } - - context->cdat->source = nm_g_unix_fd_source_new(sdp_get_socket(context->cdat->sdp_session), - G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - G_PRIORITY_DEFAULT, - _connect_sdp_io_cb, - context, - NULL); - g_source_attach(context->cdat->source, NULL); - return TRUE; -} - -/*****************************************************************************/ - -gboolean -nm_bluez5_dun_connect(const char * adapter, - const char * remote, - GCancellable * cancellable, - NMBluez5DunConnectCb callback, - gpointer callback_user_data, - NMBluez5DunNotifyTtyHangupCb notify_tty_hangup_cb, - gpointer notify_tty_hangup_user_data, - GError ** error) -{ - nm_auto_free_context NMBluez5DunContext *context = NULL; - ConnectData * cdat; - gsize src_l; - gsize dst_l; - - g_return_val_if_fail(adapter, FALSE); - g_return_val_if_fail(remote, FALSE); - g_return_val_if_fail(G_IS_CANCELLABLE(cancellable), FALSE); - g_return_val_if_fail(callback, FALSE); - g_return_val_if_fail(notify_tty_hangup_cb, FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - nm_assert(!g_cancellable_is_cancelled(cancellable)); - - src_l = strlen(adapter) + 1; - dst_l = strlen(remote) + 1; - - cdat = g_slice_new(ConnectData); - *cdat = (ConnectData){ - .callback = callback, - .callback_user_data = callback_user_data, - .cancellable = g_object_ref(cancellable), - .sdp_session_try_count = 5, - }; - - context = g_malloc(sizeof(NMBluez5DunContext) + src_l + dst_l); - *context = (NMBluez5DunContext){ - .cdat = cdat, - .notify_tty_hangup_cb = notify_tty_hangup_cb, - .notify_tty_hangup_user_data = notify_tty_hangup_user_data, - .rfcomm_tty_no = -1, - .rfcomm_sock_fd = -1, - .rfcomm_tty_fd = -1, - .rfcomm_channel = -1, - }; - memcpy(&context->src_str[0], adapter, src_l); - context->dst_str = &context->src_str[src_l]; - memcpy((char *) context->dst_str, remote, dst_l); - - if (str2ba(adapter, &context->src) < 0) { - g_set_error(error, NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "invalid source"); - return FALSE; - } - - if (str2ba(remote, &context->dst) < 0) { - g_set_error(error, NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "invalid remote"); - return FALSE; - } - - context->cdat->cancelled_id = g_signal_connect(context->cdat->cancellable, - "cancelled", - G_CALLBACK(_connect_cancelled_cb), - context); - - if (!_connect_sdp_session_start(context, error)) - return FALSE; - - _LOGD(context, "starting channel number discovery for device %s", context->dst_str); - - g_steal_pointer(&context); - return TRUE; -} - -/*****************************************************************************/ - -void -nm_bluez5_dun_disconnect(NMBluez5DunContext *context) -{ - nm_assert(context); - nm_assert(!context->cdat); - - _LOGD(context, "disconnecting DUN connection"); - - _context_free(context); -} - -/*****************************************************************************/ - -static void -_context_cleanup_connect_data(NMBluez5DunContext *context) -{ - ConnectData *cdat; - - cdat = g_steal_pointer(&context->cdat); - if (!cdat) - return; - - nm_clear_g_signal_handler(cdat->cancellable, &cdat->cancelled_id); - - nm_clear_g_source_inst(&cdat->source); - - nm_clear_pointer(&cdat->sdp_session, sdp_close); - - g_clear_object(&cdat->cancellable); - - g_clear_error(&cdat->rfcomm_sdp_search_error); - - nm_g_slice_free(cdat); -} - -static void -_context_invoke_callback(NMBluez5DunContext *context, GError *error) -{ - NMBluez5DunConnectCb callback; - gpointer callback_user_data; - - nm_assert(context); - nm_assert(context->cdat); - nm_assert(context->cdat->callback); - nm_assert(error || context->rfcomm_tty_path); - - if (!error) - _LOGD(context, "connected via \"%s\"", context->rfcomm_tty_path); - else if (nm_utils_error_is_cancelled(error)) - _LOGD(context, "cancelled"); - else - _LOGD(context, "failed to connect: %s", error->message); - - callback = context->cdat->callback; - callback_user_data = context->cdat->callback_user_data; - - _context_cleanup_connect_data(context); - - callback(error ? NULL : context, - error ? NULL : context->rfcomm_tty_path, - error, - callback_user_data); -} - -static void -_context_invoke_callback_success(NMBluez5DunContext *context) -{ - nm_assert(context->rfcomm_tty_path); - _context_invoke_callback(context, NULL); -} - -static void -_context_invoke_callback_fail_and_free(NMBluez5DunContext *context, GError *error) -{ - nm_assert(error); - _context_invoke_callback(context, error); - _context_free(context); -} - -static void -_context_free(NMBluez5DunContext *context) -{ - nm_assert(context); - - _context_cleanup_connect_data(context); - - nm_clear_g_source_inst(&context->rfcomm_tty_poll_source); - - if (context->rfcomm_sock_fd >= 0) { - if (context->rfcomm_tty_no >= 0) { - struct rfcomm_dev_req req; - - memset(&req, 0, sizeof(struct rfcomm_dev_req)); - req.dev_id = context->rfcomm_tty_no; - context->rfcomm_tty_no = -1; - (void) ioctl(context->rfcomm_sock_fd, RFCOMMRELEASEDEV, &req); - } - nm_close(nm_steal_fd(&context->rfcomm_sock_fd)); - } - - if (context->rfcomm_tty_fd >= 0) - nm_close(nm_steal_fd(&context->rfcomm_tty_fd)); - nm_clear_g_free(&context->rfcomm_tty_path); - g_free(context); -} diff --git a/src/devices/bluetooth/nm-bluez5-dun.h b/src/devices/bluetooth/nm-bluez5-dun.h deleted file mode 100644 index 94fa5550..00000000 --- a/src/devices/bluetooth/nm-bluez5-dun.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#ifndef __NM_BLUEZ5_DUN_H__ -#define __NM_BLUEZ5_DUN_H__ - -typedef struct _NMBluez5DunContext NMBluez5DunContext; - -#if WITH_BLUEZ5_DUN - -typedef void (*NMBluez5DunConnectCb)(NMBluez5DunContext *context, - const char * rfcomm_dev, - GError * error, - gpointer user_data); - -typedef void (*NMBluez5DunNotifyTtyHangupCb)(NMBluez5DunContext *context, gpointer user_data); - -gboolean nm_bluez5_dun_connect(const char * adapter, - const char * remote, - GCancellable * cancellable, - NMBluez5DunConnectCb callback, - gpointer callback_user_data, - NMBluez5DunNotifyTtyHangupCb notify_tty_hangup_cb, - gpointer notify_tty_hangup_user_data, - GError ** error); - -void nm_bluez5_dun_disconnect(NMBluez5DunContext *context); - -const char *nm_bluez5_dun_context_get_adapter(const NMBluez5DunContext *context); -const char *nm_bluez5_dun_context_get_remote(const NMBluez5DunContext *context); -const char *nm_bluez5_dun_context_get_rfcomm_dev(const NMBluez5DunContext *context); - -#endif /* WITH_BLUEZ5_DUN */ - -#endif /* __NM_BLUEZ5_DUN_H__ */ diff --git a/src/devices/bluetooth/nm-bt-error.c b/src/devices/bluetooth/nm-bt-error.c deleted file mode 100644 index 8f5265f8..00000000 --- a/src/devices/bluetooth/nm-bt-error.c +++ /dev/null @@ -1,10 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-bt-error.h" - -NM_CACHED_QUARK_FCN("nm-bt-error", nm_bt_error_quark); diff --git a/src/devices/bluetooth/nm-bt-error.h b/src/devices/bluetooth/nm-bt-error.h deleted file mode 100644 index 766d2d39..00000000 --- a/src/devices/bluetooth/nm-bt-error.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#ifndef _NM_BLUEZ5_ERROR_H_ -#define _NM_BLUEZ5_ERROR_H_ - -typedef enum { - NM_BT_ERROR_CONNECTION_NOT_BT = 0, /*< nick=ConnectionNotBt >*/ - NM_BT_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ - NM_BT_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ - NM_BT_ERROR_DUN_CONNECT_FAILED, /*< nick=DunConnectFailed >*/ -} NMBtError; - -#define NM_BT_ERROR (nm_bt_error_quark()) -GQuark nm_bt_error_quark(void); - -#endif /* _NM_BT_ERROR_H_ */ diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c deleted file mode 100644 index c31961df..00000000 --- a/src/devices/bluetooth/nm-device-bt.c +++ /dev/null @@ -1,1411 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2011 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-bt.h" - -#include <stdio.h> - -#include "nm-core-internal.h" -#include "nm-bluez-common.h" -#include "nm-bluez-manager.h" -#include "devices/nm-device-private.h" -#include "ppp/nm-ppp-manager.h" -#include "nm-setting-connection.h" -#include "nm-setting-bluetooth.h" -#include "nm-setting-cdma.h" -#include "nm-setting-gsm.h" -#include "nm-setting-serial.h" -#include "nm-setting-ppp.h" -#include "NetworkManagerUtils.h" -#include "settings/nm-settings-connection.h" -#include "nm-utils.h" -#include "nm-bt-error.h" -#include "nm-ip4-config.h" -#include "platform/nm-platform.h" - -#include "devices/wwan/nm-modem-manager.h" -#include "devices/wwan/nm-modem.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceBt); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceBt, - PROP_BT_BDADDR, - PROP_BT_BZ_MGR, - PROP_BT_CAPABILITIES, - PROP_BT_DBUS_PATH, - PROP_BT_NAME, ); - -enum { - PPP_STATS, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct { - NMModemManager *modem_manager; - - NMBluezManager *bz_mgr; - - char *dbus_path; - - char *bdaddr; - char *name; - - char *connect_rfcomm_iface; - - GSList *connect_modem_candidates; - - NMModem *modem; - - GCancellable *connect_bz_cancellable; - - gulong connect_watch_link_id; - - guint connect_watch_link_idle_id; - - guint connect_wait_modem_id; - - NMBluetoothCapabilities capabilities : 6; - - NMBluetoothCapabilities connect_bt_type : 6; /* BT type of the current connection */ - - NMDeviceStageState stage1_bt_state : 3; - NMDeviceStageState stage1_modem_prepare_state : 3; - - bool is_connected : 1; - - bool mm_running : 1; - -} NMDeviceBtPrivate; - -struct _NMDeviceBt { - NMDevice parent; - NMDeviceBtPrivate _priv; -}; - -struct _NMDeviceBtClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceBt, nm_device_bt, NM_TYPE_DEVICE) - -#define NM_DEVICE_BT_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceBt, NM_IS_DEVICE_BT, NMDevice) - -/*****************************************************************************/ - -NMBluetoothCapabilities -nm_device_bt_get_capabilities(NMDeviceBt *self) -{ - g_return_val_if_fail(NM_IS_DEVICE_BT(self), NM_BT_CAPABILITY_NONE); - - return NM_DEVICE_BT_GET_PRIVATE(self)->capabilities; -} - -static NMBluetoothCapabilities -get_connection_bt_type(NMConnection *connection) -{ - NMSettingBluetooth *s_bt; - const char * bt_type; - - s_bt = nm_connection_get_setting_bluetooth(connection); - - if (s_bt) { - bt_type = nm_setting_bluetooth_get_connection_type(s_bt); - if (bt_type) { - if (nm_streq(bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN)) - return NM_BT_CAPABILITY_DUN; - else if (nm_streq(bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU)) - return NM_BT_CAPABILITY_NAP; - } - } - - return NM_BT_CAPABILITY_NONE; -} - -static gboolean -get_connection_bt_type_check(NMDeviceBt * self, - NMConnection * connection, - NMBluetoothCapabilities *out_bt_type, - GError ** error) -{ - NMBluetoothCapabilities bt_type; - - bt_type = get_connection_bt_type(connection); - - NM_SET_OUT(out_bt_type, bt_type); - - if (bt_type == NM_BT_CAPABILITY_NONE) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "profile is not a PANU/DUN bluetooth type"); - return FALSE; - } - - if (!NM_FLAGS_ALL(NM_DEVICE_BT_GET_PRIVATE(self)->capabilities, bt_type)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not support bluetooth type"); - return FALSE; - } - - return TRUE; -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_NON_KERNEL; -} - -static gboolean -can_auto_connect(NMDevice *device, NMSettingsConnection *sett_conn, char **specific_object) -{ - NMDeviceBt * self = NM_DEVICE_BT(device); - NMDeviceBtPrivate * priv = NM_DEVICE_BT_GET_PRIVATE(self); - NMBluetoothCapabilities bt_type; - - nm_assert(!specific_object || !*specific_object); - - if (!NM_DEVICE_CLASS(nm_device_bt_parent_class)->can_auto_connect(device, sett_conn, NULL)) - return FALSE; - - if (!get_connection_bt_type_check(self, - nm_settings_connection_get_connection(sett_conn), - &bt_type, - NULL)) - return FALSE; - - /* Can't auto-activate a DUN connection without ModemManager */ - if (bt_type == NM_BT_CAPABILITY_DUN && priv->mm_running == FALSE) - return FALSE; - - return TRUE; -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceBt * self = NM_DEVICE_BT(device); - NMDeviceBtPrivate * priv = NM_DEVICE_BT_GET_PRIVATE(self); - NMSettingBluetooth *s_bt; - const char * bdaddr; - - if (!NM_DEVICE_CLASS(nm_device_bt_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (!get_connection_bt_type_check(self, connection, NULL, error)) - return FALSE; - - s_bt = nm_connection_get_setting_bluetooth(connection); - - bdaddr = nm_setting_bluetooth_get_bdaddr(s_bt); - if (!bdaddr) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "profile lacks bdaddr setting"); - return FALSE; - } - if (!nm_utils_hwaddr_matches(priv->bdaddr, -1, bdaddr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "devices bdaddr setting mismatches"); - return FALSE; - } - - return TRUE; -} - -static gboolean -check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDeviceBt * self = NM_DEVICE_BT(device); - NMDeviceBtPrivate * priv = NM_DEVICE_BT_GET_PRIVATE(self); - NMBluetoothCapabilities bt_type; - - if (!get_connection_bt_type_check(self, connection, &bt_type, error)) - return FALSE; - - if (bt_type == NM_BT_CAPABILITY_DUN && !priv->mm_running) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "ModemManager missing for DUN profile"); - return FALSE; - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMDeviceBtPrivate * priv = NM_DEVICE_BT_GET_PRIVATE(device); - NMSettingBluetooth *s_bt; - const char * setting_bdaddr; - const char * ctype; - gboolean is_dun = FALSE; - gboolean is_pan = FALSE; - NMSettingGsm * s_gsm; - NMSettingCdma * s_cdma; - NMSettingSerial * s_serial; - NMSettingPpp * s_ppp; - const char * fallback_prefix = NULL, *preferred = NULL; - - s_gsm = nm_connection_get_setting_gsm(connection); - s_cdma = nm_connection_get_setting_cdma(connection); - s_serial = nm_connection_get_setting_serial(connection); - s_ppp = nm_connection_get_setting_ppp(connection); - - s_bt = nm_connection_get_setting_bluetooth(connection); - if (!s_bt) { - s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new(); - nm_connection_add_setting(connection, NM_SETTING(s_bt)); - } - - ctype = nm_setting_bluetooth_get_connection_type(s_bt); - if (ctype) { - if (!strcmp(ctype, NM_SETTING_BLUETOOTH_TYPE_DUN)) - is_dun = TRUE; - else if (!strcmp(ctype, NM_SETTING_BLUETOOTH_TYPE_PANU)) - is_pan = TRUE; - } else { - if (s_gsm || s_cdma) - is_dun = TRUE; - else if (priv->capabilities & NM_BT_CAPABILITY_NAP) - is_pan = TRUE; - } - - if (is_pan) { - /* Make sure the device supports PAN */ - if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("PAN requested, but Bluetooth device does not support NAP")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_BLUETOOTH_SETTING_NAME, - NM_SETTING_BLUETOOTH_TYPE); - return FALSE; - } - - /* PAN can't use any DUN-related settings */ - if (s_gsm || s_cdma || s_serial || s_ppp) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("PAN connections cannot specify GSM, CDMA, or serial settings")); - g_prefix_error(error, - "%s: ", - s_gsm ? NM_SETTING_GSM_SETTING_NAME - : s_cdma ? NM_SETTING_CDMA_SETTING_NAME - : s_serial ? NM_SETTING_SERIAL_SETTING_NAME - : NM_SETTING_PPP_SETTING_NAME); - return FALSE; - } - - g_object_set(G_OBJECT(s_bt), - NM_SETTING_BLUETOOTH_TYPE, - NM_SETTING_BLUETOOTH_TYPE_PANU, - NULL); - - fallback_prefix = _("PAN connection"); - } else if (is_dun) { - /* Make sure the device supports PAN */ - if (!(priv->capabilities & NM_BT_CAPABILITY_DUN)) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("DUN requested, but Bluetooth device does not support DUN")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_BLUETOOTH_SETTING_NAME, - NM_SETTING_BLUETOOTH_TYPE); - return FALSE; - } - - /* Need at least a GSM or a CDMA setting */ - if (!s_gsm && !s_cdma) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("DUN connection must include a GSM or CDMA setting")); - g_prefix_error(error, "%s: ", NM_SETTING_BLUETOOTH_SETTING_NAME); - return FALSE; - } - - g_object_set(G_OBJECT(s_bt), - NM_SETTING_BLUETOOTH_TYPE, - NM_SETTING_BLUETOOTH_TYPE_DUN, - NULL); - - if (s_gsm) { - fallback_prefix = _("GSM connection"); - } else { - fallback_prefix = _("CDMA connection"); - if (!nm_setting_cdma_get_number(s_cdma)) - g_object_set(G_OBJECT(s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL); - } - } else { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Unknown/unhandled Bluetooth connection type")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_BLUETOOTH_SETTING_NAME, - NM_SETTING_BLUETOOTH_TYPE); - return FALSE; - } - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_BLUETOOTH_SETTING_NAME, - existing_connections, - preferred, - fallback_prefix, - NULL, - NULL, - is_dun ? FALSE : TRUE); /* No IPv6 yet for DUN */ - - setting_bdaddr = nm_setting_bluetooth_get_bdaddr(s_bt); - if (setting_bdaddr) { - /* Make sure the setting BT Address (if any) matches the device's */ - if (!nm_utils_hwaddr_matches(setting_bdaddr, -1, priv->bdaddr, -1)) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_BLUETOOTH_SETTING_NAME, - NM_SETTING_BLUETOOTH_BDADDR); - return FALSE; - } - } else { - /* Lock the connection to this device by default */ - if (!nm_utils_hwaddr_matches(priv->bdaddr, -1, NULL, ETH_ALEN)) - g_object_set(G_OBJECT(s_bt), NM_SETTING_BLUETOOTH_BDADDR, priv->bdaddr, NULL); - } - - return TRUE; -} - -/*****************************************************************************/ -/* IP method PPP */ - -static void -ppp_stats(NMModem *modem, guint i_in_bytes, guint i_out_bytes, gpointer user_data) -{ - guint32 in_bytes = i_in_bytes; - guint32 out_bytes = i_out_bytes; - - g_signal_emit(NM_DEVICE_BT(user_data), - signals[PPP_STATS], - 0, - (guint) in_bytes, - (guint) out_bytes); -} - -static void -ppp_failed(NMModem *modem, guint i_reason, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceBt * self = NM_DEVICE_BT(user_data); - NMDeviceStateReason reason = i_reason; - - switch (nm_device_get_state(device)) { - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_CONFIG: - case NM_DEVICE_STATE_NEED_AUTH: - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, reason); - break; - case NM_DEVICE_STATE_IP_CONFIG: - case NM_DEVICE_STATE_IP_CHECK: - case NM_DEVICE_STATE_SECONDARIES: - case NM_DEVICE_STATE_ACTIVATED: - if (nm_device_activate_ip4_state_in_conf(device)) - nm_device_activate_schedule_ip_config_timeout(device, AF_INET); - else if (nm_device_activate_ip6_state_in_conf(device)) - nm_device_activate_schedule_ip_config_timeout(device, AF_INET6); - else if (nm_device_activate_ip4_state_done(device)) { - nm_device_ip_method_failed(device, - AF_INET, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else if (nm_device_activate_ip6_state_done(device)) { - nm_device_ip_method_failed(device, - AF_INET6, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else { - _LOGW(LOGD_MB, - "PPP failure in unexpected state %u", - (guint) nm_device_get_state(device)); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } - break; - default: - break; - } -} - -static void -modem_auth_requested(NMModem *modem, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - /* Auth requests (PIN, PAP/CHAP passwords, etc) only get handled - * during activation. - */ - if (!nm_device_is_activating(device)) - return; - - nm_device_state_changed(device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); -} - -static void -modem_auth_result(NMModem *modem, GError *error, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(device); - - g_return_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_NEED_AUTH); - - if (error) { - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_INIT; - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -modem_prepare_result(NMModem *modem, gboolean success, guint i_reason, gpointer user_data) -{ - NMDeviceBt * self = user_data; - NMDeviceBtPrivate * priv = NM_DEVICE_BT_GET_PRIVATE(self); - NMDeviceStateReason reason = i_reason; - NMDeviceState state; - - state = nm_device_get_state(NM_DEVICE(self)); - - g_return_if_fail(NM_IN_SET(state, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_NEED_AUTH)); - - nm_assert(priv->stage1_modem_prepare_state == NM_DEVICE_STAGE_STATE_PENDING); - - if (!success) { - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT) { - /* If the connect failed because the SIM PIN was wrong don't allow - * the device to be auto-activated anymore, which would risk locking - * the SIM if the incorrect PIN continues to be used. - */ - nm_device_autoconnect_blocked_set(NM_DEVICE(self), - NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN); - } - - nm_device_state_changed(NM_DEVICE(self), NM_DEVICE_STATE_FAILED, reason); - return; - } - - priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare(NM_DEVICE(self), FALSE); -} - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(device); - - if (priv->modem) - nm_modem_device_state_changed(priv->modem, new_state, old_state); - - /* Need to recheck available connections whenever MM appears or disappears, - * since the device could be both DUN and NAP capable and thus may not - * change state (which rechecks available connections) when MM comes and goes. - */ - if (priv->mm_running && NM_FLAGS_HAS(priv->capabilities, NM_BT_CAPABILITY_DUN)) - nm_device_recheck_available_connections(device); -} - -static void -modem_ip4_config_result(NMModem *modem, NMIP4Config *config, GError *error, gpointer user_data) -{ - NMDeviceBt *self = NM_DEVICE_BT(user_data); - NMDevice * device = NM_DEVICE(self); - - g_return_if_fail(nm_device_activate_ip4_state_in_conf(device) == TRUE); - - if (error) { - _LOGW(LOGD_MB | LOGD_IP4 | LOGD_BT, - "retrieving IP4 configuration failed: %s", - error->message); - nm_device_ip_method_failed(device, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - nm_device_activate_schedule_ip_config_result(device, AF_INET, NM_IP_CONFIG_CAST(config)); -} - -static void -ip_ifindex_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - if (!nm_device_is_activating(device)) - return; - - if (!nm_device_set_ip_ifindex(device, nm_modem_get_ip_ifindex(modem))) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } -} - -/*****************************************************************************/ - -static void -modem_cleanup(NMDeviceBt *self) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - if (priv->modem) { - g_signal_handlers_disconnect_matched(priv->modem, - G_SIGNAL_MATCH_DATA, - 0, - 0, - NULL, - NULL, - self); - nm_clear_pointer(&priv->modem, nm_modem_unclaim); - } -} - -static void -modem_state_cb(NMModem *modem, int new_state_i, int old_state_i, gpointer user_data) -{ - NMModemState new_state = new_state_i; - NMModemState old_state = old_state_i; - NMDevice * device = NM_DEVICE(user_data); - NMDeviceState dev_state = nm_device_get_state(device); - - if (new_state <= NM_MODEM_STATE_DISABLING && old_state > NM_MODEM_STATE_DISABLING) { - /* Will be called whenever something external to NM disables the - * modem directly through ModemManager. - */ - if (nm_device_is_activating(device) || dev_state == NM_DEVICE_STATE_ACTIVATED) { - nm_device_state_changed(device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - return; - } - } - - if (new_state < NM_MODEM_STATE_CONNECTING && old_state >= NM_MODEM_STATE_CONNECTING - && dev_state >= NM_DEVICE_STATE_NEED_AUTH && dev_state <= NM_DEVICE_STATE_ACTIVATED) { - /* Fail the device if the modem disconnects unexpectedly while the - * device is activating/activated. */ - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; - } -} - -static void -modem_removed_cb(NMModem *modem, gpointer user_data) -{ - NMDeviceBt * self = NM_DEVICE_BT(user_data); - NMDeviceState state; - - state = nm_device_get_state(NM_DEVICE(self)); - if (nm_device_is_activating(NM_DEVICE(self)) || state == NM_DEVICE_STATE_ACTIVATED) { - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return; - } - - modem_cleanup(self); -} - -static gboolean -modem_try_claim(NMDeviceBt *self, NMModem *modem) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - gs_free char * rfcomm_base_name = NULL; - NMDeviceState state; - - if (priv->modem) { - if (priv->modem == modem) - return TRUE; - return FALSE; - } - - if (nm_modem_is_claimed(modem)) - return FALSE; - - if (!priv->connect_rfcomm_iface) - return FALSE; - - rfcomm_base_name = g_path_get_basename(priv->connect_rfcomm_iface); - if (!nm_streq0(rfcomm_base_name, nm_modem_get_control_port(modem))) - return FALSE; - - /* Can only accept the modem in stage1, but since the interface matched - * what we were expecting, don't let anything else claim the modem either. - */ - state = nm_device_get_state(NM_DEVICE(self)); - if (state != NM_DEVICE_STATE_PREPARE) { - _LOGD(LOGD_BT | LOGD_MB, - "modem found but device not in correct state (%d)", - nm_device_get_state(NM_DEVICE(self))); - return FALSE; - } - - priv->modem = nm_modem_claim(modem); - priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_INIT; - - g_signal_connect(modem, NM_MODEM_PPP_STATS, G_CALLBACK(ppp_stats), self); - g_signal_connect(modem, NM_MODEM_PPP_FAILED, G_CALLBACK(ppp_failed), self); - g_signal_connect(modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK(modem_prepare_result), self); - g_signal_connect(modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK(modem_ip4_config_result), self); - g_signal_connect(modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK(modem_auth_requested), self); - g_signal_connect(modem, NM_MODEM_AUTH_RESULT, G_CALLBACK(modem_auth_result), self); - g_signal_connect(modem, NM_MODEM_STATE_CHANGED, G_CALLBACK(modem_state_cb), self); - g_signal_connect(modem, NM_MODEM_REMOVED, G_CALLBACK(modem_removed_cb), self); - g_signal_connect(modem, - "notify::" NM_MODEM_IP_IFINDEX, - G_CALLBACK(ip_ifindex_changed_cb), - self); - - _LOGD(LOGD_BT | LOGD_MB, "modem found"); - - return TRUE; -} - -static void -mm_modem_added_cb(NMModemManager *manager, NMModem *modem, gpointer user_data) -{ - NMDeviceBt * self = user_data; - NMDeviceBtPrivate *priv; - - if (!modem_try_claim(user_data, modem)) - return; - - priv = NM_DEVICE_BT_GET_PRIVATE(self); - - if (priv->stage1_bt_state == NM_DEVICE_STAGE_STATE_COMPLETED) - nm_device_activate_schedule_stage1_device_prepare(NM_DEVICE(self), FALSE); -} - -/*****************************************************************************/ - -void -_nm_device_bt_notify_set_connected(NMDeviceBt *self, gboolean connected) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - connected = !!connected; - if (priv->is_connected == connected) - return; - - priv->is_connected = connected; - - if (connected || priv->stage1_bt_state != NM_DEVICE_STAGE_STATE_COMPLETED - || nm_device_get_state(NM_DEVICE(self)) > NM_DEVICE_STATE_ACTIVATED) { - _LOGT(LOGD_BT, "set-connected: %d", connected); - return; - } - - _LOGT(LOGD_BT, "set-connected: %d (disconnecting device...)", connected); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_CARRIER); -} - -static gboolean -connect_watch_link_idle_cb(gpointer user_data) -{ - NMDeviceBt * self = user_data; - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - int ifindex; - - priv->connect_watch_link_idle_id = 0; - - if (nm_device_get_state(NM_DEVICE(self)) <= NM_DEVICE_STATE_ACTIVATED) { - ifindex = nm_device_get_ip_ifindex(NM_DEVICE(self)); - if (ifindex > 0 - && !nm_platform_link_get(nm_device_get_platform(NM_DEVICE(self)), ifindex)) { - _LOGT(LOGD_BT, "device disappeared"); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - } - } - - return G_SOURCE_REMOVE; -} - -static void -connect_watch_link_cb(NMPlatform * platform, - int obj_type_i, - int ifindex, - NMPlatformLink *info, - int change_type_i, - NMDevice * self) -{ - const NMPlatformSignalChangeType change_type = change_type_i; - NMDeviceBtPrivate * priv; - - /* bluez doesn't notify us when the connection disconnects. - * Neither does NMManager (or NMDevice) tell us when the ip-ifindex goes away. - * This is horrible, and should be improved. For now, watch the link ourself... */ - - if (NM_IN_SET(change_type, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_SIGNAL_REMOVED)) { - priv = NM_DEVICE_BT_GET_PRIVATE(self); - if (priv->connect_watch_link_idle_id == 0) - priv->connect_watch_link_idle_id = g_idle_add(connect_watch_link_idle_cb, self); - } -} - -static gboolean -connect_wait_modem_timeout(gpointer user_data) -{ - NMDeviceBt * self = NM_DEVICE_BT(user_data); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - /* since this timeout is longer than the connect timeout, we must have already - * hit the connect-timeout first or being connected. */ - nm_assert(priv->stage1_bt_state == NM_DEVICE_STAGE_STATE_COMPLETED); - - priv->connect_wait_modem_id = 0; - nm_clear_g_cancellable(&priv->connect_bz_cancellable); - - if (priv->modem) - _LOGD(LOGD_BT, "timeout connecting modem for DUN connection"); - else - _LOGD(LOGD_BT, "timeout finding modem for DUN connection"); - - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND); - return G_SOURCE_REMOVE; -} - -static void -connect_bz_cb(NMBluezManager *bz_mgr, - gboolean is_complete, - const char * device_name, - GError * error, - gpointer user_data) -{ - NMDeviceBt * self; - NMDeviceBtPrivate *priv; - char sbuf[100]; - - if (nm_utils_error_is_cancelled(error)) - return; - - self = user_data; - priv = NM_DEVICE_BT_GET_PRIVATE(self); - - nm_assert(nm_device_is_activating(NM_DEVICE(self))); - nm_assert(NM_IN_SET((NMBluetoothCapabilities) priv->connect_bt_type, - NM_BT_CAPABILITY_DUN, - NM_BT_CAPABILITY_NAP)); - - if (!is_complete) { - nm_assert(priv->connect_bt_type == NM_BT_CAPABILITY_DUN); - nm_assert(device_name); - nm_assert(!error); - - if (!nm_streq0(priv->connect_rfcomm_iface, device_name)) { - nm_assert(!priv->connect_rfcomm_iface); - _LOGD(LOGD_BT, - "DUN is still connecting but got serial port \"%s\" to claim modem", - device_name); - g_free(priv->connect_rfcomm_iface); - priv->connect_rfcomm_iface = g_strdup(device_name); - } - return; - } - - g_clear_object(&priv->connect_bz_cancellable); - - if (!device_name) { - _LOGW(LOGD_BT, - "%s connect request failed: %s", - nm_bluetooth_capability_to_string(priv->connect_bt_type, sbuf, sizeof(sbuf)), - error->message); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return; - } - - _LOGD(LOGD_BT, - "%s connect request successful (%s)", - nm_bluetooth_capability_to_string(priv->connect_bt_type, sbuf, sizeof(sbuf)), - device_name); - - if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) { - if (!nm_streq0(priv->connect_rfcomm_iface, device_name)) { - nm_assert_not_reached(); - g_free(priv->connect_rfcomm_iface); - priv->connect_rfcomm_iface = g_strdup(device_name); - } - } else { - nm_assert(priv->connect_bt_type == NM_BT_CAPABILITY_NAP); - if (!nm_device_set_ip_iface(NM_DEVICE(self), device_name)) { - _LOGW(LOGD_BT, "Error connecting with bluez: cannot find device %s", device_name); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return; - } - priv->connect_watch_link_id = g_signal_connect(nm_device_get_platform(NM_DEVICE(self)), - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK(connect_watch_link_cb), - self); - } - - if (!priv->is_connected) { - /* we got the callback from NMBluezManager with success. We actually should be - * connected and this line shouldn't be reached. */ - nm_assert_not_reached(); - _LOGE(LOGD_BT, "bluetooth is unexpectedly not in connected state"); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return; - } - - priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare(NM_DEVICE(self), FALSE); -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceBt * self = NM_DEVICE_BT(device); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - NMConnection * connection; - - connection = nm_device_get_applied_connection(device); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - priv->connect_bt_type = get_connection_bt_type(connection); - if (priv->connect_bt_type == NM_BT_CAPABILITY_NONE) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_BT_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN && !priv->mm_running) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (priv->stage1_bt_state == NM_DEVICE_STAGE_STATE_PENDING) - return NM_ACT_STAGE_RETURN_POSTPONE; - else if (priv->stage1_bt_state == NM_DEVICE_STAGE_STATE_INIT) { - gs_unref_object GCancellable *cancellable = NULL; - char sbuf[100]; - - _LOGD(LOGD_BT, - "connecting to %s bluetooth device", - nm_bluetooth_capability_to_string(priv->connect_bt_type, sbuf, sizeof(sbuf))); - - cancellable = g_cancellable_new(); - - if (!nm_bluez_manager_connect(priv->bz_mgr, - priv->dbus_path, - priv->connect_bt_type, - 30000, - cancellable, - connect_bz_cb, - self, - &error)) { - _LOGD(LOGD_BT, "cannot connect to bluetooth device: %s", error->message); - *out_failure_reason = NM_DEVICE_STATE_REASON_BT_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - priv->connect_bz_cancellable = g_steal_pointer(&cancellable); - priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_PENDING; - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) { - if (!priv->modem) { - gs_free NMModem **modems = NULL; - guint i, n; - - if (priv->connect_wait_modem_id == 0) - priv->connect_wait_modem_id = - g_timeout_add_seconds(30, connect_wait_modem_timeout, self); - - modems = nm_modem_manager_get_modems(priv->modem_manager, &n); - for (i = 0; i < n; i++) { - if (modem_try_claim(self, modems[i])) - break; - } - if (!priv->modem) - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (priv->stage1_modem_prepare_state == NM_DEVICE_STAGE_STATE_PENDING) - return NM_ACT_STAGE_RETURN_POSTPONE; - if (priv->stage1_modem_prepare_state == NM_DEVICE_STAGE_STATE_INIT) { - priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_PENDING; - return nm_modem_act_stage1_prepare(priv->modem, - nm_device_get_act_request(NM_DEVICE(self)), - out_failure_reason); - } - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceBt * self = NM_DEVICE_BT(device); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) - nm_modem_act_stage2_config(priv->modem); - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(device); - - nm_assert_addr_family(addr_family); - - if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) { - if (addr_family == AF_INET) { - return nm_modem_stage3_ip4_config_start(priv->modem, - device, - NM_DEVICE_CLASS(nm_device_bt_parent_class), - out_failure_reason); - } else { - return nm_modem_stage3_ip6_config_start(priv->modem, device, out_failure_reason); - } - } - - return NM_DEVICE_CLASS(nm_device_bt_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(device); - - nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->connect_watch_link_id); - nm_clear_g_source(&priv->connect_watch_link_idle_id); - priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_INIT; - nm_clear_g_source(&priv->connect_wait_modem_id); - nm_clear_g_cancellable(&priv->connect_bz_cancellable); - - priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_INIT; - - if (priv->connect_bt_type == NM_BT_CAPABILITY_DUN) { - if (priv->modem) { - nm_modem_deactivate(priv->modem, device); - - /* Since we're killing the Modem object before it'll get the - * state change signal, simulate the state change here. - */ - nm_modem_device_state_changed(priv->modem, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_ACTIVATED); - modem_cleanup(NM_DEVICE_BT(device)); - } - } - - if (priv->connect_bt_type != NM_BT_CAPABILITY_NONE) { - priv->connect_bt_type = NM_BT_CAPABILITY_NONE; - nm_bluez_manager_disconnect(priv->bz_mgr, priv->dbus_path); - } - - nm_clear_g_free(&priv->connect_rfcomm_iface); - - if (NM_DEVICE_CLASS(nm_device_bt_parent_class)->deactivate) - NM_DEVICE_CLASS(nm_device_bt_parent_class)->deactivate(device); -} - -void -_nm_device_bt_notify_removed(NMDeviceBt *self) -{ - g_signal_emit_by_name(self, NM_DEVICE_REMOVED); -} - -/*****************************************************************************/ - -gboolean -_nm_device_bt_for_same_device(NMDeviceBt * self, - const char * dbus_path, - const char * bdaddr, - const char * name, - NMBluetoothCapabilities capabilities) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - return nm_streq(priv->dbus_path, dbus_path) && nm_streq(priv->bdaddr, bdaddr) - && capabilities == priv->capabilities && (!name || nm_streq(priv->name, name)); -} - -void -_nm_device_bt_notify_set_name(NMDeviceBt *self, const char *name) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - nm_assert(name); - - if (!nm_streq(priv->name, name)) { - _LOGT(LOGD_BT, "set-name: %s", name); - g_free(priv->name); - priv->name = g_strdup(name); - _notify(self, PROP_BT_NAME); - } -} - -/*****************************************************************************/ - -static gboolean -is_available(NMDevice *dev, NMDeviceCheckDevAvailableFlags flags) -{ - NMDeviceBt * self = NM_DEVICE_BT(dev); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - /* PAN doesn't need ModemManager, so devices that support it are always available */ - if (priv->capabilities & NM_BT_CAPABILITY_NAP) - return TRUE; - - /* DUN requires ModemManager */ - return priv->mm_running; -} - -static void -set_mm_running(NMDeviceBt *self) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - gboolean running; - - running = (nm_modem_manager_name_owner_get(priv->modem_manager) != NULL); - - if (priv->mm_running != running) { - _LOGD(LOGD_BT, "ModemManager now %s", running ? "available" : "unavailable"); - - priv->mm_running = running; - nm_device_queue_recheck_available(NM_DEVICE(self), - NM_DEVICE_STATE_REASON_NONE, - NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE); - } -} - -static void -mm_name_owner_changed_cb(GObject *object, GParamSpec *pspec, gpointer user_data) -{ - set_mm_running(user_data); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_BT_NAME: - g_value_set_string(value, priv->name); - break; - case PROP_BT_CAPABILITIES: - g_value_set_uint(value, priv->capabilities); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_BT_BZ_MGR: - /* construct-only */ - priv->bz_mgr = g_object_ref(g_value_get_pointer(value)); - nm_assert(NM_IS_BLUEZ_MANAGER(priv->bz_mgr)); - break; - case PROP_BT_DBUS_PATH: - /* construct-only */ - priv->dbus_path = g_value_dup_string(value); - nm_assert(priv->dbus_path); - break; - case PROP_BT_BDADDR: - /* construct-only */ - priv->bdaddr = g_value_dup_string(value); - nm_assert(priv->bdaddr); - break; - case PROP_BT_NAME: - /* construct-only */ - priv->name = g_value_dup_string(value); - nm_assert(priv->name); - break; - case PROP_BT_CAPABILITIES: - /* construct-only */ - priv->capabilities = g_value_get_uint(value); - nm_assert(NM_IN_SET((NMBluetoothCapabilities) priv->capabilities, - NM_BT_CAPABILITY_DUN, - NM_BT_CAPABILITY_NAP, - NM_BT_CAPABILITY_DUN | NM_BT_CAPABILITY_NAP)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_bt_init(NMDeviceBt *self) -{} - -static void -constructed(GObject *object) -{ - NMDeviceBt * self = NM_DEVICE_BT(object); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - G_OBJECT_CLASS(nm_device_bt_parent_class)->constructed(object); - - priv->modem_manager = g_object_ref(nm_modem_manager_get()); - - nm_modem_manager_name_owner_ref(priv->modem_manager); - - g_signal_connect(priv->modem_manager, - NM_MODEM_MANAGER_MODEM_ADDED, - G_CALLBACK(mm_modem_added_cb), - self); - - g_signal_connect(priv->modem_manager, - "notify::" NM_MODEM_MANAGER_NAME_OWNER, - G_CALLBACK(mm_name_owner_changed_cb), - self); - - set_mm_running(self); -} - -NMDeviceBt * -nm_device_bt_new(NMBluezManager * bz_mgr, - const char * dbus_path, - const char * bdaddr, - const char * name, - NMBluetoothCapabilities capabilities) -{ - g_return_val_if_fail(NM_IS_BLUEZ_MANAGER(bz_mgr), NULL); - g_return_val_if_fail(dbus_path, NULL); - g_return_val_if_fail(bdaddr, NULL); - g_return_val_if_fail(name, NULL); - g_return_val_if_fail(capabilities != NM_BT_CAPABILITY_NONE, NULL); - - return g_object_new(NM_TYPE_DEVICE_BT, - NM_DEVICE_UDI, - dbus_path, - NM_DEVICE_IFACE, - bdaddr, - NM_DEVICE_DRIVER, - "bluez", - NM_DEVICE_PERM_HW_ADDRESS, - bdaddr, - NM_DEVICE_BT_BDADDR, - bdaddr, - NM_DEVICE_BT_BZ_MGR, - bz_mgr, - NM_DEVICE_BT_CAPABILITIES, - (guint) capabilities, - NM_DEVICE_BT_DBUS_PATH, - dbus_path, - NM_DEVICE_BT_NAME, - name, - NM_DEVICE_TYPE_DESC, - "Bluetooth", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_BT, - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceBt * self = NM_DEVICE_BT(object); - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(self); - - nm_clear_g_signal_handler(nm_device_get_platform(NM_DEVICE(self)), - &priv->connect_watch_link_id); - nm_clear_g_source(&priv->connect_watch_link_idle_id); - - nm_clear_g_source(&priv->connect_wait_modem_id); - nm_clear_g_cancellable(&priv->connect_bz_cancellable); - - if (priv->modem_manager) { - g_signal_handlers_disconnect_by_func(priv->modem_manager, - G_CALLBACK(mm_name_owner_changed_cb), - self); - g_signal_handlers_disconnect_by_func(priv->modem_manager, - G_CALLBACK(mm_modem_added_cb), - self); - nm_modem_manager_name_owner_unref(priv->modem_manager); - g_clear_object(&priv->modem_manager); - } - - modem_cleanup(self); - - G_OBJECT_CLASS(nm_device_bt_parent_class)->dispose(object); - - g_clear_object(&priv->bz_mgr); -} - -static void -finalize(GObject *object) -{ - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE(object); - - g_free(priv->connect_rfcomm_iface); - g_free(priv->dbus_path); - g_free(priv->name); - g_free(priv->bdaddr); - - G_OBJECT_CLASS(nm_device_bt_parent_class)->finalize(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_bluetooth = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_BLUETOOTH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Name", "s", NM_DEVICE_BT_NAME), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("BtCapabilities", - "u", - NM_DEVICE_BT_CAPABILITIES), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_bt_class_init(NMDeviceBtClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->constructed = constructed; - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_bluetooth); - - device_class->connection_type_check_compatible = NM_SETTING_BLUETOOTH_SETTING_NAME; - - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->can_auto_connect = can_auto_connect; - device_class->deactivate = deactivate; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - device_class->is_available = is_available; - device_class->get_configured_mtu = nm_modem_get_configured_mtu; - - device_class->state_changed = device_state_changed; - - obj_properties[PROP_BT_BZ_MGR] = - g_param_spec_pointer(NM_DEVICE_BT_BZ_MGR, - "", - "", - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BT_BDADDR] = - g_param_spec_string(NM_DEVICE_BT_BDADDR, - "", - "", - NULL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BT_DBUS_PATH] = - g_param_spec_string(NM_DEVICE_BT_DBUS_PATH, - "", - "", - NULL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BT_NAME] = - g_param_spec_string(NM_DEVICE_BT_NAME, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BT_CAPABILITIES] = - g_param_spec_uint(NM_DEVICE_BT_CAPABILITIES, - "", - "", - NM_BT_CAPABILITY_NONE, - G_MAXUINT, - NM_BT_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[PPP_STATS] = g_signal_new(NM_DEVICE_BT_PPP_STATS, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_UINT /*guint32 in_bytes*/, - G_TYPE_UINT /*guint32 out_bytes*/); -} diff --git a/src/devices/bluetooth/nm-device-bt.h b/src/devices/bluetooth/nm-device-bt.h deleted file mode 100644 index e8a35a21..00000000 --- a/src/devices/bluetooth/nm-device-bt.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_BT_H__ -#define __NETWORKMANAGER_DEVICE_BT_H__ - -#include "devices/nm-device.h" - -#define NM_TYPE_DEVICE_BT (nm_device_bt_get_type()) -#define NM_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BT, NMDeviceBt)) -#define NM_DEVICE_BT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) -#define NM_IS_DEVICE_BT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BT)) -#define NM_IS_DEVICE_BT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_BT)) -#define NM_DEVICE_BT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_BT, NMDeviceBtClass)) - -#define NM_DEVICE_BT_BDADDR "bt-bdaddr" -#define NM_DEVICE_BT_BZ_MGR "bt-bz-mgr" -#define NM_DEVICE_BT_CAPABILITIES "bt-capabilities" -#define NM_DEVICE_BT_DBUS_PATH "bt-dbus-path" -#define NM_DEVICE_BT_NAME "bt-name" - -#define NM_DEVICE_BT_PPP_STATS "ppp-stats" - -typedef struct _NMDeviceBt NMDeviceBt; -typedef struct _NMDeviceBtClass NMDeviceBtClass; - -GType nm_device_bt_get_type(void); - -struct _NMBluezManager; - -NMDeviceBt *nm_device_bt_new(struct _NMBluezManager *bz_mgr, - const char * dbus_path, - const char * bdaddr, - const char * name, - NMBluetoothCapabilities capabilities); - -gboolean _nm_device_bt_for_same_device(NMDeviceBt * device, - const char * dbus_path, - const char * bdaddr, - const char * name, - NMBluetoothCapabilities capabilities); - -NMBluetoothCapabilities nm_device_bt_get_capabilities(NMDeviceBt *device); - -struct _NMModem; - -gboolean nm_device_bt_modem_added(NMDeviceBt *device, struct _NMModem *modem, const char *driver); - -void _nm_device_bt_notify_removed(NMDeviceBt *self); - -void _nm_device_bt_notify_set_name(NMDeviceBt *self, const char *name); - -void _nm_device_bt_notify_set_connected(NMDeviceBt *self, gboolean connected); - -#endif /* __NETWORKMANAGER_DEVICE_BT_H__ */ diff --git a/src/devices/bluetooth/tests/nm-bt-test.c b/src/devices/bluetooth/tests/nm-bt-test.c deleted file mode 100644 index a57bb076..00000000 --- a/src/devices/bluetooth/tests/nm-bt-test.c +++ /dev/null @@ -1,223 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ - -#include "nm-default.h" - -#include <glib-unix.h> - -#include "devices/bluetooth/nm-bluez5-dun.h" - -#include "nm-test-utils-core.h" - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_BT -#define _NMLOG(level, ...) \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - NULL, \ - NULL, \ - "bt%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - NM_PRINT_FMT_QUOTED(gl.argv_cmd, "[", gl.argv_cmd, "]", "") \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)) - -/*****************************************************************************/ - -struct { - int argc; - const char *const *argv; - const char * argv_cmd; - GMainLoop * loop; -} gl; - -typedef struct _MainCmdInfo { - const char *name; - int (*main_func)(const struct _MainCmdInfo *main_cmd_info); -} MainCmdInfo; - -/*****************************************************************************/ - -#if WITH_BLUEZ5_DUN - -typedef struct { - NMBluez5DunContext *dun_context; - GCancellable * cancellable; - guint timeout_id; - guint sig_term_id; - guint sig_int_id; -} DunConnectData; - -static void -_dun_connect_cb(NMBluez5DunContext *context, - const char * rfcomm_dev, - GError * error, - gpointer user_data) -{ - DunConnectData *dun_connect_data = user_data; - - g_assert(dun_connect_data); - g_assert(!dun_connect_data->dun_context); - g_assert((!!error) != (!!rfcomm_dev)); - - if (rfcomm_dev && !context) { - _LOGI("dun-connect notifies path \"%s\". Wait longer...", rfcomm_dev); - return; - } - - if (rfcomm_dev) { - g_assert(context); - _LOGI("dun-connect completed with path \"%s\"", rfcomm_dev); - } else { - g_assert(!context); - _LOGI("dun-connect failed with error: %s", error->message); - } - - dun_connect_data->dun_context = context; - - g_main_loop_quit(gl.loop); -} - -static void -_dun_notify_tty_hangup_cb(NMBluez5DunContext *context, gpointer user_data) -{ - _LOGI("dun-connect: notified TTY hangup"); -} - -static gboolean -_timeout_cb(gpointer user_data) -{ - DunConnectData *dun_connect_data = user_data; - - _LOGI("timeout"); - dun_connect_data->timeout_id = 0; - if (dun_connect_data->cancellable) - g_cancellable_cancel(dun_connect_data->cancellable); - return G_SOURCE_REMOVE; -} - -static gboolean -_sig_xxx_cb(DunConnectData *dun_connect_data, int sigid) -{ - _LOGI("signal %s received", sigid == SIGTERM ? "SIGTERM" : "SIGINT"); - g_main_loop_quit(gl.loop); - return G_SOURCE_CONTINUE; -} - -static gboolean -_sig_term_cb(gpointer user_data) -{ - return _sig_xxx_cb(user_data, SIGTERM); -} - -static gboolean -_sig_int_cb(gpointer user_data) -{ - return _sig_xxx_cb(user_data, SIGINT); -} -#endif - -static int -do_dun_connect(const MainCmdInfo *main_cmd_info) -{ -#if WITH_BLUEZ5_DUN - gs_unref_object GCancellable *cancellable = NULL; - gs_free_error GError *error = NULL; - const char * adapter; - const char * remote; - DunConnectData dun_connect_data = {}; - - if (gl.argc < 4) { - _LOGE("missing arguments \"adapter\" and \"remote\""); - return -1; - } - - adapter = gl.argv[2]; - remote = gl.argv[3]; - - cancellable = g_cancellable_new(); - dun_connect_data.cancellable = cancellable; - - if (!nm_bluez5_dun_connect(adapter, - remote, - cancellable, - _dun_connect_cb, - &dun_connect_data, - _dun_notify_tty_hangup_cb, - &dun_connect_data, - &error)) { - _LOGE("connect failed to start: %s", error->message); - return -1; - } - - dun_connect_data.timeout_id = g_timeout_add(60000, _timeout_cb, &dun_connect_data); - - g_main_loop_run(gl.loop); - - nm_clear_g_source(&dun_connect_data.timeout_id); - - if (dun_connect_data.dun_context) { - dun_connect_data.sig_term_id = g_unix_signal_add(SIGTERM, _sig_term_cb, &dun_connect_data); - dun_connect_data.sig_int_id = g_unix_signal_add(SIGINT, _sig_int_cb, &dun_connect_data); - - g_main_loop_run(gl.loop); - - nm_clear_g_source(&dun_connect_data.sig_term_id); - nm_clear_g_source(&dun_connect_data.sig_int_id); - - nm_bluez5_dun_disconnect(g_steal_pointer(&dun_connect_data.dun_context)); - } - - return 0; -#else - _LOGE("compiled without bluetooth DUN support"); - return 1; -#endif -} - -/*****************************************************************************/ - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - static const MainCmdInfo main_cmd_infos[] = { - { - .name = "dun-connect", - .main_func = do_dun_connect, - }, - }; - int exit_code = 0; - guint i; - - if (!g_getenv("G_MESSAGES_DEBUG")) - g_setenv("G_MESSAGES_DEBUG", "all", TRUE); - - nmtst_init_with_logging(&argc, &argv, "DEBUG", "ALL"); - - nm_logging_init(NULL, TRUE); - - gl.argv = (const char *const *) argv; - gl.argc = argc; - gl.loop = g_main_loop_new(NULL, FALSE); - - _LOGI("bluetooth test util start"); - - gl.argv_cmd = argc >= 2 ? argv[1] : NULL; - - for (i = 0; i < G_N_ELEMENTS(main_cmd_infos); i++) { - if (nm_streq0(main_cmd_infos[i].name, gl.argv_cmd)) { - _LOGD("start \"%s\"", gl.argv_cmd); - exit_code = main_cmd_infos[i].main_func(&main_cmd_infos[i]); - _LOGD("completed with %d", exit_code); - break; - } - } - if (gl.argv_cmd && i >= G_N_ELEMENTS(main_cmd_infos)) { - nm_log_err(LOGD_BT, "invalid command \"%s\"", gl.argv_cmd); - exit_code = -1; - } - - nm_clear_pointer(&gl.loop, g_main_loop_unref); - - return exit_code; -} diff --git a/src/devices/meson.build b/src/devices/meson.build deleted file mode 100644 index 40a5c9dc..00000000 --- a/src/devices/meson.build +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -subdir('adsl') - -if enable_modem_manager - subdir('wwan') - subdir('bluetooth') -endif - -if enable_wifi - subdir('wifi') -endif - -if enable_teamdctl - subdir('team') -endif - -if enable_ovs - subdir('ovs') -endif - -if enable_tests - subdir('tests') -endif diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c deleted file mode 100644 index c9992ff5..00000000 --- a/src/devices/nm-acd-manager.c +++ /dev/null @@ -1,495 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2015 - 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-acd-manager.h" - -#include <netinet/in.h> -#include <sys/types.h> -#include <sys/wait.h> - -#include "platform/nm-platform.h" -#include "nm-utils.h" -#include "NetworkManagerUtils.h" -#include "n-acd/src/n-acd.h" - -/*****************************************************************************/ - -typedef enum { - STATE_INIT, - STATE_PROBING, - STATE_PROBE_DONE, - STATE_ANNOUNCING, -} State; - -typedef struct { - in_addr_t address; - gboolean duplicate; - NAcdProbe *probe; -} AddressInfo; - -struct _NMAcdManager { - int ifindex; - guint8 hwaddr[ETH_ALEN]; - State state; - GHashTable *addresses; - guint completed; - NAcd * acd; - GSource * event_source; - - NMAcdCallbacks callbacks; - gpointer user_data; -}; - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_IP4 -#define _NMLOG_PREFIX_NAME "acd" -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - char _sbuf[64]; \ - \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - self && self->ifindex > 0 \ - ? nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex) \ - : NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - self ? nm_sprintf_buf(_sbuf, "[%p,%d]", self, self->ifindex) \ - : "" _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static const char * -_acd_event_to_string(unsigned int event) -{ - switch (event) { - case N_ACD_EVENT_READY: - return "ready"; - case N_ACD_EVENT_USED: - return "used"; - case N_ACD_EVENT_DEFENDED: - return "defended"; - case N_ACD_EVENT_CONFLICT: - return "conflict"; - case N_ACD_EVENT_DOWN: - return "down"; - } - return NULL; -} - -#define ACD_EVENT_TO_STRING_BUF_SIZE 50 - -static const char * -_acd_event_to_string_buf(unsigned event, char buffer[static ACD_EVENT_TO_STRING_BUF_SIZE]) -{ - const char *s; - - s = _acd_event_to_string(event); - if (s) - return s; - - g_snprintf(buffer, ACD_EVENT_TO_STRING_BUF_SIZE, "(%u)", event); - return buffer; -} - -static const char * -acd_error_to_string(int error) -{ - if (error < 0) - return nm_strerror_native(-error); - - switch (error) { - case _N_ACD_E_SUCCESS: - return "success"; - case N_ACD_E_PREEMPTED: - return "preempted"; - case N_ACD_E_INVALID_ARGUMENT: - return "invalid argument"; - } - - g_return_val_if_reached(NULL); -} - -static int -acd_error_to_nmerr(int error, gboolean always_fail) -{ - if (error < 0) - return -nm_errno_native(error); - - if (always_fail) { - if (NM_IN_SET(error, N_ACD_E_PREEMPTED, N_ACD_E_INVALID_ARGUMENT)) - return -NME_UNSPEC; - g_return_val_if_reached(-NME_UNSPEC); - } - - /* so, @error is either zero (indicating success) or one - * of the special status codes like N_ACD_E_*. In both cases, - * return the positive value here. */ - if (NM_IN_SET(error, _N_ACD_E_SUCCESS, N_ACD_E_PREEMPTED, N_ACD_E_INVALID_ARGUMENT)) - return error; - - g_return_val_if_reached(error); -} - -/*****************************************************************************/ - -/** - * nm_acd_manager_add_address: - * @self: a #NMAcdManager - * @address: an IP address - * - * Add @address to the list of IP addresses to probe. - - * Returns: %TRUE on success, %FALSE if the address was already in the list - */ -gboolean -nm_acd_manager_add_address(NMAcdManager *self, in_addr_t address) -{ - AddressInfo *info; - - g_return_val_if_fail(self, FALSE); - g_return_val_if_fail(self->state == STATE_INIT, FALSE); - - if (g_hash_table_lookup(self->addresses, GUINT_TO_POINTER(address))) - return FALSE; - - info = g_slice_new0(AddressInfo); - info->address = address; - - g_hash_table_insert(self->addresses, GUINT_TO_POINTER(address), info); - - return TRUE; -} - -static gboolean -acd_event(int fd, GIOCondition condition, gpointer data) -{ - NMAcdManager *self = data; - NAcdEvent * event; - AddressInfo * info; - gboolean emit_probe_terminated = FALSE; - char address_str[INET_ADDRSTRLEN]; - int r; - - if (n_acd_dispatch(self->acd)) - return G_SOURCE_CONTINUE; - - while (!n_acd_pop_event(self->acd, &event) && event) { - char to_string_buffer[ACD_EVENT_TO_STRING_BUF_SIZE]; - gs_free char *hwaddr_str = NULL; - gboolean check_probing_done = FALSE; - - switch (event->event) { - case N_ACD_EVENT_READY: - n_acd_probe_get_userdata(event->ready.probe, (void **) &info); - info->duplicate = FALSE; - if (self->state == STATE_ANNOUNCING) { - /* fake probe ended, start announcing */ - r = n_acd_probe_announce(info->probe, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW("couldn't announce address %s on interface '%s': %s", - _nm_utils_inet4_ntop(info->address, address_str), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - } else { - _LOGD("announcing address %s", - _nm_utils_inet4_ntop(info->address, address_str)); - } - } - check_probing_done = TRUE; - break; - case N_ACD_EVENT_USED: - n_acd_probe_get_userdata(event->used.probe, (void **) &info); - info->duplicate = TRUE; - check_probing_done = TRUE; - break; - case N_ACD_EVENT_DEFENDED: - n_acd_probe_get_userdata(event->defended.probe, (void **) &info); - _LOGD("defended address %s from host %s", - _nm_utils_inet4_ntop(info->address, address_str), - (hwaddr_str = - nm_utils_hwaddr_ntoa(event->defended.sender, event->defended.n_sender))); - break; - case N_ACD_EVENT_CONFLICT: - n_acd_probe_get_userdata(event->conflict.probe, (void **) &info); - _LOGW("conflict for address %s detected with host %s on interface '%s'", - _nm_utils_inet4_ntop(info->address, address_str), - (hwaddr_str = - nm_utils_hwaddr_ntoa(event->defended.sender, event->defended.n_sender)), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex)); - break; - default: - _LOGD("unhandled event '%s'", _acd_event_to_string_buf(event->event, to_string_buffer)); - break; - } - - if (check_probing_done && self->state == STATE_PROBING - && ++self->completed == g_hash_table_size(self->addresses)) { - self->state = STATE_PROBE_DONE; - emit_probe_terminated = TRUE; - } - } - - if (emit_probe_terminated) { - if (self->callbacks.probe_terminated_callback) { - self->callbacks.probe_terminated_callback(self, self->user_data); - } - } - - return G_SOURCE_CONTINUE; -} - -static gboolean -acd_probe_add(NMAcdManager *self, AddressInfo *info, guint64 timeout) -{ - NAcdProbeConfig *probe_config; - int r; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - r = n_acd_probe_config_new(&probe_config); - if (r) { - _LOGW("could not create probe config for %s on interface '%s': %s", - _nm_utils_inet4_ntop(info->address, sbuf), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - return FALSE; - } - - n_acd_probe_config_set_ip(probe_config, (struct in_addr){info->address}); - n_acd_probe_config_set_timeout(probe_config, timeout); - - r = n_acd_probe(self->acd, &info->probe, probe_config); - if (r) { - _LOGW("could not start probe for %s on interface '%s': %s", - _nm_utils_inet4_ntop(info->address, sbuf), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - n_acd_probe_config_free(probe_config); - return FALSE; - } - - n_acd_probe_set_userdata(info->probe, info); - n_acd_probe_config_free(probe_config); - - return TRUE; -} - -static int -acd_init(NMAcdManager *self) -{ - NAcdConfig *config; - int r; - - if (self->acd) - return 0; - - r = n_acd_config_new(&config); - if (r) - return r; - - n_acd_config_set_ifindex(config, self->ifindex); - n_acd_config_set_transport(config, N_ACD_TRANSPORT_ETHERNET); - n_acd_config_set_mac(config, self->hwaddr, ETH_ALEN); - - r = n_acd_new(&self->acd, config); - n_acd_config_free(config); - return r; -} - -/** - * nm_acd_manager_start_probe: - * @self: a #NMAcdManager - * @timeout: maximum probe duration in milliseconds - * @error: location to store error, or %NULL - * - * Start probing IP addresses for duplicates; when the probe terminates a - * PROBE_TERMINATED signal is emitted. - * - * Returns: 0 on success or a negative NetworkManager error code (NME_*). - */ -int -nm_acd_manager_start_probe(NMAcdManager *self, guint timeout) -{ - GHashTableIter iter; - AddressInfo * info; - gboolean success = FALSE; - int fd, r; - - g_return_val_if_fail(self, FALSE); - g_return_val_if_fail(self->state == STATE_INIT, FALSE); - - r = acd_init(self); - if (r) { - _LOGW("couldn't init ACD for probing on interface '%s': %s", - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - return acd_error_to_nmerr(r, TRUE); - } - - self->completed = 0; - - g_hash_table_iter_init(&iter, self->addresses); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &info)) - success |= acd_probe_add(self, info, timeout); - - if (success) - self->state = STATE_PROBING; - - nm_assert(!self->event_source); - n_acd_get_fd(self->acd, &fd); - self->event_source = - nm_g_unix_fd_source_new(fd, G_IO_IN, G_PRIORITY_DEFAULT, acd_event, self, NULL); - g_source_attach(self->event_source, NULL); - - return success ? 0 : -NME_UNSPEC; -} - -/** - * nm_acd_manager_check_address: - * @self: a #NMAcdManager - * @address: an IP address - * - * Check if an IP address is duplicate. @address must have been added with - * nm_acd_manager_add_address(). - * - * Returns: %TRUE if the address is not duplicate, %FALSE otherwise - */ -gboolean -nm_acd_manager_check_address(NMAcdManager *self, in_addr_t address) -{ - AddressInfo *info; - - g_return_val_if_fail(self, FALSE); - g_return_val_if_fail(NM_IN_SET(self->state, STATE_INIT, STATE_PROBE_DONE), FALSE); - - info = g_hash_table_lookup(self->addresses, GUINT_TO_POINTER(address)); - g_return_val_if_fail(info, FALSE); - - return !info->duplicate; -} - -/** - * nm_acd_manager_announce_addresses: - * @self: a #NMAcdManager - * - * Start announcing addresses. - * - * Returns: a negative NetworkManager error number or zero on success. - */ -int -nm_acd_manager_announce_addresses(NMAcdManager *self) -{ - GHashTableIter iter; - AddressInfo * info; - int r; - int fd; - gboolean success = TRUE; - - r = acd_init(self); - if (r) { - _LOGW("couldn't init ACD for announcing addresses on interface '%s': %s", - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - return acd_error_to_nmerr(r, TRUE); - } - - if (self->state == STATE_INIT) { - /* n-acd can't announce without probing, therefore let's - * start a fake probe with zero timeout and then perform - * the announcement. */ - g_hash_table_iter_init(&iter, self->addresses); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &info)) { - if (!acd_probe_add(self, info, 0)) - success = FALSE; - } - self->state = STATE_ANNOUNCING; - } else if (self->state == STATE_ANNOUNCING) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - g_hash_table_iter_init(&iter, self->addresses); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &info)) { - if (info->duplicate) - continue; - r = n_acd_probe_announce(info->probe, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW("couldn't announce address %s on interface '%s': %s", - _nm_utils_inet4_ntop(info->address, sbuf), - nm_platform_link_get_name(NM_PLATFORM_GET, self->ifindex), - acd_error_to_string(r)); - success = FALSE; - } else - _LOGD("announcing address %s", _nm_utils_inet4_ntop(info->address, sbuf)); - } - } - - if (!self->event_source) { - n_acd_get_fd(self->acd, &fd); - self->event_source = - nm_g_unix_fd_source_new(fd, G_IO_IN, G_PRIORITY_DEFAULT, acd_event, self, NULL); - g_source_attach(self->event_source, NULL); - } - - return success ? 0 : -NME_UNSPEC; -} - -static void -destroy_address_info(gpointer data) -{ - AddressInfo *info = (AddressInfo *) data; - - n_acd_probe_free(info->probe); - - g_slice_free(AddressInfo, info); -} - -/*****************************************************************************/ - -NMAcdManager * -nm_acd_manager_new(int ifindex, - const guint8 * hwaddr, - guint hwaddr_len, - const NMAcdCallbacks *callbacks, - gpointer user_data) -{ - NMAcdManager *self; - - g_return_val_if_fail(ifindex > 0, NULL); - g_return_val_if_fail(hwaddr, NULL); - g_return_val_if_fail(hwaddr_len == ETH_ALEN, NULL); - - self = g_slice_new0(NMAcdManager); - - if (callbacks) - self->callbacks = *callbacks; - self->user_data = user_data; - - self->addresses = g_hash_table_new_full(nm_direct_hash, NULL, NULL, destroy_address_info); - self->state = STATE_INIT; - self->ifindex = ifindex; - memcpy(self->hwaddr, hwaddr, ETH_ALEN); - return self; -} - -void -nm_acd_manager_free(NMAcdManager *self) -{ - g_return_if_fail(self); - - if (self->callbacks.user_data_destroy) - self->callbacks.user_data_destroy(self->user_data); - - nm_clear_pointer(&self->addresses, g_hash_table_destroy); - nm_clear_g_source_inst(&self->event_source); - nm_clear_pointer(&self->acd, n_acd_unref); - - g_slice_free(NMAcdManager, self); -} diff --git a/src/devices/nm-acd-manager.h b/src/devices/nm-acd-manager.h deleted file mode 100644 index 21001c74..00000000 --- a/src/devices/nm-acd-manager.h +++ /dev/null @@ -1,34 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2015 - 2018 Red Hat, Inc. - */ - -#ifndef __NM_ACD_MANAGER__ -#define __NM_ACD_MANAGER__ - -#include <netinet/in.h> - -typedef struct _NMAcdManager NMAcdManager; - -typedef struct { - void (*probe_terminated_callback)(NMAcdManager *self, gpointer user_data); - GDestroyNotify user_data_destroy; -} NMAcdCallbacks; - -NMAcdManager *nm_acd_manager_new(int ifindex, - const guint8 * hwaddr, - guint hwaddr_len, - const NMAcdCallbacks *callbacks, - gpointer user_data); - -void nm_acd_manager_free(NMAcdManager *self); - -gboolean nm_acd_manager_add_address(NMAcdManager *self, in_addr_t address); -int nm_acd_manager_start_probe(NMAcdManager *self, guint timeout); -gboolean nm_acd_manager_check_address(NMAcdManager *self, in_addr_t address); -int nm_acd_manager_announce_addresses(NMAcdManager *self); - -NM_AUTO_DEFINE_FCN0(NMAcdManager *, _nm_auto_free_acdmgr, nm_acd_manager_free); -#define nm_auto_free_acdmgr nm_auto(_nm_auto_free_acdmgr) - -#endif /* __NM_ACD_MANAGER__ */ diff --git a/src/devices/nm-device-6lowpan.c b/src/devices/nm-device-6lowpan.c deleted file mode 100644 index bf63fb73..00000000 --- a/src/devices/nm-device-6lowpan.c +++ /dev/null @@ -1,339 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-6lowpan.h" - -#include "nm-device-private.h" -#include "settings/nm-settings.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-setting-6lowpan.h" -#include "nm-utils.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDevice6Lowpan); - -/*****************************************************************************/ - -typedef struct { - gulong parent_state_id; -} NMDevice6LowpanPrivate; - -struct _NMDevice6Lowpan { - NMDevice parent; - NMDevice6LowpanPrivate _priv; -}; - -struct _NMDevice6LowpanClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDevice6Lowpan, nm_device_6lowpan, NM_TYPE_DEVICE) - -#define NM_DEVICE_6LOWPAN_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDevice6Lowpan, NM_IS_DEVICE_6LOWPAN, NMDevice) - -/*****************************************************************************/ - -static void -parent_state_changed(NMDevice * parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN(user_data); - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void -parent_changed_notify(NMDevice *device, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent) -{ - NMDevice6Lowpan * self = NM_DEVICE_6LOWPAN(device); - NMDevice6LowpanPrivate *priv = NM_DEVICE_6LOWPAN_GET_PRIVATE(self); - - NM_DEVICE_CLASS(nm_device_6lowpan_parent_class) - ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); - - if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); - } - - if (new_ifindex > 0) { - /* Recheck availability now that the parent has changed */ - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_PARENT_CHANGED, - NM_DEVICE_STATE_REASON_PARENT_CHANGED); - } -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char * iface = nm_device_get_iface(device); - NMSetting6Lowpan *s_6lowpan; - int parent_ifindex; - int r; - - s_6lowpan = NM_SETTING_6LOWPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_6LOWPAN)); - g_return_val_if_fail(s_6lowpan, FALSE); - - parent_ifindex = parent ? nm_device_get_ifindex(parent) : 0; - - if (parent_ifindex <= 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "6LoWPAN devices can not be created without a parent interface"); - g_return_val_if_fail(!parent, FALSE); - return FALSE; - } - - r = nm_platform_link_6lowpan_add(nm_device_get_platform(device), - iface, - parent_ifindex, - out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create 6lowpan interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - nm_device_parent_set_ifindex(device, parent_ifindex); - - return TRUE; -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NMDevice6Lowpan *self = NM_DEVICE_6LOWPAN(device); - int parent = 0; - int ifindex; - - NM_DEVICE_CLASS(nm_device_6lowpan_parent_class)->link_changed(device, pllink); - - ifindex = nm_device_get_ifindex(device); - if (!nm_platform_link_6lowpan_get_properties(nm_device_get_platform(device), - ifindex, - &parent)) { - _LOGW(LOGD_DEVICE, "could not get 6lowpan properties"); - return; - } - - nm_device_parent_set_ifindex(device, parent); -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_6lowpan_parent_class)->is_available(device, flags); -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSetting6Lowpan *s_6lowpan; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_6LOWPAN_SETTING_NAME, - existing_connections, - NULL, - _("6LOWPAN connection"), - NULL, - NULL, - TRUE); - - s_6lowpan = NM_SETTING_6LOWPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_6LOWPAN)); - if (!s_6lowpan) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A '6lowpan' setting is required."); - return FALSE; - } - - /* If there's no 6LoWPAN interface, no parent, and no hardware address in the - * settings, then there's not enough information to complete the setting. - */ - if (!nm_setting_6lowpan_get_parent(s_6lowpan) - && !nm_device_match_parent_hwaddr(device, connection, TRUE)) { - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "The '6lowpan' setting had no interface name, parent, or hardware address."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMSetting6Lowpan *s_6lowpan = - NM_SETTING_6LOWPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_6LOWPAN)); - - if (!s_6lowpan) { - s_6lowpan = (NMSetting6Lowpan *) nm_setting_6lowpan_new(); - nm_connection_add_setting(connection, (NMSetting *) s_6lowpan); - } - - g_object_set( - s_6lowpan, - NM_SETTING_6LOWPAN_PARENT, - nm_device_parent_find_for_connection(device, nm_setting_6lowpan_get_parent(s_6lowpan)), - NULL); -} - -/*****************************************************************************/ - -static void -nm_device_6lowpan_init(NMDevice6Lowpan *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_6lowpan = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_6LOWPAN, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Parent", "o", NM_DEVICE_PARENT), ), ), -}; - -static void -nm_device_6lowpan_class_init(NMDevice6LowpanClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_6lowpan); - - device_class->connection_type_supported = NM_SETTING_6LOWPAN_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_6LOWPAN_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_6LOWPAN); - - device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; - device_class->complete_connection = complete_connection; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - device_class->link_changed = link_changed; - device_class->is_available = is_available; - device_class->parent_changed_notify = parent_changed_notify; - device_class->update_connection = update_connection; -} - -/*****************************************************************************/ - -#define NM_TYPE_6LOWPAN_DEVICE_FACTORY (nm_6lowpan_device_factory_get_type()) -#define NM_6LOWPAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_6LOWPAN_DEVICE_FACTORY, NM6LowpanDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_6LOWPAN, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "6LoWPAN", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_6LOWPAN, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_6LOWPAN, - NULL); -} - -static const char * -get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSetting6Lowpan *s_6lowpan; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_6LOWPAN_SETTING_NAME), NULL); - - s_6lowpan = NM_SETTING_6LOWPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_6LOWPAN)); - g_assert(s_6lowpan); - - return nm_setting_6lowpan_get_parent(s_6lowpan); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - NMSetting6Lowpan *s_6lowpan; - const char * ifname; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_6LOWPAN_SETTING_NAME), NULL); - - s_6lowpan = NM_SETTING_6LOWPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_6LOWPAN)); - g_assert(s_6lowpan); - - if (!parent_iface) - return NULL; - - ifname = nm_connection_get_interface_name(connection); - return g_strdup(ifname); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - 6LOWPAN, - 6Lowpan, - 6lowpan, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_6LOWPAN) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_6LOWPAN_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); diff --git a/src/devices/nm-device-6lowpan.h b/src/devices/nm-device-6lowpan.h deleted file mode 100644 index 60207d76..00000000 --- a/src/devices/nm-device-6lowpan.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_6LOWPAN_H__ -#define __NETWORKMANAGER_DEVICE_6LOWPAN_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_6LOWPAN (nm_device_6lowpan_get_type()) -#define NM_DEVICE_6LOWPAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_6LOWPAN, NMDevice6Lowpan)) -#define NM_DEVICE_6LOWPAN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_6LOWPAN, NMDevice6LowpanClass)) -#define NM_IS_DEVICE_6LOWPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_6LOWPAN)) -#define NM_IS_DEVICE_6LOWPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_6LOWPAN)) -#define NM_DEVICE_6LOWPAN_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_6LOWPAN, NMDevice6LowpanClass)) - -typedef struct _NMDevice6Lowpan NMDevice6Lowpan; -typedef struct _NMDevice6LowpanClass NMDevice6LowpanClass; - -GType nm_device_6lowpan_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_6LOWPAN_H__ */ diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c deleted file mode 100644 index 3ef14a9e..00000000 --- a/src/devices/nm-device-bond.c +++ /dev/null @@ -1,639 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 - 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-bond.h" - -#include <stdlib.h> -#include <net/if.h> - -#include "NetworkManagerUtils.h" -#include "nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-core-internal.h" -#include "nm-ip4-config.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceBond); - -/*****************************************************************************/ - -#define OPTIONS_APPLY_SUBSET \ - NM_SETTING_BOND_OPTION_MIIMON, NM_SETTING_BOND_OPTION_UPDELAY, \ - NM_SETTING_BOND_OPTION_DOWNDELAY, NM_SETTING_BOND_OPTION_ARP_INTERVAL, \ - NM_SETTING_BOND_OPTION_ARP_VALIDATE, NM_SETTING_BOND_OPTION_PRIMARY, \ - NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, \ - NM_SETTING_BOND_OPTION_AD_SELECT, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY, \ - NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS, \ - NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, NM_SETTING_BOND_OPTION_LACP_RATE, \ - NM_SETTING_BOND_OPTION_LP_INTERVAL, NM_SETTING_BOND_OPTION_MIN_LINKS, \ - NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, \ - NM_SETTING_BOND_OPTION_RESEND_IGMP, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, \ - NM_SETTING_BOND_OPTION_USE_CARRIER, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, \ - NM_SETTING_BOND_OPTION_NUM_GRAT_ARP - -#define OPTIONS_REAPPLY_SUBSET \ - NM_SETTING_BOND_OPTION_MIIMON, NM_SETTING_BOND_OPTION_UPDELAY, \ - NM_SETTING_BOND_OPTION_DOWNDELAY, NM_SETTING_BOND_OPTION_ARP_INTERVAL, \ - NM_SETTING_BOND_OPTION_ARP_VALIDATE, NM_SETTING_BOND_OPTION_PRIMARY, \ - NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO, \ - NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS, \ - NM_SETTING_BOND_OPTION_FAIL_OVER_MAC, NM_SETTING_BOND_OPTION_LP_INTERVAL, \ - NM_SETTING_BOND_OPTION_MIN_LINKS, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, \ - NM_SETTING_BOND_OPTION_PRIMARY_RESELECT, NM_SETTING_BOND_OPTION_RESEND_IGMP, \ - NM_SETTING_BOND_OPTION_USE_CARRIER, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, \ - NM_SETTING_BOND_OPTION_NUM_GRAT_ARP - -#define OPTIONS_REAPPLY_FULL \ - OPTIONS_REAPPLY_SUBSET, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE, \ - NM_SETTING_BOND_OPTION_ARP_IP_TARGET - -/*****************************************************************************/ - -struct _NMDeviceBond { - NMDevice parent; -}; - -struct _NMDeviceBondClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceBond, nm_device_bond, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingBond *s_bond; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_BOND_SETTING_NAME, - existing_connections, - NULL, - _("Bond connection"), - "bond", - NULL, - TRUE); - - s_bond = nm_connection_get_setting_bond(connection); - if (!s_bond) { - s_bond = (NMSettingBond *) nm_setting_bond_new(); - nm_connection_add_setting(connection, NM_SETTING(s_bond)); - } - - return TRUE; -} - -/*****************************************************************************/ - -static gboolean -_set_bond_attr(NMDevice *device, const char *attr, const char *value) -{ - NMDeviceBond *self = NM_DEVICE_BOND(device); - int ifindex = nm_device_get_ifindex(device); - gboolean ret; - - ret = - nm_platform_sysctl_master_set_option(nm_device_get_platform(device), ifindex, attr, value); - if (!ret) - _LOGW(LOGD_PLATFORM, "failed to set bonding attribute '%s' to '%s'", attr, value); - return ret; -} - -#define _set_bond_attr_take(device, attr, value) \ - G_STMT_START \ - { \ - gs_free char *_tmp = (value); \ - \ - _set_bond_attr(device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, _tmp); \ - } \ - G_STMT_END - -#define _set_bond_attr_printf(device, attr, fmt, ...) \ - _set_bond_attr_take((device), (attr), g_strdup_printf(fmt, __VA_ARGS__)) - -static gboolean -ignore_option(NMSettingBond *s_bond, const char *option, const char *value) -{ - const char *defvalue; - - if (nm_streq0(option, NM_SETTING_BOND_OPTION_MIIMON)) { - /* The default value for miimon, when missing in the setting, is - * 0 if arp_interval is != 0, and 100 otherwise. So, let's ignore - * miimon=0 (which means that miimon is disabled) and accept any - * other value. Adding miimon=100 does not cause any harm. - */ - defvalue = "0"; - } else - defvalue = nm_setting_bond_get_option_default(s_bond, option); - - return nm_streq0(value, defvalue); -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMSettingBond *s_bond = nm_connection_get_setting_bond(connection); - int ifindex = nm_device_get_ifindex(device); - NMBondMode mode = NM_BOND_MODE_UNKNOWN; - const char ** options; - - if (!s_bond) { - s_bond = (NMSettingBond *) nm_setting_bond_new(); - nm_connection_add_setting(connection, (NMSetting *) s_bond); - } - - /* Read bond options from sysfs and update the Bond setting to match */ - options = nm_setting_bond_get_valid_options(NULL); - for (; options[0]; options++) { - const char * option = options[0]; - gs_free char *value = NULL; - char * p; - - if (NM_IN_STRSET(option, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE)) - continue; - - value = - nm_platform_sysctl_master_get_option(nm_device_get_platform(device), ifindex, option); - - if (value && _nm_setting_bond_get_option_type(s_bond, option) == NM_BOND_OPTION_TYPE_BOTH) { - p = strchr(value, ' '); - if (p) - *p = '\0'; - } - - if (mode == NM_BOND_MODE_UNKNOWN) { - if (value && nm_streq(option, NM_SETTING_BOND_OPTION_MODE)) - mode = _nm_setting_bond_mode_from_string(value); - if (mode == NM_BOND_MODE_UNKNOWN) - continue; - } - - if (!_nm_setting_bond_option_supported(option, mode)) - continue; - - if (value && value[0] && !ignore_option(s_bond, option, value)) { - /* Replace " " with "," for arp_ip_targets from the kernel */ - if (nm_streq(option, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)) { - for (p = value; *p; p++) { - if (*p == ' ') - *p = ','; - } - } - - nm_setting_bond_add_option(s_bond, option, value); - } - } -} - -static gboolean -master_update_slave_connection(NMDevice * self, - NMDevice * slave, - NMConnection *connection, - GError ** error) -{ - g_object_set(nm_connection_get_setting_connection(connection), - NM_SETTING_CONNECTION_MASTER, - nm_device_get_iface(self), - NM_SETTING_CONNECTION_SLAVE_TYPE, - NM_SETTING_BOND_SETTING_NAME, - NULL); - return TRUE; -} - -static void -set_arp_targets(NMDevice *device, const char *cur_arp_ip_target, const char *new_arp_ip_target) -{ - gs_unref_ptrarray GPtrArray *free_list = NULL; - gs_free const char ** cur_strv = NULL; - gs_free const char ** new_strv = NULL; - gsize cur_len; - gsize new_len; - gsize i; - gsize j; - - cur_strv = nm_utils_strsplit_set_full(cur_arp_ip_target, - NM_ASCII_SPACES, - NM_UTILS_STRSPLIT_SET_FLAGS_STRSTRIP); - new_strv = nm_utils_bond_option_arp_ip_targets_split(new_arp_ip_target); - - cur_len = NM_PTRARRAY_LEN(cur_strv); - new_len = NM_PTRARRAY_LEN(new_strv); - - if (new_len > 0) { - for (j = 0, i = 0; i < new_len; i++) { - const char *s; - in_addr_t a4; - - s = new_strv[i]; - if (nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &a4)) { - char sbuf[INET_ADDRSTRLEN]; - - _nm_utils_inet4_ntop(a4, sbuf); - if (!nm_streq(s, sbuf)) { - if (!free_list) - free_list = g_ptr_array_new_with_free_func(g_free); - s = g_strdup(sbuf); - g_ptr_array_add(free_list, (gpointer) s); - } - } - - if (nm_utils_strv_find_first((char **) new_strv, i, s) < 0) - new_strv[j++] = s; - } - new_strv[j] = NULL; - new_len = j; - } - - if (cur_len == 0 && new_len == 0) - return; - - if (_nm_utils_strv_equal((char **) cur_strv, (char **) new_strv)) - return; - - for (i = 0; i < cur_len; i++) - _set_bond_attr_printf(device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, "-%s", cur_strv[i]); - for (i = 0; i < new_len; i++) - _set_bond_attr_printf(device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, "+%s", new_strv[i]); -} - -/* - * Sets bond attribute stored in the option hashtable or - * the default value if no value was set. - */ -static void -set_bond_attr_or_default(NMDevice *device, NMSettingBond *s_bond, const char *opt) -{ - NMDeviceBond *self = NM_DEVICE_BOND(device); - const char * value; - - value = nm_setting_bond_get_option_or_default(s_bond, opt); - if (!value) { - if (_LOGT_ENABLED(LOGD_BOND) && nm_setting_bond_get_option_by_name(s_bond, opt)) - _LOGT(LOGD_BOND, "bond option '%s' not set as it conflicts with other options", opt); - return; - } - - _set_bond_attr(device, opt, value); -} - -static void -set_bond_attrs_or_default(NMDevice *device, NMSettingBond *s_bond, const char *const *attr_v) -{ - nm_assert(NM_IS_DEVICE(device)); - nm_assert(s_bond); - nm_assert(attr_v); - - for (; *attr_v; ++attr_v) - set_bond_attr_or_default(device, s_bond, *attr_v); -} - -static void -set_bond_arp_ip_targets(NMDevice *device, NMSettingBond *s_bond) -{ - int ifindex = nm_device_get_ifindex(device); - gs_free char *cur_arp_ip_target = NULL; - - /* ARP targets: clear and initialize the list */ - cur_arp_ip_target = nm_platform_sysctl_master_get_option(nm_device_get_platform(device), - ifindex, - NM_SETTING_BOND_OPTION_ARP_IP_TARGET); - set_arp_targets( - device, - cur_arp_ip_target, - nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)); -} - -static gboolean -apply_bonding_config(NMDeviceBond *self) -{ - NMDevice * device = NM_DEVICE(self); - NMSettingBond *s_bond; - NMBondMode mode; - const char * mode_str; - - s_bond = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BOND); - g_return_val_if_fail(s_bond, FALSE); - - mode_str = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE); - mode = _nm_setting_bond_mode_from_string(mode_str); - g_return_val_if_fail(mode != NM_BOND_MODE_UNKNOWN, FALSE); - - /* Set mode first, as some other options (e.g. arp_interval) are valid - * only for certain modes. - */ - set_bond_attr_or_default(device, s_bond, NM_SETTING_BOND_OPTION_MODE); - - set_bond_arp_ip_targets(device, s_bond); - - set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_APPLY_SUBSET)); - return TRUE; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceBond * self = NM_DEVICE_BOND(device); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - - /* Interface must be down to set bond options */ - nm_device_take_down(device, TRUE); - if (!apply_bonding_config(self)) - ret = NM_ACT_STAGE_RETURN_FAILURE; - else { - if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - nm_device_bring_up(device, TRUE, NULL); - - return ret; -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - NMDeviceBond *self = NM_DEVICE_BOND(device); - - nm_device_master_check_slave_physical_port(device, slave, LOGD_BOND); - - if (configure) { - gboolean success; - - nm_device_take_down(slave, TRUE); - success = nm_platform_link_enslave(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - nm_device_get_ip_ifindex(slave)); - nm_device_bring_up(slave, TRUE, NULL); - - if (!success) { - _LOGI(LOGD_BOND, "enslaved bond slave %s: failed", nm_device_get_ip_iface(slave)); - return FALSE; - } - - _LOGI(LOGD_BOND, "enslaved bond slave %s", nm_device_get_ip_iface(slave)); - } else - _LOGI(LOGD_BOND, "bond slave %s was enslaved", nm_device_get_ip_iface(slave)); - - return TRUE; -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{ - NMDeviceBond *self = NM_DEVICE_BOND(device); - gboolean success; - gs_free char *address = NULL; - int ifindex_slave; - int ifindex; - - if (configure) { - ifindex = nm_device_get_ifindex(device); - if (ifindex <= 0 || !nm_platform_link_get(nm_device_get_platform(device), ifindex)) - configure = FALSE; - } - - ifindex_slave = nm_device_get_ip_ifindex(slave); - - if (ifindex_slave <= 0) - _LOGD(LOGD_BOND, "bond slave %s is already released", nm_device_get_ip_iface(slave)); - - if (configure) { - /* When the last slave is released the bond MAC will be set to a random - * value by kernel; remember the current one and restore it afterwards. - */ - address = g_strdup(nm_device_get_hw_address(device)); - - if (ifindex_slave > 0) { - success = nm_platform_link_release(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - ifindex_slave); - - if (success) { - _LOGI(LOGD_BOND, "released bond slave %s", nm_device_get_ip_iface(slave)); - } else { - _LOGW(LOGD_BOND, "failed to release bond slave %s", nm_device_get_ip_iface(slave)); - } - } - - nm_platform_process_events(nm_device_get_platform(device)); - if (nm_device_update_hw_address(device)) - nm_device_hw_addr_set(device, address, "restore", FALSE); - - /* Kernel bonding code "closes" the slave when releasing it, (which clears - * IFF_UP), so we must bring it back up here to ensure carrier changes and - * other state is noticed by the now-released slave. - */ - if (ifindex_slave > 0) { - if (!nm_device_bring_up(slave, TRUE, NULL)) - _LOGW(LOGD_BOND, "released bond slave could not be brought up."); - } - } else { - if (ifindex_slave > 0) { - _LOGI(LOGD_BOND, "bond slave %s was released", nm_device_get_ip_iface(slave)); - } - } -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char *iface = nm_device_get_iface(device); - int r; - - g_assert(iface); - - r = nm_platform_link_bond_add(nm_device_get_platform(device), iface, out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create bond interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - return TRUE; -} - -static gboolean -can_reapply_change(NMDevice * device, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error) -{ - NMDeviceClass *device_class; - - /* Only handle bond setting here, delegate other settings to parent class */ - if (nm_streq(setting_name, NM_SETTING_BOND_SETTING_NAME)) { - NMSettingBond *s_a = NM_SETTING_BOND(s_old); - NMSettingBond *s_b = NM_SETTING_BOND(s_new); - const char ** option_list; - - if (!nm_device_hash_check_invalid_keys(diffs, - NM_SETTING_BOND_SETTING_NAME, - error, - NM_SETTING_BOND_OPTIONS)) - return FALSE; - - option_list = nm_setting_bond_get_valid_options(NULL); - - for (; *option_list; ++option_list) { - const char *name = *option_list; - - /* We support changes to these */ - if (NM_IN_STRSET(name, OPTIONS_REAPPLY_FULL)) - continue; - - /* Reject any other changes */ - if (!nm_streq0(nm_setting_bond_get_option_normalized(s_a, name), - nm_setting_bond_get_option_normalized(s_b, name))) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply '%s' bond option", - name); - return FALSE; - } - } - - return TRUE; - } - - device_class = NM_DEVICE_CLASS(nm_device_bond_parent_class); - return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); -} - -static void -reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_new) -{ - NMDeviceBond * self = NM_DEVICE_BOND(device); - NMSettingBond *s_bond; - const char * value; - NMBondMode mode; - - NM_DEVICE_CLASS(nm_device_bond_parent_class)->reapply_connection(device, con_old, con_new); - - _LOGD(LOGD_BOND, "reapplying bond settings"); - s_bond = nm_connection_get_setting_bond(con_new); - g_return_if_fail(s_bond); - - value = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE); - mode = _nm_setting_bond_mode_from_string(value); - g_return_if_fail(mode != NM_BOND_MODE_UNKNOWN); - - /* Below we set only the bond options that kernel allows to modify - * while keeping the bond interface up */ - - set_bond_arp_ip_targets(device, s_bond); - - set_bond_attrs_or_default(device, s_bond, NM_MAKE_STRV(OPTIONS_REAPPLY_SUBSET)); -} - -/*****************************************************************************/ - -static void -nm_device_bond_init(NMDeviceBond *self) -{ - nm_assert(nm_device_is_master(NM_DEVICE(self))); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_bond = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_BOND, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Slaves", - "ao", - NM_DEVICE_SLAVES), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_bond_class_init(NMDeviceBondClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_bond); - - device_class->connection_type_supported = NM_SETTING_BOND_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_BOND_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_BOND); - - device_class->is_master = TRUE; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->complete_connection = complete_connection; - - device_class->update_connection = update_connection; - device_class->master_update_slave_connection = master_update_slave_connection; - - device_class->create_and_realize = create_and_realize; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; - device_class->can_reapply_change = can_reapply_change; - device_class->reapply_connection = reapply_connection; -} - -/*****************************************************************************/ - -#define NM_TYPE_BOND_DEVICE_FACTORY (nm_bond_device_factory_get_type()) -#define NM_BOND_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BOND_DEVICE_FACTORY, NMBondDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_BOND, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_DRIVER, - "bonding", - NM_DEVICE_TYPE_DESC, - "Bond", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_BOND, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_BOND, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - BOND, - Bond, - bond, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_BOND) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_BOND_SETTING_NAME), - factory_class->create_device = create_device;); diff --git a/src/devices/nm-device-bond.h b/src/devices/nm-device-bond.h deleted file mode 100644 index 46be7c23..00000000 --- a/src/devices/nm-device-bond.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2012 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_BOND_H__ -#define __NETWORKMANAGER_DEVICE_BOND_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_BOND (nm_device_bond_get_type()) -#define NM_DEVICE_BOND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BOND, NMDeviceBond)) -#define NM_DEVICE_BOND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BOND, NMDeviceBondClass)) -#define NM_IS_DEVICE_BOND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BOND)) -#define NM_IS_DEVICE_BOND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_BOND)) -#define NM_DEVICE_BOND_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_BOND, NMDeviceBondClass)) - -typedef struct _NMDeviceBond NMDeviceBond; -typedef struct _NMDeviceBondClass NMDeviceBondClass; - -GType nm_device_bond_get_type(void); - -#endif /* NM_DEVICE_BOND_H */ diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c deleted file mode 100644 index 48dcec1b..00000000 --- a/src/devices/nm-device-bridge.c +++ /dev/null @@ -1,1245 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 - 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-bridge.h" - -#include <stdlib.h> - -#include "NetworkManagerUtils.h" -#include "nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-core-internal.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceBridge); - -/*****************************************************************************/ - -struct _NMDeviceBridge { - NMDevice parent; - GCancellable *bt_cancellable; - bool vlan_configured : 1; - bool bt_registered : 1; -}; - -struct _NMDeviceBridgeClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -const NMBtVTableNetworkServer *nm_bt_vtable_network_server = NULL; - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -static gboolean -check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMSettingBluetooth *s_bt; - - if (!NM_DEVICE_CLASS(nm_device_bridge_parent_class) - ->check_connection_available(device, connection, flags, specific_object, error)) - return FALSE; - - s_bt = _nm_connection_get_setting_bluetooth_for_nap(connection); - if (s_bt) { - const char *bdaddr; - - if (!nm_bt_vtable_network_server) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "bluetooth plugin not available to activate NAP profile"); - return FALSE; - } - - bdaddr = nm_setting_bluetooth_get_bdaddr(s_bt); - if (!nm_bt_vtable_network_server->is_available( - nm_bt_vtable_network_server, - bdaddr, - (self->bt_cancellable || self->bt_registered) ? device : NULL)) { - if (bdaddr) - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "no suitable NAP device \"%s\" available", - bdaddr); - else - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "no suitable NAP device available"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingBridge *s_bridge; - const char * mac_address; - - if (!NM_DEVICE_CLASS(nm_device_bridge_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (nm_connection_is_type(connection, NM_SETTING_BLUETOOTH_SETTING_NAME) - && _nm_connection_get_setting_bluetooth_for_nap(connection)) { - s_bridge = nm_connection_get_setting_bridge(connection); - if (!s_bridge) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "missing bridge setting for bluetooth NAP profile"); - return FALSE; - } - - /* a bluetooth NAP connection is handled by the bridge. - * - * Proceed... */ - } else { - s_bridge = - _nm_connection_check_main_setting(connection, NM_SETTING_BRIDGE_SETTING_NAME, error); - if (!s_bridge) - return FALSE; - } - - mac_address = nm_setting_bridge_get_mac_address(s_bridge); - if (mac_address && nm_device_is_real(device)) { - const char *hw_addr; - - hw_addr = nm_device_get_hw_address(device); - if (!hw_addr || !nm_utils_hwaddr_matches(hw_addr, -1, mac_address, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "mac address mismatches"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingBridge *s_bridge; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_BRIDGE_SETTING_NAME, - existing_connections, - NULL, - _("Bridge connection"), - "bridge", - NULL, - TRUE); - - s_bridge = nm_connection_get_setting_bridge(connection); - if (!s_bridge) { - s_bridge = (NMSettingBridge *) nm_setting_bridge_new(); - nm_connection_add_setting(connection, NM_SETTING(s_bridge)); - } - - return TRUE; -} - -static void -to_sysfs_group_address_sys(const char *group_address, NMEtherAddr *out_addr) -{ - if (group_address == NULL) { - *out_addr = (NMEtherAddr) NM_ETHER_ADDR_INIT(NM_BRIDGE_GROUP_ADDRESS_DEF_BIN); - return; - } - if (!nm_utils_hwaddr_aton(group_address, out_addr, ETH_ALEN)) - nm_assert_not_reached(); -} - -static void -from_sysfs_group_address(const char *value, GValue *out) -{ - if (!nm_utils_hwaddr_matches(value, -1, NM_BRIDGE_GROUP_ADDRESS_DEF_STR, -1)) - g_value_set_string(out, value); -} - -static const char * -to_sysfs_group_address(GValue *value) -{ - return g_value_get_string(value) ?: NM_BRIDGE_GROUP_ADDRESS_DEF_STR; -} - -static int -to_sysfs_vlan_protocol_sys(const char *value) -{ - if (nm_streq0(value, "802.1ad")) - return ETH_P_8021AD; - - return ETH_P_8021Q; -} - -static void -from_sysfs_vlan_protocol(const char *value, GValue *out) -{ - switch (_nm_utils_ascii_str_to_uint64(value, 16, 0, G_MAXUINT, -1)) { - case ETH_P_8021Q: - /* default value */ - break; - case ETH_P_8021AD: - g_value_set_string(out, "802.1ad"); - break; - } -} - -static const char * -to_sysfs_vlan_protocol(GValue *value) -{ - const char *str = g_value_get_string(value); - - if (nm_streq0(str, "802.1ad")) { - G_STATIC_ASSERT_EXPR(ETH_P_8021AD == 0x88A8); - return "0x88A8"; - } - - G_STATIC_ASSERT_EXPR(ETH_P_8021Q == 0x8100); - return "0x8100"; -} - -static int -to_sysfs_multicast_router_sys(const char *value) -{ - if (nm_streq0(value, "disabled")) - return 0; - if (nm_streq0(value, "auto")) - return 1; - if (nm_streq0(value, "enabled")) - return 2; - - return 1; -} - -static const char * -to_sysfs_multicast_router(GValue *value) -{ - const char *str = g_value_get_string(value); - - if (nm_streq0(str, "disabled")) - return "0"; - if (nm_streq0(str, "auto")) - return "1"; - if (nm_streq0(str, "enabled")) - return "2"; - - return "1"; -} - -static void -from_sysfs_multicast_router(const char *value, GValue *out) -{ - switch (_nm_utils_ascii_str_to_uint64(value, 10, 0, G_MAXUINT, -1)) { - case 0: - g_value_set_string(out, "disabled"); - break; - case 2: - g_value_set_string(out, "enabled"); - break; - case 1: - default: - /* default value */ - break; - } -} - -/*****************************************************************************/ -#define _DEFAULT_IF_ZERO(val, def_val) \ - ({ \ - typeof(val) _val = (val); \ - typeof(val) _def_val = (def_val); \ - \ - (_val == 0) ? _def_val : _val; \ - }) - -typedef struct { - const char *name; - const char *sysname; - const char *(*to_sysfs)(GValue *value); - void (*from_sysfs)(const char *value, GValue *out); - guint64 nm_min; - guint64 nm_max; - guint64 nm_default; - bool default_if_zero; - bool user_hz_compensate; - bool only_with_stp; -} Option; - -#define OPTION(_name, _sysname, ...) \ - { \ - .name = ""_name \ - "", \ - .sysname = ""_sysname \ - "", \ - __VA_ARGS__ \ - } - -#define OPTION_TYPE_INT(min, max, def) .nm_min = (min), .nm_max = (max), .nm_default = (def) - -#define OPTION_TYPE_BOOL(def) OPTION_TYPE_INT(FALSE, TRUE, def) - -#define OPTION_TYPE_TOFROM(to, fro) .to_sysfs = (to), .from_sysfs = (fro) - -static const Option master_options[] = { - OPTION(NM_SETTING_BRIDGE_STP, /* this must stay as the first item */ - "stp_state", - OPTION_TYPE_BOOL(NM_BRIDGE_STP_DEF), ), - OPTION(NM_SETTING_BRIDGE_PRIORITY, - "priority", - OPTION_TYPE_INT(NM_BRIDGE_PRIORITY_MIN, NM_BRIDGE_PRIORITY_MAX, NM_BRIDGE_PRIORITY_DEF), - .default_if_zero = TRUE, - .only_with_stp = TRUE, ), - OPTION(NM_SETTING_BRIDGE_FORWARD_DELAY, - "forward_delay", - OPTION_TYPE_INT(NM_BRIDGE_FORWARD_DELAY_MIN, - NM_BRIDGE_FORWARD_DELAY_MAX, - NM_BRIDGE_FORWARD_DELAY_DEF), - .default_if_zero = TRUE, - .user_hz_compensate = TRUE, - .only_with_stp = TRUE, ), - OPTION(NM_SETTING_BRIDGE_HELLO_TIME, - "hello_time", - OPTION_TYPE_INT(NM_BRIDGE_HELLO_TIME_MIN, - NM_BRIDGE_HELLO_TIME_MAX, - NM_BRIDGE_HELLO_TIME_DEF), - .default_if_zero = TRUE, - .user_hz_compensate = TRUE, - .only_with_stp = TRUE, ), - OPTION(NM_SETTING_BRIDGE_MAX_AGE, - "max_age", - OPTION_TYPE_INT(NM_BRIDGE_MAX_AGE_MIN, NM_BRIDGE_MAX_AGE_MAX, NM_BRIDGE_MAX_AGE_DEF), - .default_if_zero = TRUE, - .user_hz_compensate = TRUE, - .only_with_stp = TRUE, ), - OPTION(NM_SETTING_BRIDGE_AGEING_TIME, - "ageing_time", - OPTION_TYPE_INT(NM_BRIDGE_AGEING_TIME_MIN, - NM_BRIDGE_AGEING_TIME_MAX, - NM_BRIDGE_AGEING_TIME_DEF), - .default_if_zero = TRUE, - .user_hz_compensate = TRUE, ), - OPTION(NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, "group_fwd_mask", OPTION_TYPE_INT(0, 0xFFFF, 0), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_HASH_MAX, - "hash_max", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_HASH_MAX_MIN, - NM_BRIDGE_MULTICAST_HASH_MAX_MAX, - NM_BRIDGE_MULTICAST_HASH_MAX_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_COUNT, - "multicast_last_member_count", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_MIN, - NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_MAX, - NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL, - "multicast_last_member_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL, - "multicast_membership_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERIER, - "multicast_querier", - OPTION_TYPE_BOOL(NM_BRIDGE_MULTICAST_QUERIER_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERIER_INTERVAL, - "multicast_querier_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERY_INTERVAL, - "multicast_query_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_QUERY_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_QUERY_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_QUERY_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL, - "multicast_query_response_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, - "multicast_query_use_ifaddr", - OPTION_TYPE_BOOL(NM_BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_SNOOPING, - "multicast_snooping", - OPTION_TYPE_BOOL(NM_BRIDGE_MULTICAST_SNOOPING_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_ROUTER, - "multicast_router", - OPTION_TYPE_TOFROM(to_sysfs_multicast_router, from_sysfs_multicast_router), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT, - "multicast_startup_query_count", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_MIN, - NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_MAX, - NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL, - "multicast_startup_query_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_GROUP_ADDRESS, - "group_addr", - OPTION_TYPE_TOFROM(to_sysfs_group_address, from_sysfs_group_address), ), - OPTION(NM_SETTING_BRIDGE_VLAN_PROTOCOL, - "vlan_protocol", - OPTION_TYPE_TOFROM(to_sysfs_vlan_protocol, from_sysfs_vlan_protocol), ), - OPTION(NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, - "vlan_stats_enabled", - OPTION_TYPE_BOOL(NM_BRIDGE_VLAN_STATS_ENABLED_DEF)), - { - 0, - }}; - -static const Option slave_options[] = { - OPTION(NM_SETTING_BRIDGE_PORT_PRIORITY, - "priority", - OPTION_TYPE_INT(NM_BRIDGE_PORT_PRIORITY_MIN, - NM_BRIDGE_PORT_PRIORITY_MAX, - NM_BRIDGE_PORT_PRIORITY_DEF), - .default_if_zero = TRUE, ), - OPTION(NM_SETTING_BRIDGE_PORT_PATH_COST, - "path_cost", - OPTION_TYPE_INT(NM_BRIDGE_PORT_PATH_COST_MIN, - NM_BRIDGE_PORT_PATH_COST_MAX, - NM_BRIDGE_PORT_PATH_COST_DEF), - .default_if_zero = TRUE, ), - OPTION(NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", OPTION_TYPE_BOOL(FALSE), ), - {0}}; - -static void -commit_option(NMDevice *device, NMSetting *setting, const Option *option, gboolean slave) -{ - int ifindex = nm_device_get_ifindex(device); - nm_auto_unset_gvalue GValue val = G_VALUE_INIT; - GParamSpec * pspec; - const char * value; - char value_buf[100]; - - if (slave) - nm_assert(NM_IS_SETTING_BRIDGE_PORT(setting)); - else - nm_assert(NM_IS_SETTING_BRIDGE(setting)); - - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(setting), option->name); - nm_assert(pspec); - - g_value_init(&val, G_PARAM_SPEC_VALUE_TYPE(pspec)); - g_object_get_property((GObject *) setting, option->name, &val); - - if (option->to_sysfs) { - value = option->to_sysfs(&val); - goto out; - } - - switch (pspec->value_type) { - case G_TYPE_BOOLEAN: - value = g_value_get_boolean(&val) ? "1" : "0"; - break; - case G_TYPE_UINT64: - case G_TYPE_UINT: - { - guint64 uval; - - if (pspec->value_type == G_TYPE_UINT64) - uval = g_value_get_uint64(&val); - else - uval = (guint) g_value_get_uint(&val); - - /* zero means "unspecified" for some NM properties but isn't in the - * allowed kernel range, so reset the property to the default value. - */ - if (option->default_if_zero && uval == 0) { - if (pspec->value_type == G_TYPE_UINT64) - uval = NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(pspec); - else - uval = NM_G_PARAM_SPEC_GET_DEFAULT_UINT(pspec); - } - - /* Linux kernel bridge interfaces use 'centiseconds' for time-based values. - * In reality it's not centiseconds, but depends on HZ and USER_HZ, which - * is almost always works out to be a multiplier of 100, so we can assume - * centiseconds. See clock_t_to_jiffies(). - */ - if (option->user_hz_compensate) - uval *= 100; - - if (pspec->value_type == G_TYPE_UINT64) - nm_sprintf_buf(value_buf, "%" G_GUINT64_FORMAT, uval); - else - nm_sprintf_buf(value_buf, "%u", (guint) uval); - - value = value_buf; - } break; - case G_TYPE_STRING: - value = g_value_get_string(&val); - break; - default: - nm_assert_not_reached(); - value = NULL; - break; - } - -out: - if (!value) - return; - - if (slave) { - nm_platform_sysctl_slave_set_option(nm_device_get_platform(device), - ifindex, - option->sysname, - value); - } else { - nm_platform_sysctl_master_set_option(nm_device_get_platform(device), - ifindex, - option->sysname, - value); - } -} - -static const NMPlatformBridgeVlan ** -setting_vlans_to_platform(GPtrArray *array) -{ - NMPlatformBridgeVlan **arr; - NMPlatformBridgeVlan * p_data; - guint i; - - if (!array || !array->len) - return NULL; - - G_STATIC_ASSERT_EXPR(_nm_alignof(NMPlatformBridgeVlan *) >= _nm_alignof(NMPlatformBridgeVlan)); - arr = g_malloc((sizeof(NMPlatformBridgeVlan *) * (array->len + 1)) - + (sizeof(NMPlatformBridgeVlan) * (array->len))); - p_data = (NMPlatformBridgeVlan *) &arr[array->len + 1]; - - for (i = 0; i < array->len; i++) { - NMBridgeVlan *vlan = array->pdata[i]; - guint16 vid_start, vid_end; - - nm_bridge_vlan_get_vid_range(vlan, &vid_start, &vid_end); - - p_data[i] = (NMPlatformBridgeVlan){ - .vid_start = vid_start, - .vid_end = vid_end, - .pvid = nm_bridge_vlan_is_pvid(vlan), - .untagged = nm_bridge_vlan_is_untagged(vlan), - }; - arr[i] = &p_data[i]; - } - arr[i] = NULL; - return (const NMPlatformBridgeVlan **) arr; -} - -static void -commit_slave_options(NMDevice *device, NMSettingBridgePort *setting) -{ - const Option * option; - NMSetting * s; - gs_unref_object NMSetting *s_clear = NULL; - - if (setting) - s = NM_SETTING(setting); - else - s = s_clear = nm_setting_bridge_port_new(); - - for (option = slave_options; option->name; option++) - commit_option(device, s, option, TRUE); -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMSettingBridge *s_bridge = nm_connection_get_setting_bridge(connection); - int ifindex = nm_device_get_ifindex(device); - const Option * option; - gs_free char * stp = NULL; - int stp_value; - - if (!s_bridge) { - s_bridge = (NMSettingBridge *) nm_setting_bridge_new(); - nm_connection_add_setting(connection, (NMSetting *) s_bridge); - } - - option = master_options; - nm_assert(nm_streq(option->sysname, "stp_state")); - - stp = nm_platform_sysctl_master_get_option(nm_device_get_platform(device), - ifindex, - option->sysname); - stp_value = - _nm_utils_ascii_str_to_int64(stp, 10, option->nm_min, option->nm_max, option->nm_default); - g_object_set(s_bridge, option->name, stp_value, NULL); - option++; - - for (; option->name; option++) { - nm_auto_unset_gvalue GValue value = G_VALUE_INIT; - gs_free char * str = NULL; - GParamSpec * pspec; - - str = nm_platform_sysctl_master_get_option(nm_device_get_platform(device), - ifindex, - option->sysname); - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(s_bridge), option->name); - - if (!stp_value && option->only_with_stp) - continue; - - if (!str) { - _LOGW(LOGD_BRIDGE, "failed to read bridge setting '%s'", option->sysname); - continue; - } - - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - - if (option->from_sysfs) { - option->from_sysfs(str, &value); - goto out; - } - - switch (pspec->value_type) { - case G_TYPE_UINT64: - case G_TYPE_UINT: - { - guint64 uvalue; - - /* See comments in set_sysfs_uint() about centiseconds. */ - if (option->user_hz_compensate) { - uvalue = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min * 100, - option->nm_max * 100, - option->nm_default * 100); - uvalue /= 100; - } else { - uvalue = _nm_utils_ascii_str_to_uint64(str, - 10, - option->nm_min, - option->nm_max, - option->nm_default); - } - - if (pspec->value_type == G_TYPE_UINT64) - g_value_set_uint64(&value, uvalue); - else - g_value_set_uint(&value, (guint) uvalue); - } break; - case G_TYPE_BOOLEAN: - { - gboolean bvalue; - - bvalue = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min, - option->nm_max, - option->nm_default); - g_value_set_boolean(&value, bvalue); - } break; - case G_TYPE_STRING: - g_value_set_string(&value, str); - break; - default: - nm_assert_not_reached(); - break; - } - -out: - g_object_set_property(G_OBJECT(s_bridge), option->name, &value); - } -} - -static gboolean -master_update_slave_connection(NMDevice * device, - NMDevice * slave, - NMConnection *connection, - GError ** error) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMSettingConnection *s_con; - NMSettingBridgePort *s_port; - int ifindex_slave = nm_device_get_ifindex(slave); - const char * iface = nm_device_get_iface(device); - const Option * option; - - g_return_val_if_fail(ifindex_slave > 0, FALSE); - - s_con = nm_connection_get_setting_connection(connection); - s_port = nm_connection_get_setting_bridge_port(connection); - if (!s_port) { - s_port = (NMSettingBridgePort *) nm_setting_bridge_port_new(); - nm_connection_add_setting(connection, NM_SETTING(s_port)); - } - - for (option = slave_options; option->name; option++) { - gs_free char *str = nm_platform_sysctl_slave_get_option(nm_device_get_platform(device), - ifindex_slave, - option->sysname); - uint value; - - if (str) { - /* See comments in set_sysfs_uint() about centiseconds. */ - if (option->user_hz_compensate) { - value = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min * 100, - option->nm_max * 100, - option->nm_default * 100); - value /= 100; - } else { - value = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min, - option->nm_max, - option->nm_default); - } - g_object_set(s_port, option->name, value, NULL); - } else - _LOGW(LOGD_BRIDGE, "failed to read bridge port setting '%s'", option->sysname); - } - - g_object_set(s_con, - NM_SETTING_CONNECTION_MASTER, - iface, - NM_SETTING_CONNECTION_SLAVE_TYPE, - NM_SETTING_BRIDGE_SETTING_NAME, - NULL); - return TRUE; -} - -static gboolean -bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - gconstpointer hwaddr; - size_t length; - gboolean enabled; - guint16 pvid; - NMPlatform * plat; - int ifindex; - gs_unref_ptrarray GPtrArray *vlans = NULL; - gs_free const NMPlatformBridgeVlan **plat_vlans = NULL; - - if (self->vlan_configured) - return TRUE; - - plat = nm_device_get_platform(device); - ifindex = nm_device_get_ifindex(device); - enabled = nm_setting_bridge_get_vlan_filtering(s_bridge); - - if (!enabled) { - nm_platform_sysctl_master_set_option(plat, ifindex, "vlan_filtering", "0"); - nm_platform_sysctl_master_set_option(plat, ifindex, "default_pvid", "1"); - nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL); - return TRUE; - } - - hwaddr = nm_platform_link_get_address(plat, ifindex, &length); - g_return_val_if_fail(length == ETH_ALEN, FALSE); - if (nm_utils_hwaddr_matches(hwaddr, length, &nm_ether_addr_zero, ETH_ALEN)) { - /* We need a non-zero MAC address to set the default pvid. - * Retry later. */ - return TRUE; - } - - self->vlan_configured = TRUE; - - /* Filtering must be disabled to change the default PVID */ - if (!nm_platform_sysctl_master_set_option(plat, ifindex, "vlan_filtering", "0")) - return FALSE; - - /* Clear the default PVID so that we later can force the re-creation of - * default PVID VLANs by writing the option again. */ - if (!nm_platform_sysctl_master_set_option(plat, ifindex, "default_pvid", "0")) - return FALSE; - - /* Clear all existing VLANs */ - if (!nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL)) - return FALSE; - - /* Now set the default PVID. After this point the kernel creates - * a PVID VLAN on each port, including the bridge itself. */ - pvid = nm_setting_bridge_get_vlan_default_pvid(s_bridge); - if (pvid) { - char value[32]; - - nm_sprintf_buf(value, "%u", pvid); - if (!nm_platform_sysctl_master_set_option(plat, ifindex, "default_pvid", value)) - return FALSE; - } - - /* Create VLANs only after setting the default PVID, so that - * any PVID VLAN overrides the bridge's default PVID. */ - g_object_get(s_bridge, NM_SETTING_BRIDGE_VLANS, &vlans, NULL); - plat_vlans = setting_vlans_to_platform(vlans); - if (plat_vlans && !nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, plat_vlans)) - return FALSE; - - if (!nm_platform_sysctl_master_set_option(plat, ifindex, "vlan_filtering", "1")) - return FALSE; - - return TRUE; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMConnection *connection; - NMSetting * s_bridge; - const Option *option; - - connection = nm_device_get_applied_connection(device); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_bridge = (NMSetting *) nm_connection_get_setting_bridge(connection); - g_return_val_if_fail(s_bridge, NM_ACT_STAGE_RETURN_FAILURE); - - for (option = master_options; option->name; option++) - commit_option(device, s_bridge, option, FALSE); - - if (!bridge_set_vlan_options(device, (NMSettingBridge *) s_bridge)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static void -_bt_register_bridge_cb(GError *error, gpointer user_data) -{ - NMDeviceBridge *self; - - if (nm_utils_error_is_cancelled(error)) - return; - - self = user_data; - - g_clear_object(&self->bt_cancellable); - - if (error) { - _LOGD(LOGD_DEVICE, "bluetooth NAP server failed to register bridge: %s", error->message); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return; - } - - nm_device_activate_schedule_stage2_device_config(NM_DEVICE(self), FALSE); -} - -void -_nm_device_bridge_notify_unregister_bt_nap(NMDevice *device, const char *reason) -{ - NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); - - _LOGD(LOGD_DEVICE, - "bluetooth NAP server unregistered from bridge: %s%s", - reason, - self->bt_registered ? "" : " (was no longer registered)"); - - nm_clear_g_cancellable(&self->bt_cancellable); - - if (self->bt_registered) { - self->bt_registered = FALSE; - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); - } -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMConnection * connection; - NMSettingBluetooth *s_bt; - gs_free_error GError *error = NULL; - - connection = nm_device_get_applied_connection(device); - - s_bt = _nm_connection_get_setting_bluetooth_for_nap(connection); - if (!s_bt) - return NM_ACT_STAGE_RETURN_SUCCESS; - - if (!nm_bt_vtable_network_server) { - _LOGD(LOGD_DEVICE, "bluetooth NAP server failed because bluetooth plugin not available"); - *out_failure_reason = NM_DEVICE_STATE_REASON_BT_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (self->bt_cancellable) - return NM_ACT_STAGE_RETURN_POSTPONE; - - if (self->bt_registered) - return NM_ACT_STAGE_RETURN_POSTPONE; - - self->bt_cancellable = g_cancellable_new(); - if (!nm_bt_vtable_network_server->register_bridge(nm_bt_vtable_network_server, - nm_setting_bluetooth_get_bdaddr(s_bt), - device, - self->bt_cancellable, - _bt_register_bridge_cb, - device, - &error)) { - _LOGD(LOGD_DEVICE, "bluetooth NAP server failed to register bridge: %s", error->message); - *out_failure_reason = NM_DEVICE_STATE_REASON_BT_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - self->bt_registered = TRUE; - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); - - _LOGD(LOGD_DEVICE, - "deactivate bridge%s", - self->bt_registered ? " (registered as NAP bluetooth device)" : ""); - - self->vlan_configured = FALSE; - - nm_clear_g_cancellable(&self->bt_cancellable); - - if (self->bt_registered) { - self->bt_registered = FALSE; - nm_bt_vtable_network_server->unregister_bridge(nm_bt_vtable_network_server, device); - } -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMConnection * master_connection; - NMSettingBridge * s_bridge; - NMSettingBridgePort *s_port; - - if (configure) { - if (!nm_platform_link_enslave(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - nm_device_get_ip_ifindex(slave))) - return FALSE; - - master_connection = nm_device_get_applied_connection(device); - nm_assert(master_connection); - s_bridge = nm_connection_get_setting_bridge(master_connection); - nm_assert(s_bridge); - s_port = nm_connection_get_setting_bridge_port(connection); - - bridge_set_vlan_options(device, s_bridge); - - if (nm_setting_bridge_get_vlan_filtering(s_bridge)) { - gs_free const NMPlatformBridgeVlan **plat_vlans = NULL; - gs_unref_ptrarray GPtrArray *vlans = NULL; - - if (s_port) - g_object_get(s_port, NM_SETTING_BRIDGE_PORT_VLANS, &vlans, NULL); - - plat_vlans = setting_vlans_to_platform(vlans); - - /* Since the link was just enslaved, there are no existing VLANs - * (except for the default one) and so there's no need to flush. */ - - if (plat_vlans - && !nm_platform_link_set_bridge_vlans(nm_device_get_platform(slave), - nm_device_get_ifindex(slave), - TRUE, - plat_vlans)) - return FALSE; - } - - commit_slave_options(slave, s_port); - - _LOGI(LOGD_BRIDGE, "attached bridge port %s", nm_device_get_ip_iface(slave)); - } else { - _LOGI(LOGD_BRIDGE, "bridge port %s was attached", nm_device_get_ip_iface(slave)); - } - - return TRUE; -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{ - NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); - gboolean success; - int ifindex_slave; - int ifindex; - - if (configure) { - ifindex = nm_device_get_ifindex(device); - if (ifindex <= 0 || !nm_platform_link_get(nm_device_get_platform(device), ifindex)) - configure = FALSE; - } - - ifindex_slave = nm_device_get_ip_ifindex(slave); - - if (ifindex_slave <= 0) { - _LOGD(LOGD_TEAM, "bond slave %s is already released", nm_device_get_ip_iface(slave)); - return; - } - - if (configure) { - success = nm_platform_link_release(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - ifindex_slave); - - if (success) { - _LOGI(LOGD_BRIDGE, "detached bridge port %s", nm_device_get_ip_iface(slave)); - } else { - _LOGW(LOGD_BRIDGE, "failed to detach bridge port %s", nm_device_get_ip_iface(slave)); - } - } else { - _LOGI(LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface(slave)); - } -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - NMSettingWired * s_wired; - NMSettingBridge * s_bridge; - const char * iface = nm_device_get_iface(device); - const char * hwaddr; - gs_free char * hwaddr_cloned = NULL; - guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX]; - NMPlatformLnkBridge props; - int r; - guint32 mtu = 0; - - nm_assert(iface); - - s_bridge = nm_connection_get_setting_bridge(connection); - nm_assert(s_bridge); - - s_wired = nm_connection_get_setting_wired(connection); - if (s_wired) - mtu = nm_setting_wired_get_mtu(s_wired); - - hwaddr = nm_setting_bridge_get_mac_address(s_bridge); - if (!hwaddr - && nm_device_hw_addr_get_cloned(device, connection, FALSE, &hwaddr_cloned, NULL, NULL)) { - /* FIXME: we set the MAC address when creating the interface, while the - * NMDevice is still unrealized. As we afterwards realize the device, it - * forgets the parameters for the cloned MAC address, and in stage 1 - * it might create a different MAC address. That should be fixed by - * better handling device realization. */ - hwaddr = hwaddr_cloned; - } - - if (hwaddr) { - if (!nm_utils_hwaddr_aton(hwaddr, mac_address, ETH_ALEN)) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Invalid hardware address '%s'", - hwaddr); - g_return_val_if_reached(FALSE); - } - } - - props = (NMPlatformLnkBridge){ - .forward_delay = _DEFAULT_IF_ZERO(nm_setting_bridge_get_forward_delay(s_bridge) * 100u, - NM_BRIDGE_FORWARD_DELAY_DEF_SYS), - .hello_time = _DEFAULT_IF_ZERO(nm_setting_bridge_get_hello_time(s_bridge) * 100u, - NM_BRIDGE_HELLO_TIME_DEF_SYS), - .max_age = _DEFAULT_IF_ZERO(nm_setting_bridge_get_max_age(s_bridge) * 100u, - NM_BRIDGE_MAX_AGE_DEF_SYS), - .ageing_time = _DEFAULT_IF_ZERO(nm_setting_bridge_get_ageing_time(s_bridge) * 100u, - NM_BRIDGE_AGEING_TIME_DEF_SYS), - .stp_state = nm_setting_bridge_get_stp(s_bridge), - .priority = nm_setting_bridge_get_priority(s_bridge), - .vlan_protocol = to_sysfs_vlan_protocol_sys(nm_setting_bridge_get_vlan_protocol(s_bridge)), - .vlan_stats_enabled = nm_setting_bridge_get_vlan_stats_enabled(s_bridge), - .group_fwd_mask = nm_setting_bridge_get_group_forward_mask(s_bridge), - .mcast_snooping = nm_setting_bridge_get_multicast_snooping(s_bridge), - .mcast_router = - to_sysfs_multicast_router_sys(nm_setting_bridge_get_multicast_router(s_bridge)), - .mcast_query_use_ifaddr = nm_setting_bridge_get_multicast_query_use_ifaddr(s_bridge), - .mcast_querier = nm_setting_bridge_get_multicast_querier(s_bridge), - .mcast_hash_max = nm_setting_bridge_get_multicast_hash_max(s_bridge), - .mcast_last_member_count = nm_setting_bridge_get_multicast_last_member_count(s_bridge), - .mcast_startup_query_count = nm_setting_bridge_get_multicast_startup_query_count(s_bridge), - .mcast_last_member_interval = - nm_setting_bridge_get_multicast_last_member_interval(s_bridge), - .mcast_membership_interval = nm_setting_bridge_get_multicast_membership_interval(s_bridge), - .mcast_querier_interval = nm_setting_bridge_get_multicast_querier_interval(s_bridge), - .mcast_query_interval = nm_setting_bridge_get_multicast_query_interval(s_bridge), - .mcast_query_response_interval = - nm_setting_bridge_get_multicast_query_response_interval(s_bridge), - .mcast_startup_query_interval = - nm_setting_bridge_get_multicast_startup_query_interval(s_bridge), - }; - - to_sysfs_group_address_sys(nm_setting_bridge_get_group_address(s_bridge), &props.group_addr); - - /* If mtu != 0, we set the MTU of the new bridge at creation time. However, kernel will still - * automatically adjust the MTU of the bridge based on the minimum of the slave's MTU. - * We don't want this automatism as the user asked for a fixed MTU. - * - * To workaround this behavior of kernel, we will later toggle the MTU twice. See - * NMDeviceClass.mtu_force_set. */ - r = nm_platform_link_bridge_add(nm_device_get_platform(device), - iface, - hwaddr ? mac_address : NULL, - hwaddr ? ETH_ALEN : 0, - mtu, - &props, - out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create bridge interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -nm_device_bridge_init(NMDeviceBridge *self) -{ - nm_assert(nm_device_is_master(NM_DEVICE(self))); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_bridge = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_BRIDGE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Slaves", - "ao", - NM_DEVICE_SLAVES), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_bridge_class_init(NMDeviceBridgeClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_bridge); - - device_class->connection_type_supported = NM_SETTING_BRIDGE_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_BRIDGE); - - device_class->is_master = TRUE; - device_class->mtu_force_set = TRUE; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - - device_class->update_connection = update_connection; - device_class->master_update_slave_connection = master_update_slave_connection; - - device_class->create_and_realize = create_and_realize; - device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->deactivate = deactivate; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; -} - -/*****************************************************************************/ - -#define NM_TYPE_BRIDGE_DEVICE_FACTORY (nm_bridge_device_factory_get_type()) -#define NM_BRIDGE_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_BRIDGE_DEVICE_FACTORY, NMBridgeDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_BRIDGE, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_DRIVER, - "bridge", - NM_DEVICE_TYPE_DESC, - "Bridge", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_BRIDGE, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_BRIDGE, - NULL); -} - -static gboolean -match_connection(NMDeviceFactory *factory, NMConnection *connection) -{ - const char *type = nm_connection_get_connection_type(connection); - - if (nm_streq(type, NM_SETTING_BRIDGE_SETTING_NAME)) - return TRUE; - - nm_assert(nm_streq(type, NM_SETTING_BLUETOOTH_SETTING_NAME)); - - if (!_nm_connection_get_setting_bluetooth_for_nap(connection)) - return FALSE; - - if (!g_type_from_name("NMBluezManager")) { - /* bluetooth NAP connections are handled by bridge factory. However, - * it needs help from the bluetooth plugin, so if the plugin is not loaded, - * we claim not to support it. */ - return FALSE; - } - - return TRUE; -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - BRIDGE, - Bridge, - bridge, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_BRIDGE) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_BRIDGE_SETTING_NAME, - NM_SETTING_BLUETOOTH_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->match_connection = match_connection;); diff --git a/src/devices/nm-device-bridge.h b/src/devices/nm-device-bridge.h deleted file mode 100644 index c942813e..00000000 --- a/src/devices/nm-device-bridge.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2012 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_BRIDGE_H__ -#define __NETWORKMANAGER_DEVICE_BRIDGE_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_BRIDGE (nm_device_bridge_get_type()) -#define NM_DEVICE_BRIDGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridge)) -#define NM_DEVICE_BRIDGE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridgeClass)) -#define NM_IS_DEVICE_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_BRIDGE)) -#define NM_IS_DEVICE_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_BRIDGE)) -#define NM_DEVICE_BRIDGE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridgeClass)) - -typedef struct _NMDeviceBridge NMDeviceBridge; -typedef struct _NMDeviceBridgeClass NMDeviceBridgeClass; - -GType nm_device_bridge_get_type(void); - -extern const NMBtVTableNetworkServer *nm_bt_vtable_network_server; - -void _nm_device_bridge_notify_unregister_bt_nap(NMDevice *device, const char *reason); - -#endif /* __NETWORKMANAGER_DEVICE_BRIDGE_H__ */ diff --git a/src/devices/nm-device-dummy.c b/src/devices/nm-device-dummy.c deleted file mode 100644 index 4f6b8cc2..00000000 --- a/src/devices/nm-device-dummy.c +++ /dev/null @@ -1,183 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-dummy.h" - -#include <stdlib.h> -#include <sys/types.h> - -#include "nm-act-request.h" -#include "nm-device-private.h" -#include "nm-ip4-config.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-setting-dummy.h" -#include "nm-core-internal.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceDummy); - -/*****************************************************************************/ - -struct _NMDeviceDummy { - NMDevice parent; -}; - -struct _NMDeviceDummyClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceDummy, nm_device_dummy, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingDummy *s_dummy; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_DUMMY_SETTING_NAME, - existing_connections, - NULL, - _("Dummy connection"), - NULL, - NULL, - TRUE); - - s_dummy = nm_connection_get_setting_dummy(connection); - if (!s_dummy) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'dummy' setting is required."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMSettingDummy *s_dummy = nm_connection_get_setting_dummy(connection); - - if (!s_dummy) { - s_dummy = (NMSettingDummy *) nm_setting_dummy_new(); - nm_connection_add_setting(connection, (NMSetting *) s_dummy); - } -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char * iface = nm_device_get_iface(device); - NMSettingDummy *s_dummy; - int r; - - s_dummy = nm_connection_get_setting_dummy(connection); - g_assert(s_dummy); - - r = nm_platform_link_dummy_add(nm_device_get_platform(device), iface, out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create dummy interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -nm_device_dummy_init(NMDeviceDummy *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_dummy = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_DUMMY, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_dummy_class_init(NMDeviceDummyClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_dummy); - - device_class->connection_type_supported = NM_SETTING_DUMMY_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_DUMMY_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_DUMMY); - - device_class->complete_connection = complete_connection; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->update_connection = update_connection; - device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; -} - -/*****************************************************************************/ - -#define NM_TYPE_DUMMY_DEVICE_FACTORY (nm_dummy_device_factory_get_type()) -#define NM_DUMMY_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DUMMY_DEVICE_FACTORY, NMDummyDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_DUMMY, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Dummy", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_DUMMY, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_DUMMY, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - DUMMY, - Dummy, - dummy, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_DUMMY) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_DUMMY_SETTING_NAME), - factory_class->create_device = create_device;); diff --git a/src/devices/nm-device-dummy.h b/src/devices/nm-device-dummy.h deleted file mode 100644 index b3670ef9..00000000 --- a/src/devices/nm-device-dummy.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_DUMMY_H__ -#define __NETWORKMANAGER_DEVICE_DUMMY_H__ - -#include "nm-device-generic.h" - -#define NM_TYPE_DEVICE_DUMMY (nm_device_dummy_get_type()) -#define NM_DEVICE_DUMMY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_DUMMY, NMDeviceDummy)) -#define NM_DEVICE_DUMMY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_DUMMY, NMDeviceDummyClass)) -#define NM_IS_DEVICE_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_DUMMY)) -#define NM_IS_DEVICE_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_DUMMY)) -#define NM_DEVICE_DUMMY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_DUMMY, NMDeviceDummyClass)) - -typedef struct _NMDeviceDummy NMDeviceDummy; -typedef struct _NMDeviceDummyClass NMDeviceDummyClass; - -GType nm_device_dummy_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_DUMMY_H__ */ diff --git a/src/devices/nm-device-ethernet-utils.c b/src/devices/nm-device-ethernet-utils.c deleted file mode 100644 index 5c35db83..00000000 --- a/src/devices/nm-device-ethernet-utils.c +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ethernet-utils.h" - -#include "settings/nm-settings-connection.h" - -char * -nm_device_ethernet_utils_get_default_wired_name(GHashTable *existing_ids) -{ - char *temp; - int i; - - /* Find the next available unique connection name */ - for (i = 1; i < G_MAXINT; i++) { - temp = g_strdup_printf(_("Wired connection %d"), i); - if (!existing_ids || !g_hash_table_contains(existing_ids, temp)) - return temp; - g_free(temp); - } - return NULL; -} diff --git a/src/devices/nm-device-ethernet-utils.h b/src/devices/nm-device-ethernet-utils.h deleted file mode 100644 index d67b9fa1..00000000 --- a/src/devices/nm-device-ethernet-utils.h +++ /dev/null @@ -1,11 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_ETHERNET_UTILS_H__ -#define __NETWORKMANAGER_DEVICE_ETHERNET_UTILS_H__ - -char *nm_device_ethernet_utils_get_default_wired_name(GHashTable *existing_ids); - -#endif /* NETWORKMANAGER_DEVICE_ETHERNET_UTILS_H */ diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c deleted file mode 100644 index 2569c426..00000000 --- a/src/devices/nm-device-ethernet.c +++ /dev/null @@ -1,2059 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2014 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ethernet.h" - -#include <netinet/in.h> -#include <stdlib.h> -#include <unistd.h> -#include <libudev.h> - -#include "nm-device-private.h" -#include "nm-act-request.h" -#include "nm-ip4-config.h" -#include "NetworkManagerUtils.h" -#include "supplicant/nm-supplicant-manager.h" -#include "supplicant/nm-supplicant-interface.h" -#include "supplicant/nm-supplicant-config.h" -#include "ppp/nm-ppp-manager.h" -#include "ppp/nm-ppp-manager-call.h" -#include "ppp/nm-ppp-status.h" -#include "platform/nm-platform.h" -#include "platform/nm-platform-utils.h" -#include "nm-dcb.h" -#include "settings/nm-settings-connection.h" -#include "nm-config.h" -#include "nm-device-ethernet-utils.h" -#include "settings/nm-settings.h" -#include "nm-device-factory.h" -#include "nm-core-internal.h" -#include "NetworkManagerUtils.h" -#include "nm-udev-aux/nm-udev-utils.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceEthernet); - -/*****************************************************************************/ - -#define PPPOE_RECONNECT_DELAY 7 -#define PPPOE_ENCAP_OVERHEAD 8 /* 2 bytes for PPP, 6 for PPPoE */ - -#define SUPPLICANT_LNK_TIMEOUT_SEC 15 - -/*****************************************************************************/ - -typedef enum { - DCB_WAIT_UNKNOWN = 0, - /* Ensure carrier is up before enabling DCB */ - DCB_WAIT_CARRIER_PREENABLE_UP, - /* Wait for carrier down when device starts enabling */ - DCB_WAIT_CARRIER_PRECONFIG_DOWN, - /* Wait for carrier up when device has finished enabling */ - DCB_WAIT_CARRIER_PRECONFIG_UP, - /* Wait carrier down when device starts configuring */ - DCB_WAIT_CARRIER_POSTCONFIG_DOWN, - /* Wait carrier up when device has finished configuring */ - DCB_WAIT_CARRIER_POSTCONFIG_UP, -} DcbWait; - -typedef struct _NMDeviceEthernetPrivate { - /* s390 */ - char * subchan1; - char * subchan2; - char * subchan3; - char * subchannels; /* Composite used for checking unmanaged specs */ - char ** subchannels_dbus; /* Array exported on D-Bus */ - char * s390_nettype; - GHashTable *s390_options; - - guint32 speed; - gulong carrier_id; - - struct { - NMSupplicantManager * mgr; - NMSupplMgrCreateIfaceHandle *create_handle; - NMSupplicantInterface * iface; - - gulong iface_state_id; - gulong auth_state_id; - - guint con_timeout_id; - - guint lnk_timeout_id; - - bool is_associated : 1; - } supplicant; - - NMActRequestGetSecretsCallId *wired_secrets_id; - - /* PPPoE */ - NMPPPManager *ppp_manager; - gint32 last_pppoe_time; - guint pppoe_wait_id; - - /* DCB */ - DcbWait dcb_wait; - guint dcb_timeout_id; - - guint32 ethtool_prev_speed; - - NMPlatformLinkDuplexType ethtool_prev_duplex : 3; - - bool dcb_handle_carrier_changes : 1; - - bool ethtool_prev_set : 1; - bool ethtool_prev_autoneg : 1; - -} NMDeviceEthernetPrivate; - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceEthernet, PROP_SPEED, PROP_S390_SUBCHANNELS, ); - -/*****************************************************************************/ - -G_DEFINE_TYPE(NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE) - -#define NM_DEVICE_ETHERNET_GET_PRIVATE(self) \ - _NM_GET_PRIVATE_PTR(self, NMDeviceEthernet, NM_IS_DEVICE_ETHERNET, NMDevice) - -/*****************************************************************************/ - -static void wired_secrets_cancel(NMDeviceEthernet *self); - -/*****************************************************************************/ - -static char * -get_link_basename(const char *parent_path, const char *name, GError **error) -{ - char *link_dest, *path; - char *result = NULL; - - path = g_strdup_printf("%s/%s", parent_path, name); - link_dest = g_file_read_link(path, error); - if (link_dest) { - result = g_path_get_basename(link_dest); - g_free(link_dest); - } - g_free(path); - return result; -} - -static void -_update_s390_subchannels(NMDeviceEthernet *self) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - struct udev_device * dev = NULL; - struct udev_device * parent = NULL; - const char * parent_path, *item; - int ifindex; - GDir * dir; - GError * error = NULL; - - if (priv->subchannels) { - /* only read the subchannels once. For one, we don't expect them to change - * on multiple invocations. Second, we didn't implement proper reloading. - * Proper reloading might also be complicated, because the subchannels are - * used to match on devices based on a device-spec. Thus, it's not clear - * what it means to change afterwards. */ - return; - } - - ifindex = nm_device_get_ifindex((NMDevice *) self); - dev = nm_platform_link_get_udev_device(nm_device_get_platform(NM_DEVICE(self)), ifindex); - if (!dev) - return; - - /* Try for the "ccwgroup" parent */ - parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccwgroup", NULL); - if (!parent) { - /* FIXME: whatever 'lcs' devices' subsystem is here... */ - - /* Not an s390 device */ - return; - } - - parent_path = udev_device_get_syspath(parent); - dir = g_dir_open(parent_path, 0, &error); - if (!dir) { - _LOGW(LOGD_DEVICE | LOGD_PLATFORM, - "update-s390: failed to open directory '%s': %s", - parent_path, - error->message); - g_clear_error(&error); - return; - } - - while ((item = g_dir_read_name(dir))) { - if (!strcmp(item, "cdev0")) { - priv->subchan1 = get_link_basename(parent_path, "cdev0", &error); - } else if (!strcmp(item, "cdev1")) { - priv->subchan2 = get_link_basename(parent_path, "cdev1", &error); - } else if (!strcmp(item, "cdev2")) { - priv->subchan3 = get_link_basename(parent_path, "cdev2", &error); - } else if (!strcmp(item, "driver")) { - priv->s390_nettype = get_link_basename(parent_path, "driver", &error); - } else if (!strcmp(item, "layer2") || !strcmp(item, "portname") - || !strcmp(item, "portno")) { - gs_free char *path = NULL, *value = NULL; - - path = g_strdup_printf("%s/%s", parent_path, item); - value = nm_platform_sysctl_get(nm_device_get_platform(NM_DEVICE(self)), - NMP_SYSCTL_PATHID_ABSOLUTE(path)); - - if (!strcmp(item, "portname") && !g_strcmp0(value, "no portname required")) { - /* Do nothing */ - } else if (value && *value) { - g_hash_table_insert(priv->s390_options, g_strdup(item), value); - value = NULL; - } else - _LOGW(LOGD_DEVICE | LOGD_PLATFORM, "update-s390: error reading %s", path); - } - - if (error) { - _LOGW(LOGD_DEVICE | LOGD_PLATFORM, - "update-s390: failed reading sysfs for %s (%s)", - item, - error->message); - g_clear_error(&error); - } - } - - g_dir_close(dir); - - if (priv->subchan3) { - priv->subchannels = - g_strdup_printf("%s,%s,%s", priv->subchan1, priv->subchan2, priv->subchan3); - } else if (priv->subchan2) { - priv->subchannels = g_strdup_printf("%s,%s", priv->subchan1, priv->subchan2); - } else - priv->subchannels = g_strdup(priv->subchan1); - - priv->subchannels_dbus = g_new(char *, 3 + 1); - priv->subchannels_dbus[0] = g_strdup(priv->subchan1); - priv->subchannels_dbus[1] = g_strdup(priv->subchan2); - priv->subchannels_dbus[2] = g_strdup(priv->subchan3); - priv->subchannels_dbus[3] = NULL; - - _LOGI(LOGD_DEVICE | LOGD_PLATFORM, - "update-s390: found s390 '%s' subchannels [%s]", - nm_device_get_driver((NMDevice *) self) ?: "(unknown driver)", - priv->subchannels); - - _notify(self, PROP_S390_SUBCHANNELS); -} - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - if (new_state > NM_DEVICE_STATE_ACTIVATED) - wired_secrets_cancel(NM_DEVICE_ETHERNET(device)); -} - -static void -nm_device_ethernet_init(NMDeviceEthernet *self) -{ - NMDeviceEthernetPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetPrivate); - self->_priv = priv; - - priv->s390_options = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET(device); - int ifindex = nm_device_get_ifindex(device); - - if (ifindex > 0) { - if (nm_platform_link_supports_carrier_detect(nm_device_get_platform(device), ifindex)) - return NM_DEVICE_CAP_CARRIER_DETECT; - else { - _LOGI(LOGD_PLATFORM, - "driver '%s' does not support carrier detection.", - nm_device_get_driver(device)); - } - } - - return NM_DEVICE_CAP_NONE; -} - -static guint32 -_subchannels_count_num(const char *const *array) -{ - int i; - - if (!array) - return 0; - for (i = 0; array[i]; i++) - /* NOP */; - return i; -} - -static gboolean -match_subchans(NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_mac) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - const char *const * subchans; - guint32 num1, num2; - int i; - - *try_mac = TRUE; - - subchans = nm_setting_wired_get_s390_subchannels(s_wired); - num1 = _subchannels_count_num(subchans); - num2 = _subchannels_count_num((const char *const *) priv->subchannels_dbus); - /* connection has no subchannels */ - if (num1 == 0) - return TRUE; - /* connection requires subchannels but the device has none */ - if (num2 == 0) - return FALSE; - /* number of subchannels differ */ - if (num1 != num2) - return FALSE; - - /* Make sure each subchannel in the connection is a subchannel of this device */ - for (i = 0; subchans[i]; i++) { - const char *candidate = subchans[i]; - - if ((priv->subchan1 && !strcmp(priv->subchan1, candidate)) - || (priv->subchan2 && !strcmp(priv->subchan2, candidate)) - || (priv->subchan3 && !strcmp(priv->subchan3, candidate))) - continue; - - return FALSE; /* a subchannel was not found */ - } - - *try_mac = FALSE; - return TRUE; -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET(device); - NMSettingWired * s_wired; - - if (!NM_DEVICE_CLASS(nm_device_ethernet_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (nm_connection_is_type(connection, NM_SETTING_PPPOE_SETTING_NAME)) { - s_wired = nm_connection_get_setting_wired(connection); - } else { - s_wired = - _nm_connection_check_main_setting(connection, NM_SETTING_WIRED_SETTING_NAME, error); - if (!s_wired) - return FALSE; - } - - if (s_wired) { - const char * mac, *perm_hw_addr; - gboolean try_mac = TRUE; - const char *const *mac_blacklist; - int i; - - if (!match_subchans(self, s_wired, &try_mac)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "s390 subchannels don't match"); - return FALSE; - } - - perm_hw_addr = nm_device_get_permanent_hw_address(device); - mac = nm_setting_wired_get_mac_address(s_wired); - if (perm_hw_addr) { - if (try_mac && mac && !nm_utils_hwaddr_matches(mac, -1, perm_hw_addr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "permanent MAC address doesn't match"); - return FALSE; - } - - /* Check for MAC address blacklist */ - mac_blacklist = nm_setting_wired_get_mac_address_blacklist(s_wired); - for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid(mac_blacklist[i], ETH_ALEN)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "invalid MAC in blacklist"); - return FALSE; - } - - if (nm_utils_hwaddr_matches(mac_blacklist[i], -1, perm_hw_addr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "permanent MAC address of device blacklisted"); - return FALSE; - } - } - } else if (mac) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has no permanent MAC address to match"); - return FALSE; - } - } - - return TRUE; -} - -/*****************************************************************************/ -/* 802.1X */ - -static void -supplicant_interface_release(NMDeviceEthernet *self) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - nm_clear_pointer(&priv->supplicant.create_handle, - nm_supplicant_manager_create_interface_cancel); - - nm_clear_g_source(&priv->supplicant.lnk_timeout_id); - nm_clear_g_source(&priv->supplicant.con_timeout_id); - nm_clear_g_signal_handler(priv->supplicant.iface, &priv->supplicant.iface_state_id); - nm_clear_g_signal_handler(priv->supplicant.iface, &priv->supplicant.auth_state_id); - - if (priv->supplicant.iface) { - nm_supplicant_interface_disconnect(priv->supplicant.iface); - g_clear_object(&priv->supplicant.iface); - } -} - -static void -supplicant_auth_state_changed(NMSupplicantInterface *iface, - GParamSpec * pspec, - NMDeviceEthernet * self) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMSupplicantAuthState state; - - state = nm_supplicant_interface_get_auth_state(priv->supplicant.iface); - _LOGD(LOGD_CORE, "supplicant auth state changed to %u", (unsigned) state); - - if (state == NM_SUPPLICANT_AUTH_STATE_SUCCESS) { - nm_clear_g_signal_handler(priv->supplicant.iface, &priv->supplicant.iface_state_id); - nm_device_update_dynamic_ip_setup(NM_DEVICE(self)); - } -} - -static gboolean -wired_auth_is_optional(NMDeviceEthernet *self) -{ - NMSetting8021x *s_8021x; - - s_8021x = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_802_1X); - g_return_val_if_fail(s_8021x, FALSE); - return nm_setting_802_1x_get_optional(s_8021x); -} - -static void -wired_auth_cond_fail(NMDeviceEthernet *self, NMDeviceStateReason reason) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - - if (wired_auth_is_optional(self)) { - _LOGI( - LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) 802.1X authentication is optional, continuing after a failure"); - if (NM_IN_SET(nm_device_get_state(device), - NM_DEVICE_STATE_CONFIG, - NM_DEVICE_STATE_NEED_AUTH)) - nm_device_activate_schedule_stage3_ip_config_start(device); - - if (!priv->supplicant.auth_state_id) { - priv->supplicant.auth_state_id = - g_signal_connect(priv->supplicant.iface, - "notify::" NM_SUPPLICANT_INTERFACE_AUTH_STATE, - G_CALLBACK(supplicant_auth_state_changed), - self); - } - return; - } - - supplicant_interface_release(self); - nm_device_state_changed(NM_DEVICE(self), NM_DEVICE_STATE_FAILED, reason); -} - -static void -wired_secrets_cb(NMActRequest * req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * connection, - GError * error, - gpointer user_data) -{ - NMDeviceEthernet * self = user_data; - NMDevice * device = user_data; - NMDeviceEthernetPrivate *priv; - - g_return_if_fail(NM_IS_DEVICE_ETHERNET(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - g_return_if_fail(priv->wired_secrets_id == call_id); - - priv->wired_secrets_id = NULL; - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - g_return_if_fail(req == nm_device_get_act_request(device)); - g_return_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_NEED_AUTH); - g_return_if_fail(nm_act_request_get_settings_connection(req) == connection); - - if (error) { - _LOGW(LOGD_ETHER, "%s", error->message); - wired_auth_cond_fail(self, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - supplicant_interface_release(self); - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -wired_secrets_cancel(NMDeviceEthernet *self) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - if (priv->wired_secrets_id) - nm_act_request_cancel_secrets(NULL, priv->wired_secrets_id); - nm_assert(!priv->wired_secrets_id); -} - -static void -wired_secrets_get_secrets(NMDeviceEthernet * self, - const char * setting_name, - NMSecretAgentGetSecretsFlags flags) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMActRequest * req; - - wired_secrets_cancel(self); - - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv->wired_secrets_id = - nm_act_request_get_secrets(req, TRUE, setting_name, flags, NULL, wired_secrets_cb, self); - g_return_if_fail(priv->wired_secrets_id); -} - -static gboolean -supplicant_lnk_timeout_cb(gpointer user_data) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(user_data); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMActRequest * req; - NMConnection * applied_connection; - const char * setting_name; - - priv->supplicant.lnk_timeout_id = 0; - - req = nm_device_get_act_request(device); - - if (nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) { - wired_auth_cond_fail(self, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); - return G_SOURCE_REMOVE; - } - - /* Disconnect event during initial authentication and credentials - * ARE checked - we are likely to have wrong key. Ask the user for - * another one. - */ - if (nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG) - goto time_out; - - nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(req)); - - applied_connection = nm_act_request_get_applied_connection(req); - setting_name = nm_connection_need_secrets(applied_connection, NULL); - if (!setting_name) - goto time_out; - - _LOGI(LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) disconnected during authentication, asking for new key."); - if (!wired_auth_is_optional(self)) - supplicant_interface_release(self); - - nm_device_state_changed(device, - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - wired_secrets_get_secrets(self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); - - return G_SOURCE_REMOVE; - -time_out: - _LOGW(LOGD_DEVICE | LOGD_ETHER, "link timed out."); - wired_auth_cond_fail(self, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - - return G_SOURCE_REMOVE; -} - -static NMSupplicantConfig * -build_supplicant_config(NMDeviceEthernet *self, GError **error) -{ - const char * con_uuid; - NMSupplicantConfig *config = NULL; - NMSetting8021x * security; - NMConnection * connection; - guint32 mtu; - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - - g_return_val_if_fail(connection, NULL); - - con_uuid = nm_connection_get_uuid(connection); - mtu = nm_platform_link_get_mtu(nm_device_get_platform(NM_DEVICE(self)), - nm_device_get_ifindex(NM_DEVICE(self))); - - config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE); - - security = nm_connection_get_setting_802_1x(connection); - if (!nm_supplicant_config_add_setting_8021x(config, security, con_uuid, mtu, TRUE, error)) { - g_prefix_error(error, "802-1x-setting: "); - g_clear_object(&config); - } - - return config; -} - -static void -supplicant_iface_state_is_completed(NMDeviceEthernet *self, NMSupplicantInterfaceState state) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - if (state == NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) { - nm_clear_g_source(&priv->supplicant.lnk_timeout_id); - nm_clear_g_source(&priv->supplicant.con_timeout_id); - - /* If this is the initial association during device activation, - * schedule the next activation stage. - */ - if (nm_device_get_state(NM_DEVICE(self)) == NM_DEVICE_STATE_CONFIG) { - _LOGI(LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) Stage 2 of 5 (Device Configure) successful."); - nm_device_activate_schedule_stage3_ip_config_start(NM_DEVICE(self)); - } - return; - } - - if (!priv->supplicant.lnk_timeout_id && !priv->supplicant.con_timeout_id) - priv->supplicant.lnk_timeout_id = - g_timeout_add_seconds(SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self); -} - -static void -supplicant_iface_assoc_cb(NMSupplicantInterface *iface, GError *error, gpointer user_data) -{ - NMDeviceEthernet * self; - NMDeviceEthernetPrivate *priv; - - if (nm_utils_error_is_cancelled_or_disposing(error)) - return; - - self = NM_DEVICE_ETHERNET(user_data); - priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - if (error) { - supplicant_interface_release(self); - nm_device_queue_state(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - return; - } - - nm_assert(!priv->supplicant.lnk_timeout_id); - nm_assert(!priv->supplicant.is_associated); - - priv->supplicant.is_associated = TRUE; - supplicant_iface_state_is_completed(self, - nm_supplicant_interface_get_state(priv->supplicant.iface)); -} - -static gboolean -supplicant_iface_start(NMDeviceEthernet *self) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - gs_unref_object NMSupplicantConfig *config = NULL; - gs_free_error GError *error = NULL; - - config = build_supplicant_config(self, &error); - if (!config) { - _LOGE(LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) couldn't build security configuration: %s", - error->message); - supplicant_interface_release(self); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - return FALSE; - } - - nm_supplicant_interface_disconnect(priv->supplicant.iface); - nm_supplicant_interface_assoc(priv->supplicant.iface, config, supplicant_iface_assoc_cb, self); - return TRUE; -} - -static void -supplicant_iface_state_cb(NMSupplicantInterface *iface, - int new_state_i, - int old_state_i, - int disconnect_reason, - gpointer user_data) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(user_data); - NMDeviceEthernetPrivate * priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMSupplicantInterfaceState new_state = new_state_i; - NMSupplicantInterfaceState old_state = old_state_i; - - _LOGI(LOGD_DEVICE | LOGD_ETHER, - "supplicant interface state: %s -> %s", - nm_supplicant_interface_state_to_string(old_state), - nm_supplicant_interface_state_to_string(new_state)); - - if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - supplicant_interface_release(self); - wired_auth_cond_fail(self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return; - } - - if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { - if (!supplicant_iface_start(self)) - return; - } - - if (priv->supplicant.is_associated) - supplicant_iface_state_is_completed(self, new_state); -} - -static gboolean -handle_auth_or_fail(NMDeviceEthernet *self, NMActRequest *req, gboolean new_secrets) -{ - const char * setting_name; - NMConnection *applied_connection; - - if (!nm_device_auth_retries_try_next(NM_DEVICE(self))) - return FALSE; - - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_NONE); - - nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(req)); - - applied_connection = nm_act_request_get_applied_connection(req); - setting_name = nm_connection_need_secrets(applied_connection, NULL); - if (!setting_name) { - _LOGI(LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return FALSE; - } - - _LOGI(LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) asking for new secrets"); - - /* Don't tear down supplicant if the authentication is optional - * because in case of a failure in getting new secrets we want to - * keep the supplicant alive. - */ - if (!wired_auth_is_optional(self)) - supplicant_interface_release(self); - - wired_secrets_get_secrets( - self, - setting_name, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION - | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0)); - return TRUE; -} - -static gboolean -supplicant_connection_timeout_cb(gpointer user_data) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(user_data); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMActRequest * req; - NMSettingsConnection * connection; - guint64 timestamp = 0; - gboolean new_secrets = TRUE; - - priv->supplicant.con_timeout_id = 0; - - /* Authentication failed; either driver problems, the encryption key is - * wrong, the passwords or certificates were wrong or the Ethernet switch's - * port is not configured for 802.1x. */ - _LOGW(LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) association took too long."); - - req = nm_device_get_act_request(device); - connection = nm_act_request_get_settings_connection(req); - - /* Ask for new secrets only if we've never activated this connection - * before. If we've connected before, don't bother the user with dialogs, - * just retry or fail, and if we never connect the user can fix the - * password somewhere else. */ - if (nm_settings_connection_get_timestamp(connection, ×tamp)) - new_secrets = !timestamp; - - if (!handle_auth_or_fail(self, req, new_secrets)) { - wired_auth_cond_fail(self, NM_DEVICE_STATE_REASON_NO_SECRETS); - return G_SOURCE_REMOVE; - } - - if (!priv->supplicant.lnk_timeout_id && priv->supplicant.iface) { - NMSupplicantInterfaceState state; - - state = nm_supplicant_interface_get_state(priv->supplicant.iface); - if (state != NM_SUPPLICANT_INTERFACE_STATE_COMPLETED - && nm_supplicant_interface_state_is_operational(state)) - priv->supplicant.lnk_timeout_id = - g_timeout_add_seconds(SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self); - } - - return G_SOURCE_REMOVE; -} - -static void -supplicant_interface_create_cb(NMSupplicantManager * supplicant_manager, - NMSupplMgrCreateIfaceHandle *handle, - NMSupplicantInterface * iface, - GError * error, - gpointer user_data) -{ - NMDeviceEthernet * self; - NMDeviceEthernetPrivate *priv; - guint timeout; - - if (nm_utils_error_is_cancelled(error)) - return; - - self = user_data; - priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - nm_assert(priv->supplicant.create_handle == handle); - priv->supplicant.create_handle = NULL; - - if (error) { - _LOGE(LOGD_DEVICE | LOGD_ETHER, - "Couldn't initialize supplicant interface: %s", - error->message); - supplicant_interface_release(self); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return; - } - - priv->supplicant.iface = g_object_ref(iface); - priv->supplicant.is_associated = FALSE; - - priv->supplicant.iface_state_id = g_signal_connect(priv->supplicant.iface, - NM_SUPPLICANT_INTERFACE_STATE, - G_CALLBACK(supplicant_iface_state_cb), - self); - - timeout = nm_device_get_supplicant_timeout(NM_DEVICE(self)); - priv->supplicant.con_timeout_id = - g_timeout_add_seconds(timeout, supplicant_connection_timeout_cb, self); - - if (nm_supplicant_interface_state_is_operational(nm_supplicant_interface_get_state(iface))) - supplicant_iface_start(self); -} - -static NMPlatformLinkDuplexType -link_duplex_to_platform(const char *duplex) -{ - if (!duplex) - return NM_PLATFORM_LINK_DUPLEX_UNKNOWN; - if (nm_streq(duplex, "full")) - return NM_PLATFORM_LINK_DUPLEX_FULL; - if (nm_streq(duplex, "half")) - return NM_PLATFORM_LINK_DUPLEX_HALF; - g_return_val_if_reached(NM_PLATFORM_LINK_DUPLEX_UNKNOWN); -} - -static void -link_negotiation_set(NMDevice *device) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMSettingWired * s_wired; - gboolean autoneg = TRUE; - gboolean link_autoneg; - NMPlatformLinkDuplexType duplex = NM_PLATFORM_LINK_DUPLEX_UNKNOWN; - NMPlatformLinkDuplexType link_duplex; - guint32 speed = 0; - guint32 link_speed; - - s_wired = nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRED); - if (s_wired) { - autoneg = nm_setting_wired_get_auto_negotiate(s_wired); - speed = nm_setting_wired_get_speed(s_wired); - duplex = link_duplex_to_platform(nm_setting_wired_get_duplex(s_wired)); - if (!autoneg && !speed && !duplex) { - _LOGD(LOGD_DEVICE, "set-link: ignore link negotiation"); - return; - } - } - - if (!nm_platform_ethtool_get_link_settings(nm_device_get_platform(device), - nm_device_get_ifindex(device), - &link_autoneg, - &link_speed, - &link_duplex)) { - _LOGW(LOGD_DEVICE, "set-link: unable to retrieve link negotiation"); - return; - } - - /* If link negotiation setting are already in place do nothing and return with success */ - if (!!autoneg == !!link_autoneg && speed == link_speed && duplex == link_duplex) { - _LOGD(LOGD_DEVICE, "set-link: link negotiation is already configured"); - return; - } - - if (autoneg && !speed && !duplex) - _LOGD(LOGD_DEVICE, "set-link: configure auto-negotiation"); - else { - _LOGD(LOGD_DEVICE, - "set-link: configure %snegotiation (%u Mbit%s, %s duplex%s)", - autoneg ? "auto-" : "static ", - speed ?: link_speed, - speed ? "" : "*", - duplex ? nm_platform_link_duplex_type_to_string(duplex) - : nm_platform_link_duplex_type_to_string(link_duplex), - duplex ? "" : "*"); - } - - if (!priv->ethtool_prev_set) { - /* remember the values we had before setting it. */ - priv->ethtool_prev_autoneg = link_autoneg; - priv->ethtool_prev_speed = link_speed; - priv->ethtool_prev_duplex = link_duplex; - priv->ethtool_prev_set = TRUE; - } - - if (!nm_platform_ethtool_set_link_settings(nm_device_get_platform(device), - nm_device_get_ifindex(device), - autoneg, - speed, - duplex)) { - _LOGW(LOGD_DEVICE, "set-link: failure to set link negotiation"); - return; - } -} - -static gboolean -pppoe_reconnect_delay(gpointer user_data) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(user_data); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - priv->pppoe_wait_id = 0; - priv->last_pppoe_time = 0; - _LOGI(LOGD_DEVICE, "PPPoE reconnect delay complete, resuming connection..."); - nm_device_activate_schedule_stage1_device_prepare(NM_DEVICE(self), FALSE); - return G_SOURCE_REMOVE; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - if (nm_device_sys_iface_state_is_external_or_assume(device)) { - if (!priv->ethtool_prev_set && !nm_device_sys_iface_state_is_external(device)) { - NMSettingWired *s_wired; - - /* During restart of NetworkManager service we forget the original auto - * negotiation settings. When taking over a device, remember to reset - * the "default" during deactivate. */ - s_wired = nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRED); - if (s_wired - && (nm_setting_wired_get_auto_negotiate(s_wired) - || nm_setting_wired_get_speed(s_wired) - || nm_setting_wired_get_duplex(s_wired))) { - priv->ethtool_prev_set = TRUE; - priv->ethtool_prev_autoneg = TRUE; - priv->ethtool_prev_speed = 0; - priv->ethtool_prev_duplex = NM_PLATFORM_LINK_DUPLEX_UNKNOWN; - } - } - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - link_negotiation_set(device); - - /* If we're re-activating a PPPoE connection a short while after - * a previous PPPoE connection was torn down, wait a bit to allow the - * remote side to handle the disconnection. Otherwise, the peer may - * get confused and fail to negotiate the new connection. (rh #1023503) - * - * FIXME(shutdown): when exiting, we also need to wait before quitting, - * at least for additional NM_SHUTDOWN_TIMEOUT_MS seconds because - * otherwise after restart the device won't work for the first seconds. - */ - if (priv->last_pppoe_time != 0) { - gint32 delay = nm_utils_get_monotonic_timestamp_sec() - priv->last_pppoe_time; - - if (delay < PPPOE_RECONNECT_DELAY - && nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPPOE)) { - if (priv->pppoe_wait_id == 0) { - _LOGI(LOGD_DEVICE, - "delaying PPPoE reconnect for %d seconds to ensure peer is ready...", - delay); - priv->pppoe_wait_id = g_timeout_add_seconds(delay, pppoe_reconnect_delay, self); - } - return NM_ACT_STAGE_RETURN_POSTPONE; - } - nm_clear_g_source(&priv->pppoe_wait_id); - priv->last_pppoe_time = 0; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -supplicant_check_secrets_needed(NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMConnection * connection; - NMSetting8021x * security; - const char * setting_name; - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - security = nm_connection_get_setting_802_1x(connection); - if (!security) { - _LOGE(LOGD_DEVICE, "Invalid or missing 802.1X security"); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (!priv->supplicant.mgr) - priv->supplicant.mgr = g_object_ref(nm_supplicant_manager_get()); - - /* If we need secrets, get them */ - setting_name = nm_connection_need_secrets(connection, NULL); - if (setting_name) { - NMActRequest *req = nm_device_get_act_request(NM_DEVICE(self)); - - _LOGI(LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) connection '%s' has security, but secrets are required.", - nm_connection_get_id(connection)); - - if (!handle_auth_or_fail(self, req, FALSE)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - return NM_ACT_STAGE_RETURN_FAILURE; - } - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - _LOGI(LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) connection '%s' requires no security. No secrets needed.", - nm_connection_get_id(connection)); - - supplicant_interface_release(self); - - priv->supplicant.create_handle = - nm_supplicant_manager_create_interface(priv->supplicant.mgr, - nm_device_get_ifindex(NM_DEVICE(self)), - NM_SUPPLICANT_DRIVER_WIRED, - supplicant_interface_create_cb, - self); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -carrier_changed(NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceEthernet *self) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMDeviceStateReason reason; - NMActStageReturn ret; - - if (!nm_device_has_carrier(NM_DEVICE(self))) - return; - - _LOGD(LOGD_DEVICE | LOGD_ETHER, "got carrier, initializing supplicant"); - nm_clear_g_signal_handler(self, &priv->carrier_id); - ret = supplicant_check_secrets_needed(self, &reason); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed(NM_DEVICE(self), NM_DEVICE_STATE_FAILED, reason); - } -} - -/*****************************************************************************/ -/* PPPoE */ - -static void -ppp_state_changed(NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - switch (status) { - case NM_PPP_STATUS_DISCONNECT: - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_PPP_DISCONNECT); - break; - case NM_PPP_STATUS_DEAD: - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); - break; - default: - break; - } -} - -static void -ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - if (!nm_device_set_ip_ifindex(device, ifindex)) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } -} - -static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - /* Ignore PPP IP4 events that come in after initial configuration */ - if (nm_device_activate_ip4_state_in_conf(device)) - nm_device_activate_schedule_ip_config_result(device, AF_INET, NM_IP_CONFIG_CAST(config)); -} - -static NMActStageReturn -pppoe_stage3_ip4_config_start(NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason) -{ - NMDevice * device = NM_DEVICE(self); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMSettingPppoe * s_pppoe; - NMActRequest * req; - GError * err = NULL; - - req = nm_device_get_act_request(device); - - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - s_pppoe = nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPPOE); - - g_return_val_if_fail(s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); - - priv->ppp_manager = nm_ppp_manager_create(nm_device_get_iface(device), &err); - - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); - } - - if (!priv->ppp_manager - || !nm_ppp_manager_start(priv->ppp_manager, - req, - nm_setting_pppoe_get_username(s_pppoe), - 30, - 0, - &err)) { - _LOGW(LOGD_DEVICE, "PPPoE failed to start: %s", err->message); - g_error_free(err); - - g_clear_object(&priv->ppp_manager); - - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, - G_CALLBACK(ppp_state_changed), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK(ppp_ifindex_set), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), - self); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static void dcb_state(NMDevice *device, gboolean timeout); - -static gboolean -dcb_carrier_timeout(gpointer user_data) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(user_data); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(user_data); - - g_return_val_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_CONFIG, G_SOURCE_REMOVE); - - priv->dcb_timeout_id = 0; - if (priv->dcb_wait != DCB_WAIT_CARRIER_POSTCONFIG_DOWN) { - _LOGW(LOGD_DCB, "DCB: timed out waiting for carrier (step %d)", priv->dcb_wait); - } - dcb_state(device, TRUE); - return G_SOURCE_REMOVE; -} - -static gboolean -dcb_configure(NMDevice *device) -{ - NMDeviceEthernet * self = (NMDeviceEthernet *) device; - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMSettingDcb * s_dcb; - GError * error = NULL; - - nm_clear_g_source(&priv->dcb_timeout_id); - - s_dcb = nm_device_get_applied_setting(device, NM_TYPE_SETTING_DCB); - - g_return_val_if_fail(s_dcb, FALSE); - - if (!nm_dcb_setup(nm_device_get_iface(device), s_dcb, &error)) { - _LOGW(LOGD_DCB, "Activation: (ethernet) failed to enable DCB/FCoE: %s", error->message); - g_clear_error(&error); - return FALSE; - } - - /* Pause again just in case the device takes the carrier down when - * setting specific DCB attributes. - */ - _LOGD(LOGD_DCB, "waiting for carrier (postconfig down)"); - priv->dcb_wait = DCB_WAIT_CARRIER_POSTCONFIG_DOWN; - priv->dcb_timeout_id = g_timeout_add_seconds(3, dcb_carrier_timeout, device); - return TRUE; -} - -static gboolean -dcb_enable(NMDevice *device) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - GError * error = NULL; - - nm_clear_g_source(&priv->dcb_timeout_id); - if (!nm_dcb_enable(nm_device_get_iface(device), TRUE, &error)) { - _LOGW(LOGD_DCB, "Activation: (ethernet) failed to enable DCB/FCoE: %s", error->message); - g_clear_error(&error); - return FALSE; - } - - /* Pause for 3 seconds after enabling DCB to let the card reconfigure - * itself. Drivers will often re-initialize internal settings which - * takes the carrier down for 2 or more seconds. During this time, - * lldpad will refuse to do anything else with the card since the carrier - * is down. But NM might get the carrier-down signal long after calling - * "dcbtool dcb on", so we have to first wait for the carrier to go down. - */ - _LOGD(LOGD_DCB, "waiting for carrier (preconfig down)"); - priv->dcb_wait = DCB_WAIT_CARRIER_PRECONFIG_DOWN; - priv->dcb_timeout_id = g_timeout_add_seconds(3, dcb_carrier_timeout, device); - return TRUE; -} - -static void -dcb_state(NMDevice *device, gboolean timeout) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - gboolean carrier; - - g_return_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_CONFIG); - - carrier = nm_platform_link_is_connected(nm_device_get_platform(device), - nm_device_get_ifindex(device)); - _LOGD(LOGD_DCB, "dcb_state() wait %d carrier %d timeout %d", priv->dcb_wait, carrier, timeout); - - switch (priv->dcb_wait) { - case DCB_WAIT_CARRIER_PREENABLE_UP: - if (timeout || carrier) { - _LOGD(LOGD_DCB, "dcb_state() enabling DCB"); - nm_clear_g_source(&priv->dcb_timeout_id); - if (!dcb_enable(device)) { - priv->dcb_handle_carrier_changes = FALSE; - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED); - } - } - break; - case DCB_WAIT_CARRIER_PRECONFIG_DOWN: - nm_clear_g_source(&priv->dcb_timeout_id); - priv->dcb_wait = DCB_WAIT_CARRIER_PRECONFIG_UP; - - if (!carrier) { - /* Wait for the carrier to come back up */ - _LOGD(LOGD_DCB, "waiting for carrier (preconfig up)"); - priv->dcb_timeout_id = g_timeout_add_seconds(5, dcb_carrier_timeout, device); - break; - } - _LOGD(LOGD_DCB, "dcb_state() preconfig down falling through"); - /* fall-through */ - case DCB_WAIT_CARRIER_PRECONFIG_UP: - if (timeout || carrier) { - _LOGD(LOGD_DCB, "dcb_state() preconfig up configuring DCB"); - nm_clear_g_source(&priv->dcb_timeout_id); - if (!dcb_configure(device)) { - priv->dcb_handle_carrier_changes = FALSE; - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED); - } - } - break; - case DCB_WAIT_CARRIER_POSTCONFIG_DOWN: - nm_clear_g_source(&priv->dcb_timeout_id); - priv->dcb_wait = DCB_WAIT_CARRIER_POSTCONFIG_UP; - - if (!carrier) { - /* Wait for the carrier to come back up */ - _LOGD(LOGD_DCB, "waiting for carrier (postconfig up)"); - priv->dcb_timeout_id = g_timeout_add_seconds(5, dcb_carrier_timeout, device); - break; - } - _LOGD(LOGD_DCB, "dcb_state() postconfig down falling through"); - /* fall-through */ - case DCB_WAIT_CARRIER_POSTCONFIG_UP: - if (timeout || carrier) { - _LOGD(LOGD_DCB, "dcb_state() postconfig up starting IP"); - nm_clear_g_source(&priv->dcb_timeout_id); - priv->dcb_handle_carrier_changes = FALSE; - priv->dcb_wait = DCB_WAIT_UNKNOWN; - nm_device_activate_schedule_stage3_ip_config_start(device); - } - break; - default: - g_assert_not_reached(); - } -} - -/*****************************************************************************/ - -static gboolean -wake_on_lan_enable(NMDevice *device) -{ - NMSettingWiredWakeOnLan wol; - NMSettingWired * s_wired; - const char * password = NULL; - - s_wired = nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRED); - - if (s_wired) { - wol = nm_setting_wired_get_wake_on_lan(s_wired); - password = nm_setting_wired_get_wake_on_lan_password(s_wired); - if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) - goto found; - } - - wol = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ethernet.wake-on-lan"), - device, - NM_SETTING_WIRED_WAKE_ON_LAN_NONE, - G_MAXINT32, - NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT); - - if (NM_FLAGS_ANY(wol, NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS) - && !nm_utils_is_power_of_two(wol)) { - nm_log_dbg(LOGD_ETHER, "invalid default value %u for wake-on-lan", (guint) wol); - wol = NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT; - } - if (wol != NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT) - goto found; - wol = NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE; -found: - return nm_platform_ethtool_set_wake_on_lan(nm_device_get_platform(device), - nm_device_get_ifindex(device), - wol, - password); -} - -/*****************************************************************************/ - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceEthernet * self = (NMDeviceEthernet *) device; - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMSettingConnection * s_con; - const char * connection_type; - gboolean do_postpone = FALSE; - NMSettingDcb * s_dcb; - - s_con = nm_device_get_applied_setting(device, NM_TYPE_SETTING_CONNECTION); - - g_return_val_if_fail(s_con, NM_ACT_STAGE_RETURN_FAILURE); - - nm_clear_g_source(&priv->dcb_timeout_id); - priv->dcb_handle_carrier_changes = FALSE; - - /* 802.1x has to run before any IP configuration since the 802.1x auth - * process opens the port up for normal traffic. - */ - connection_type = nm_setting_connection_get_connection_type(s_con); - if (nm_streq(connection_type, NM_SETTING_WIRED_SETTING_NAME)) { - NMSetting8021x *security; - - security = nm_device_get_applied_setting(device, NM_TYPE_SETTING_802_1X); - - if (security) { - /* FIXME: for now 802.1x is mutually exclusive with DCB */ - if (!nm_device_has_carrier(NM_DEVICE(self))) { - _LOGD(LOGD_DEVICE | LOGD_ETHER, - "delay supplicant initialization until carrier goes up"); - priv->carrier_id = g_signal_connect(self, - "notify::" NM_DEVICE_CARRIER, - G_CALLBACK(carrier_changed), - self); - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - return supplicant_check_secrets_needed(self, out_failure_reason); - } - } - - wake_on_lan_enable(device); - - /* DCB and FCoE setup */ - s_dcb = nm_device_get_applied_setting(device, NM_TYPE_SETTING_DCB); - if (s_dcb) { - /* lldpad really really wants the carrier to be up */ - if (nm_platform_link_is_connected(nm_device_get_platform(device), - nm_device_get_ifindex(device))) { - if (!dcb_enable(device)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - } else { - _LOGD(LOGD_DCB, "waiting for carrier (preenable up)"); - priv->dcb_wait = DCB_WAIT_CARRIER_PREENABLE_UP; - priv->dcb_timeout_id = g_timeout_add_seconds(4, dcb_carrier_timeout, device); - } - - priv->dcb_handle_carrier_changes = TRUE; - do_postpone = TRUE; - } - - /* PPPoE setup */ - if (nm_connection_is_type(nm_device_get_applied_connection(device), - NM_SETTING_PPPOE_SETTING_NAME)) { - NMSettingPpp *s_ppp; - - s_ppp = nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPP); - if (s_ppp) { - guint32 mtu; - guint32 mru; - guint32 mxu; - - mtu = nm_setting_ppp_get_mtu(s_ppp); - mru = nm_setting_ppp_get_mru(s_ppp); - mxu = MAX(mru, mtu); - if (mxu) { - _LOGD(LOGD_PPP, - "set MTU to %u (PPP interface MRU %u, MTU %u)", - mxu + PPPOE_ENCAP_OVERHEAD, - mru, - mtu); - nm_platform_link_set_mtu(nm_device_get_platform(device), - nm_device_get_ifindex(device), - mxu + PPPOE_ENCAP_OVERHEAD); - } - } - } - - return do_postpone ? NM_ACT_STAGE_RETURN_POSTPONE : NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMSettingConnection *s_con; - const char * connection_type; - - if (addr_family == AF_INET) { - s_con = nm_device_get_applied_setting(device, NM_TYPE_SETTING_CONNECTION); - - g_return_val_if_fail(s_con, NM_ACT_STAGE_RETURN_FAILURE); - - connection_type = nm_setting_connection_get_connection_type(s_con); - if (!strcmp(connection_type, NM_SETTING_PPPOE_SETTING_NAME)) - return pppoe_stage3_ip4_config_start(NM_DEVICE_ETHERNET(device), out_failure_reason); - } - - return NM_DEVICE_CLASS(nm_device_ethernet_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static guint32 -get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - /* MTU only set for plain ethernet */ - if (NM_DEVICE_ETHERNET_GET_PRIVATE(device)->ppp_manager) - return 0; - - return nm_device_get_configured_mtu_for_wired(device, out_source, out_force); -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - NMSettingDcb * s_dcb; - GError * error = NULL; - - nm_clear_g_source(&priv->pppoe_wait_id); - nm_clear_g_signal_handler(self, &priv->carrier_id); - - if (priv->ppp_manager) { - nm_ppp_manager_stop(priv->ppp_manager, NULL, NULL, NULL); - g_clear_object(&priv->ppp_manager); - } - - supplicant_interface_release(self); - - priv->dcb_wait = DCB_WAIT_UNKNOWN; - nm_clear_g_source(&priv->dcb_timeout_id); - priv->dcb_handle_carrier_changes = FALSE; - - /* Tear down DCB/FCoE if it was enabled */ - s_dcb = nm_device_get_applied_setting(device, NM_TYPE_SETTING_DCB); - if (s_dcb) { - if (!nm_dcb_cleanup(nm_device_get_iface(device), &error)) { - _LOGW(LOGD_DEVICE | LOGD_PLATFORM, "failed to disable DCB/FCoE: %s", error->message); - g_clear_error(&error); - } - } - - /* Set last PPPoE connection time */ - if (nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPPOE)) - priv->last_pppoe_time = nm_utils_get_monotonic_timestamp_sec(); - - if (priv->ethtool_prev_set) { - priv->ethtool_prev_set = FALSE; - - _LOGD(LOGD_DEVICE, - "set-link: reset %snegotiation (%u Mbit, %s duplex)", - priv->ethtool_prev_autoneg ? "auto-" : "static ", - priv->ethtool_prev_speed, - nm_platform_link_duplex_type_to_string(priv->ethtool_prev_duplex)); - if (!nm_platform_ethtool_set_link_settings(nm_device_get_platform(device), - nm_device_get_ifindex(device), - priv->ethtool_prev_autoneg, - priv->ethtool_prev_speed, - priv->ethtool_prev_duplex)) { - _LOGW(LOGD_DEVICE, "set-link: failure to reset link negotiation"); - return; - } - } -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingWired *s_wired; - NMSettingPppoe *s_pppoe; - - s_pppoe = nm_connection_get_setting_pppoe(connection); - - /* We can't telepathically figure out the service name or username, so if - * those weren't given, we can't complete the connection. - */ - if (s_pppoe && !nm_setting_verify(NM_SETTING(s_pppoe), NULL, error)) - return FALSE; - - s_wired = nm_connection_get_setting_wired(connection); - if (!s_wired) { - s_wired = (NMSettingWired *) nm_setting_wired_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wired)); - } - - /* Default to an ethernet-only connection, but if a PPPoE setting was given - * then PPPoE should be our connection type. - */ - nm_utils_complete_generic( - nm_device_get_platform(device), - connection, - s_pppoe ? NM_SETTING_PPPOE_SETTING_NAME : NM_SETTING_WIRED_SETTING_NAME, - existing_connections, - NULL, - s_pppoe ? _("PPPoE connection") : _("Wired connection"), - NULL, - nm_setting_wired_get_mac_address(s_wired) ? NULL : nm_device_get_iface(device), - s_pppoe ? FALSE : TRUE); /* No IPv6 by default yet for PPPoE */ - - return TRUE; -} - -static NMConnection * -new_default_connection(NMDevice *self) -{ - NMConnection * connection; - NMSettingsConnection *const *connections; - NMSetting * setting; - gs_unref_hashtable GHashTable *existing_ids = NULL; - struct udev_device * dev; - const char * perm_hw_addr; - const char * iface; - const char * uprop = "0"; - gs_free char * defname = NULL; - gs_free char * uuid = NULL; - guint i, n_connections; - - perm_hw_addr = nm_device_get_permanent_hw_address(self); - iface = nm_device_get_iface(self); - - connection = nm_simple_connection_new(); - setting = nm_setting_connection_new(); - nm_connection_add_setting(connection, setting); - - connections = nm_settings_get_connections(nm_device_get_settings(self), &n_connections); - if (n_connections > 0) { - existing_ids = g_hash_table_new(nm_str_hash, g_str_equal); - for (i = 0; i < n_connections; i++) - g_hash_table_add(existing_ids, (char *) nm_settings_connection_get_id(connections[i])); - } - defname = nm_device_ethernet_utils_get_default_wired_name(existing_ids); - if (!defname) - return NULL; - - /* Create a stable UUID. The UUID is also the Network_ID for stable-privacy addr-gen-mode, - * thus when it changes we will also generate different IPv6 addresses. */ - uuid = _nm_utils_uuid_generate_from_strings("default-wired", - nm_utils_machine_id_str(), - defname, - perm_hw_addr ?: iface, - NULL); - - g_object_set(setting, - NM_SETTING_CONNECTION_ID, - defname, - NM_SETTING_CONNECTION_TYPE, - NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_CONNECTION_AUTOCONNECT, - TRUE, - NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, - NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN, - NM_SETTING_CONNECTION_UUID, - uuid, - NM_SETTING_CONNECTION_TIMESTAMP, - (guint64) time(NULL), - NM_SETTING_CONNECTION_INTERFACE_NAME, - iface, - NULL); - - /* Check if we should create a Link-Local only connection */ - dev = nm_platform_link_get_udev_device(nm_device_get_platform(NM_DEVICE(self)), - nm_device_get_ip_ifindex(self)); - if (dev) - uprop = udev_device_get_property_value(dev, "NM_AUTO_DEFAULT_LINK_LOCAL_ONLY"); - - if (nm_udev_utils_property_as_boolean(uprop)) { - setting = nm_setting_ip4_config_new(); - g_object_set(setting, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL, - NULL); - nm_connection_add_setting(connection, setting); - - setting = nm_setting_ip6_config_new(); - g_object_set(setting, - NM_SETTING_IP_CONFIG_METHOD, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL, - NM_SETTING_IP_CONFIG_MAY_FAIL, - TRUE, - NULL); - nm_connection_add_setting(connection, setting); - } - - return connection; -} - -static const char * -get_s390_subchannels(NMDevice *device) -{ - nm_assert(NM_IS_DEVICE_ETHERNET(device)); - - return NM_DEVICE_ETHERNET_GET_PRIVATE(device)->subchannels; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(device); - NMSettingWired * s_wired = nm_connection_get_setting_wired(connection); - gboolean perm_hw_addr_is_fake; - const char * perm_hw_addr; - const char * mac = nm_device_get_hw_address(device); - const char * mac_prop = NM_SETTING_WIRED_MAC_ADDRESS; - GHashTableIter iter; - gpointer key, value; - - if (!s_wired) { - s_wired = (NMSettingWired *) nm_setting_wired_new(); - nm_connection_add_setting(connection, (NMSetting *) s_wired); - } - - g_object_set(nm_connection_get_setting_connection(connection), - NM_SETTING_CONNECTION_TYPE, - nm_connection_get_setting_pppoe(connection) ? NM_SETTING_PPPOE_SETTING_NAME - : NM_SETTING_WIRED_SETTING_NAME, - NULL); - - /* If the device reports a permanent address, use that for the MAC address - * and the current MAC, if different, is the cloned MAC. - */ - perm_hw_addr = nm_device_get_permanent_hw_address_full(device, TRUE, &perm_hw_addr_is_fake); - if (perm_hw_addr && !perm_hw_addr_is_fake) { - g_object_set(s_wired, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); - - mac_prop = NULL; - if (mac && !nm_utils_hwaddr_matches(perm_hw_addr, -1, mac, -1)) - mac_prop = NM_SETTING_WIRED_CLONED_MAC_ADDRESS; - } - - if (mac_prop && mac && nm_utils_hwaddr_valid(mac, ETH_ALEN)) - g_object_set(s_wired, mac_prop, mac, NULL); - - /* We don't set the MTU as we don't know whether it was set explicitly */ - - /* s390 */ - if (priv->subchannels_dbus) - g_object_set(s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, priv->subchannels_dbus, NULL); - if (priv->s390_nettype) - g_object_set(s_wired, NM_SETTING_WIRED_S390_NETTYPE, priv->s390_nettype, NULL); - - _nm_setting_wired_clear_s390_options(s_wired); - g_hash_table_iter_init(&iter, priv->s390_options); - while (g_hash_table_iter_next(&iter, &key, &value)) - nm_setting_wired_add_s390_option(s_wired, (const char *) key, (const char *) value); -} - -static void -link_speed_update(NMDevice *device) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - guint32 speed; - - if (!nm_platform_ethtool_get_link_settings(nm_device_get_platform(device), - nm_device_get_ifindex(device), - NULL, - &speed, - NULL)) - return; - if (priv->speed == speed) - return; - - priv->speed = speed; - _LOGD(LOGD_PLATFORM | LOGD_ETHER, "speed is now %d Mb/s", speed); - _notify(self, PROP_SPEED); -} - -static void -carrier_changed_notify(NMDevice *device, gboolean carrier) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - if (priv->dcb_handle_carrier_changes) { - nm_assert(nm_device_get_state(device) == NM_DEVICE_STATE_CONFIG); - - if (priv->dcb_timeout_id) { - _LOGD(LOGD_DCB, "carrier_changed() calling dcb_state()"); - dcb_state(device, FALSE); - } - } - - if (carrier) - link_speed_update(device); - - NM_DEVICE_CLASS(nm_device_ethernet_parent_class)->carrier_changed_notify(device, carrier); -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_ethernet_parent_class)->link_changed(device, pllink); - if (pllink->initialized) - _update_s390_subchannels((NMDeviceEthernet *) device); -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!NM_DEVICE_CLASS(nm_device_ethernet_parent_class)->is_available(device, flags)) - return FALSE; - - return !!nm_device_get_initial_hw_address(device); -} - -static gboolean -can_reapply_change(NMDevice * device, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error) -{ - NMDeviceClass *device_class; - - /* Only handle wired setting here, delegate other settings to parent class */ - if (nm_streq(setting_name, NM_SETTING_WIRED_SETTING_NAME)) { - return nm_device_hash_check_invalid_keys( - diffs, - NM_SETTING_WIRED_SETTING_NAME, - error, - NM_SETTING_WIRED_MTU, /* reapplied with IP config */ - NM_SETTING_WIRED_SPEED, - NM_SETTING_WIRED_DUPLEX, - NM_SETTING_WIRED_AUTO_NEGOTIATE, - NM_SETTING_WIRED_WAKE_ON_LAN, - NM_SETTING_WIRED_WAKE_ON_LAN_PASSWORD); - } - - device_class = NM_DEVICE_CLASS(nm_device_ethernet_parent_class); - return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); -} - -static void -reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_new) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET(device); - NMDeviceState state = nm_device_get_state(device); - - NM_DEVICE_CLASS(nm_device_ethernet_parent_class)->reapply_connection(device, con_old, con_new); - - _LOGD(LOGD_DEVICE, "reapplying wired settings"); - - if (state >= NM_DEVICE_STATE_PREPARE) - link_negotiation_set(device); - if (state >= NM_DEVICE_STATE_CONFIG) - wake_on_lan_enable(device); -} - -static void -dispose(GObject *object) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(object); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - wired_secrets_cancel(self); - - supplicant_interface_release(self); - - nm_clear_g_source(&priv->pppoe_wait_id); - - nm_clear_g_source(&priv->dcb_timeout_id); - - nm_clear_g_signal_handler(self, &priv->carrier_id); - - G_OBJECT_CLASS(nm_device_ethernet_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(object); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - g_clear_object(&priv->supplicant.mgr); - g_free(priv->subchan1); - g_free(priv->subchan2); - g_free(priv->subchan3); - g_free(priv->subchannels); - g_strfreev(priv->subchannels_dbus); - g_free(priv->s390_nettype); - g_hash_table_destroy(priv->s390_options); - - G_OBJECT_CLASS(nm_device_ethernet_parent_class)->finalize(object); -} - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceEthernet * self = NM_DEVICE_ETHERNET(object); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_SPEED: - g_value_set_uint(value, priv->speed); - break; - case PROP_S390_SUBCHANNELS: - g_value_set_boxed(value, priv->subchannels_dbus); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static const NMDBusInterfaceInfoExtended interface_info_device_wired = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_WIRED, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PermHwAddress", - "s", - NM_DEVICE_PERM_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Speed", - "u", - NM_DEVICE_ETHERNET_SPEED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("S390Subchannels", - "as", - NM_DEVICE_ETHERNET_S390_SUBCHANNELS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", - "b", - NM_DEVICE_CARRIER), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ethernet_class_init(NMDeviceEthernetClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - g_type_class_add_private(object_class, sizeof(NMDeviceEthernetPrivate)); - - object_class->dispose = dispose; - object_class->finalize = finalize; - object_class->get_property = get_property; - object_class->set_property = set_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_wired); - - device_class->connection_type_supported = NM_SETTING_WIRED_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_ETHERNET); - - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->check_connection_compatible = check_connection_compatible; - device_class->complete_connection = complete_connection; - device_class->new_default_connection = new_default_connection; - - device_class->act_stage1_prepare_also_for_external_or_assume = TRUE; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->get_configured_mtu = get_configured_mtu; - device_class->deactivate = deactivate; - device_class->get_s390_subchannels = get_s390_subchannels; - device_class->update_connection = update_connection; - device_class->carrier_changed_notify = carrier_changed_notify; - device_class->link_changed = link_changed; - device_class->is_available = is_available; - device_class->can_reapply_change = can_reapply_change; - device_class->reapply_connection = reapply_connection; - - device_class->state_changed = device_state_changed; - - obj_properties[PROP_SPEED] = g_param_spec_uint(NM_DEVICE_ETHERNET_SPEED, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_S390_SUBCHANNELS] = - g_param_spec_boxed(NM_DEVICE_ETHERNET_S390_SUBCHANNELS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_ETHERNET_DEVICE_FACTORY (nm_ethernet_device_factory_get_type()) -#define NM_ETHERNET_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_ETHERNET_DEVICE_FACTORY, NMEthernetDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_ETHERNET, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Ethernet", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_ETHERNET, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_ETHERNET, - NULL); -} - -static gboolean -match_connection(NMDeviceFactory *factory, NMConnection *connection) -{ - const char * type = nm_connection_get_connection_type(connection); - NMSettingPppoe *s_pppoe; - - if (nm_streq(type, NM_SETTING_WIRED_SETTING_NAME)) - return TRUE; - - nm_assert(nm_streq(type, NM_SETTING_PPPOE_SETTING_NAME)); - s_pppoe = nm_connection_get_setting_pppoe(connection); - - return !nm_setting_pppoe_get_parent(s_pppoe); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - ETHERNET, - Ethernet, - ethernet, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_ETHERNET) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_PPPOE_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->match_connection = match_connection;); diff --git a/src/devices/nm-device-ethernet.h b/src/devices/nm-device-ethernet.h deleted file mode 100644 index 36b7bc57..00000000 --- a/src/devices/nm-device-ethernet.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2010 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_ETHERNET_H__ -#define __NETWORKMANAGER_DEVICE_ETHERNET_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_ETHERNET (nm_device_ethernet_get_type()) -#define NM_DEVICE_ETHERNET(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernet)) -#define NM_DEVICE_ETHERNET_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) -#define NM_IS_DEVICE_ETHERNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_ETHERNET)) -#define NM_IS_DEVICE_ETHERNET_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_ETHERNET)) -#define NM_DEVICE_ETHERNET_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetClass)) - -#define NM_DEVICE_ETHERNET_SPEED "speed" -#define NM_DEVICE_ETHERNET_S390_SUBCHANNELS "s390-subchannels" - -struct _NMDeviceEthernetPrivate; - -typedef struct { - NMDevice parent; - struct _NMDeviceEthernetPrivate *_priv; -} NMDeviceEthernet; - -typedef struct { - NMDeviceClass parent; -} NMDeviceEthernetClass; - -GType nm_device_ethernet_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_ETHERNET_H__ */ diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c deleted file mode 100644 index a238ce1b..00000000 --- a/src/devices/nm-device-factory.c +++ /dev/null @@ -1,413 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 - 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-factory.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <gmodule.h> - -#include "platform/nm-platform.h" -#include "nm-utils.h" -#include "nm-core-internal.h" -#include "nm-setting-bluetooth.h" - -#define PLUGIN_PREFIX "libnm-device-plugin-" - -/*****************************************************************************/ - -enum { DEVICE_ADDED, LAST_SIGNAL }; - -static guint signals[LAST_SIGNAL] = {0}; - -G_DEFINE_ABSTRACT_TYPE(NMDeviceFactory, nm_device_factory, G_TYPE_OBJECT) - -/*****************************************************************************/ - -static void -nm_device_factory_get_supported_types(NMDeviceFactory * factory, - const NMLinkType ** out_link_types, - const char *const **out_setting_types) -{ - g_return_if_fail(NM_IS_DEVICE_FACTORY(factory)); - - NM_DEVICE_FACTORY_GET_CLASS(factory)->get_supported_types(factory, - out_link_types, - out_setting_types); -} - -void -nm_device_factory_start(NMDeviceFactory *factory) -{ - g_return_if_fail(factory != NULL); - - if (NM_DEVICE_FACTORY_GET_CLASS(factory)->start) - NM_DEVICE_FACTORY_GET_CLASS(factory)->start(factory); -} - -NMDevice * -nm_device_factory_create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore, - GError ** error) -{ - NMDeviceFactoryClass *klass; - NMDevice * device; - gboolean ignore = FALSE; - - g_return_val_if_fail(factory, NULL); - g_return_val_if_fail(iface && *iface, NULL); - if (plink) { - g_return_val_if_fail(!connection, NULL); - g_return_val_if_fail(strcmp(iface, plink->name) == 0, NULL); - nm_assert(factory == nm_device_factory_manager_find_factory_for_link_type(plink->type)); - } else if (connection) - nm_assert(factory == nm_device_factory_manager_find_factory_for_connection(connection)); - else - g_return_val_if_reached(NULL); - - klass = NM_DEVICE_FACTORY_GET_CLASS(factory); - if (!klass->create_device) { - g_set_error(error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Device factory %s cannot manage new devices", - G_OBJECT_TYPE_NAME(factory)); - NM_SET_OUT(out_ignore, FALSE); - return NULL; - } - - device = klass->create_device(factory, iface, plink, connection, &ignore); - NM_SET_OUT(out_ignore, ignore); - if (!device) { - if (ignore) { - g_set_error(error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Device factory %s ignores device %s", - G_OBJECT_TYPE_NAME(factory), - iface); - } else { - g_set_error(error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Device factory %s failed to create device %s", - G_OBJECT_TYPE_NAME(factory), - iface); - } - } - return device; -} - -const char * -nm_device_factory_get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - g_return_val_if_fail(factory != NULL, NULL); - g_return_val_if_fail(connection != NULL, NULL); - - if (!nm_connection_is_virtual(connection)) - return NULL; - - if (NM_DEVICE_FACTORY_GET_CLASS(factory)->get_connection_parent) - return NM_DEVICE_FACTORY_GET_CLASS(factory)->get_connection_parent(factory, connection); - return NULL; -} - -char * -nm_device_factory_get_connection_iface(NMDeviceFactory *factory, - NMConnection * connection, - const char * parent_iface, - GError ** error) -{ - NMDeviceFactoryClass *klass; - char * ifname; - - g_return_val_if_fail(factory != NULL, NULL); - g_return_val_if_fail(connection != NULL, NULL); - g_return_val_if_fail(!error || !*error, NULL); - - klass = NM_DEVICE_FACTORY_GET_CLASS(factory); - - ifname = g_strdup(nm_connection_get_interface_name(connection)); - if (!ifname && klass->get_connection_iface) - ifname = klass->get_connection_iface(factory, connection, parent_iface); - - if (!ifname) { - g_set_error(error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "failed to determine interface name: error determine name for %s", - nm_connection_get_connection_type(connection)); - return NULL; - } - - return ifname; -} - -/*****************************************************************************/ - -static void -nm_device_factory_init(NMDeviceFactory *self) -{} - -static void -nm_device_factory_class_init(NMDeviceFactoryClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - signals[DEVICE_ADDED] = g_signal_new(NM_DEVICE_FACTORY_DEVICE_ADDED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - NM_TYPE_DEVICE); -} - -/*****************************************************************************/ - -static GHashTable *factories_by_link = NULL; -static GHashTable *factories_by_setting = NULL; - -static void __attribute__((destructor)) _cleanup(void) -{ - nm_clear_pointer(&factories_by_link, g_hash_table_unref); - nm_clear_pointer(&factories_by_setting, g_hash_table_unref); -} - -NMDeviceFactory * -nm_device_factory_manager_find_factory_for_link_type(NMLinkType link_type) -{ - g_return_val_if_fail(factories_by_link, NULL); - - return g_hash_table_lookup(factories_by_link, GUINT_TO_POINTER(link_type)); -} - -NMDeviceFactory * -nm_device_factory_manager_find_factory_for_connection(NMConnection *connection) -{ - NMDeviceFactoryClass *klass; - NMDeviceFactory * factory; - const char * type; - GSList * list; - - g_return_val_if_fail(factories_by_setting, NULL); - - type = nm_connection_get_connection_type(connection); - list = g_hash_table_lookup(factories_by_setting, type); - - for (; list; list = g_slist_next(list)) { - factory = list->data; - klass = NM_DEVICE_FACTORY_GET_CLASS(factory); - if (!klass->match_connection || klass->match_connection(factory, connection)) - return factory; - } - - return NULL; -} - -void -nm_device_factory_manager_for_each_factory(NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data) -{ - GHashTableIter iter; - NMDeviceFactory *factory; - GSList * list_iter, *list = NULL; - - if (factories_by_link) { - g_hash_table_iter_init(&iter, factories_by_link); - while (g_hash_table_iter_next(&iter, NULL, (gpointer) &factory)) { - if (!g_slist_find(list, factory)) - list = g_slist_prepend(list, factory); - } - } - - if (factories_by_setting) { - g_hash_table_iter_init(&iter, factories_by_setting); - while (g_hash_table_iter_next(&iter, NULL, (gpointer) &list_iter)) { - for (; list_iter; list_iter = g_slist_next(list_iter)) { - if (!g_slist_find(list, list_iter->data)) - list = g_slist_prepend(list, list_iter->data); - } - } - } - - for (list_iter = list; list_iter; list_iter = list_iter->next) - callback(list_iter->data, user_data); - - g_slist_free(list); -} - -static gboolean -_add_factory(NMDeviceFactory * factory, - const char * path, - NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data) -{ - const NMLinkType * link_types = NULL; - const char *const *setting_types = NULL; - GSList * list, *list2; - int i; - - g_return_val_if_fail(factories_by_link, FALSE); - g_return_val_if_fail(factories_by_setting, FALSE); - - nm_device_factory_get_supported_types(factory, &link_types, &setting_types); - - g_return_val_if_fail((link_types && link_types[0] > NM_LINK_TYPE_UNKNOWN) - || (setting_types && setting_types[0]), - FALSE); - - for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) - g_hash_table_insert(factories_by_link, - GUINT_TO_POINTER(link_types[i]), - g_object_ref(factory)); - for (i = 0; setting_types && setting_types[i]; i++) { - list = g_hash_table_lookup(factories_by_setting, (char *) setting_types[i]); - if (list) { - list2 = g_slist_append(list, g_object_ref(factory)); - nm_assert(list == list2); - } else { - list = g_slist_append(list, g_object_ref(factory)); - g_hash_table_insert(factories_by_setting, (char *) setting_types[i], list); - } - } - - callback(factory, user_data); - - nm_log(path ? LOGL_INFO : LOGL_DEBUG, - LOGD_PLATFORM, - NULL, - NULL, - "Loaded device plugin: %s (%s)", - G_OBJECT_TYPE_NAME(factory), - path ?: "internal"); - return TRUE; -} - -static void -_load_internal_factory(GType factory_gtype, - NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data) -{ - gs_unref_object NMDeviceFactory *factory = NULL; - - factory = (NMDeviceFactory *) g_object_new(factory_gtype, NULL); - _add_factory(factory, NULL, callback, user_data); -} - -static void -factories_list_unref(GSList *list) -{ - g_slist_free_full(list, g_object_unref); -} - -static void -load_factories_from_dir(const char * dirname, - NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data) -{ - NMDeviceFactory *factory; - GError * error = NULL; - char ** path, **paths; - - paths = nm_utils_read_plugin_paths(dirname, PLUGIN_PREFIX); - if (!paths) - return; - - for (path = paths; *path; path++) { - GModule * plugin; - NMDeviceFactoryCreateFunc create_func; - const char * item; - - item = strrchr(*path, '/'); - g_assert(item); - - plugin = g_module_open(*path, G_MODULE_BIND_LOCAL); - - if (!plugin) { - nm_log_warn(LOGD_PLATFORM, "(%s): failed to load plugin: %s", item, g_module_error()); - continue; - } - - if (!g_module_symbol(plugin, "nm_device_factory_create", (gpointer) &create_func)) { - nm_log_warn(LOGD_PLATFORM, - "(%s): failed to find device factory creator: %s", - item, - g_module_error()); - g_module_close(plugin); - continue; - } - - /* after loading glib types from the plugin, we cannot unload the library anymore. - * Make it resident. */ - g_module_make_resident(plugin); - - factory = create_func(&error); - if (!factory) { - nm_log_warn(LOGD_PLATFORM, - "(%s): failed to initialize device factory: %s", - item, - NM_G_ERROR_MSG(error)); - g_clear_error(&error); - continue; - } - g_clear_error(&error); - - _add_factory(factory, g_module_name(plugin), callback, user_data); - - g_object_unref(factory); - } - g_strfreev(paths); -} - -void -nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data) -{ - g_return_if_fail(factories_by_link == NULL); - g_return_if_fail(factories_by_setting == NULL); - - factories_by_link = g_hash_table_new_full(nm_direct_hash, NULL, NULL, g_object_unref); - factories_by_setting = g_hash_table_new_full(nm_str_hash, - g_str_equal, - NULL, - (GDestroyNotify) factories_list_unref); - -#define _ADD_INTERNAL(get_type_fcn) \ - G_STMT_START \ - { \ - GType get_type_fcn(void); \ - _load_internal_factory(get_type_fcn(), callback, user_data); \ - } \ - G_STMT_END - - _ADD_INTERNAL(nm_6lowpan_device_factory_get_type); - _ADD_INTERNAL(nm_bond_device_factory_get_type); - _ADD_INTERNAL(nm_bridge_device_factory_get_type); - _ADD_INTERNAL(nm_dummy_device_factory_get_type); - _ADD_INTERNAL(nm_ethernet_device_factory_get_type); - _ADD_INTERNAL(nm_infiniband_device_factory_get_type); - _ADD_INTERNAL(nm_ip_tunnel_device_factory_get_type); - _ADD_INTERNAL(nm_macsec_device_factory_get_type); - _ADD_INTERNAL(nm_macvlan_device_factory_get_type); - _ADD_INTERNAL(nm_ppp_device_factory_get_type); - _ADD_INTERNAL(nm_tun_device_factory_get_type); - _ADD_INTERNAL(nm_veth_device_factory_get_type); - _ADD_INTERNAL(nm_vlan_device_factory_get_type); - _ADD_INTERNAL(nm_vrf_device_factory_get_type); - _ADD_INTERNAL(nm_vxlan_device_factory_get_type); - _ADD_INTERNAL(nm_wireguard_device_factory_get_type); - _ADD_INTERNAL(nm_wpan_device_factory_get_type); - - load_factories_from_dir(NMPLUGINDIR, callback, user_data); -} diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h deleted file mode 100644 index 5e7a8acd..00000000 --- a/src/devices/nm-device-factory.h +++ /dev/null @@ -1,237 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2007 - 2014 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_FACTORY_H__ -#define __NETWORKMANAGER_DEVICE_FACTORY_H__ - -#include "nm-dbus-interface.h" -#include "nm-device.h" - -/* WARNING: this file is private API between NetworkManager and its internal - * device plugins. Its API can change at any time and is not guaranteed to be - * stable. NM and device plugins are distributed together and this API is - * not meant to enable third-party plugins. - */ - -#define NM_TYPE_DEVICE_FACTORY (nm_device_factory_get_type()) -#define NM_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) -#define NM_DEVICE_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_FACTORY, NMDeviceFactoryClass)) -#define NM_IS_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_FACTORY)) -#define NM_IS_DEVICE_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_FACTORY)) -#define NM_DEVICE_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactoryClass)) - -#define NM_DEVICE_FACTORY_DEVICE_ADDED "device-added" - -typedef struct { - GObject parent; -} NMDeviceFactory; - -typedef struct { - GObjectClass parent; - - /** - * get_supported_types: - * @factory: the #NMDeviceFactory - * @out_link_types: on return, a %NM_LINK_TYPE_NONE terminated - * list of #NMLinkType that the plugin supports - * @out_setting_types: on return, a %NULL terminated list of - * base-type #NMSetting names that the plugin can create devices for - * - * Returns the #NMLinkType and #NMSetting names that this plugin - * supports. This function MUST be implemented. - */ - void (*get_supported_types)(NMDeviceFactory * factory, - const NMLinkType ** out_link_types, - const char *const **out_setting_types); - - /** - * start: - * @factory: the #NMDeviceFactory - * - * Start the factory and discover any existing devices that the factory - * can manage. - */ - void (*start)(NMDeviceFactory *factory); - - /** - * match_connection: - * @connection: the #NMConnection - * - * Check if the factory supports the given connection. - */ - gboolean (*match_connection)(NMDeviceFactory *factory, NMConnection *connection); - - /** - * get_connection_parent: - * @factory: the #NMDeviceFactory - * @connection: the #NMConnection to return the parent name for, if supported - * - * Given a connection, returns the parent interface name, parent connection - * UUID, or parent device permanent hardware address for @connection. - * - * Returns: the parent interface name, parent connection UUID, parent - * device permanent hardware address, or %NULL - */ - const char *(*get_connection_parent)(NMDeviceFactory *factory, NMConnection *connection); - - /** - * get_connection_iface: - * @factory: the #NMDeviceFactory - * @connection: the #NMConnection to return the interface name for - * @parent_iface: optional parent interface name for virtual devices - * - * Given a connection, returns the interface name that a device activating - * that connection would have. - * - * Returns: the interface name, or %NULL - */ - char *(*get_connection_iface)(NMDeviceFactory *factory, - NMConnection * connection, - const char * parent_iface); - - /** - * create_device: - * @factory: the #NMDeviceFactory - * @iface: the interface name of the device - * @plink: the #NMPlatformLink if backed by a kernel device - * @connection: the #NMConnection if not backed by a kernel device - * @out_ignore: on return, %TRUE if the link should be ignored - * - * The plugin should create a new unrealized device using the details given - * by @iface and @plink or @connection. If both @iface and @plink are given, - * they are guaranteed to match. If both @iface and @connection are given, - * @iface is guaranteed to be the interface name that @connection specifies. - * - * If the plugin cannot create a #NMDevice for the link and wants the - * core to ignore it, set @out_ignore to %TRUE and return %NULL. - * - * Returns: the new unrealized #NMDevice, or %NULL - */ - NMDevice *(*create_device)(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore); - -} NMDeviceFactoryClass; - -GType nm_device_factory_get_type(void); - -/*****************************************************************************/ - -/** - * nm_device_factory_create: - * @error: an error if creation of the factory failed, or %NULL - * - * Creates a #GObject that implements the #NMDeviceFactory interface. This - * function must not emit any signals or perform any actions that would cause - * devices or components to be created immediately. Instead these should be - * deferred to the "start" interface method. - * - * Returns: the #GObject implementing #NMDeviceFactory or %NULL - */ -NMDeviceFactory *nm_device_factory_create(GError **error); - -/* Should match nm_device_factory_create() */ -typedef NMDeviceFactory *(*NMDeviceFactoryCreateFunc)(GError **error); - -/*****************************************************************************/ - -const char *nm_device_factory_get_connection_parent(NMDeviceFactory *factory, - NMConnection * connection); - -char *nm_device_factory_get_connection_iface(NMDeviceFactory *factory, - NMConnection * connection, - const char * parent_iface, - GError ** error); - -void nm_device_factory_start(NMDeviceFactory *factory); - -NMDevice *nm_device_factory_create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore, - GError ** error); - -#define NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(...) \ - { \ - static NMLinkType const _link_types_declared[] = {__VA_ARGS__, NM_LINK_TYPE_NONE}; \ - _link_types = _link_types_declared; \ - } -#define NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(...) \ - { \ - static const char *const _setting_types_declared[] = {__VA_ARGS__, NULL}; \ - _setting_types = _setting_types_declared; \ - } - -#define NM_DEVICE_FACTORY_DECLARE_TYPES(...) \ - static void get_supported_types(NMDeviceFactory * factory, \ - const NMLinkType ** out_link_types, \ - const char *const **out_setting_types) \ - { \ - static NMLinkType const _link_types_null[1] = {NM_LINK_TYPE_NONE}; \ - static const char *const _setting_types_null[1] = {NULL}; \ - \ - const NMLinkType * _link_types = _link_types_null; \ - const char *const *_setting_types = _setting_types_null; \ - \ - { \ - __VA_ARGS__; \ - } \ - \ - NM_SET_OUT(out_link_types, _link_types); \ - NM_SET_OUT(out_setting_types, _setting_types); \ - } - -/************************************************************************** - * INTERNAL DEVICE FACTORY FUNCTIONS - devices provided by plugins should - * not use these functions. - **************************************************************************/ - -#define NM_DEVICE_FACTORY_DEFINE_INTERNAL(upper, mixed, lower, st_code, dfi_code) \ - typedef struct { \ - NMDeviceFactory parent; \ - } NM##mixed##DeviceFactory; \ - typedef struct { \ - NMDeviceFactoryClass parent; \ - } NM##mixed##DeviceFactoryClass; \ - \ - GType nm_##lower##_device_factory_get_type(void); \ - \ - G_DEFINE_TYPE(NM##mixed##DeviceFactory, nm_##lower##_device_factory, NM_TYPE_DEVICE_FACTORY) \ - \ - NM_DEVICE_FACTORY_DECLARE_TYPES(st_code) \ - \ - static void nm_##lower##_device_factory_init(NM##mixed##DeviceFactory *self) {} \ - \ - static void nm_##lower##_device_factory_class_init(NM##mixed##DeviceFactoryClass *klass) \ - { \ - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); \ - \ - factory_class->get_supported_types = get_supported_types; \ - dfi_code \ - } - -/************************************************************************** - * PRIVATE FACTORY FUNCTIONS - for factory consumers (eg, NMManager). - **************************************************************************/ - -typedef void (*NMDeviceFactoryManagerFactoryFunc)(NMDeviceFactory *factory, gpointer user_data); - -void nm_device_factory_manager_load_factories(NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data); - -NMDeviceFactory *nm_device_factory_manager_find_factory_for_link_type(NMLinkType link_type); - -NMDeviceFactory *nm_device_factory_manager_find_factory_for_connection(NMConnection *connection); - -void nm_device_factory_manager_for_each_factory(NMDeviceFactoryManagerFactoryFunc callback, - gpointer user_data); - -#endif /* __NETWORKMANAGER_DEVICE_FACTORY_H__ */ diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c deleted file mode 100644 index ccd56366..00000000 --- a/src/devices/nm-device-generic.c +++ /dev/null @@ -1,238 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-generic.h" - -#include "nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_TYPE_DESCRIPTION, ); - -typedef struct { - char *type_description; -} NMDeviceGenericPrivate; - -struct _NMDeviceGeneric { - NMDevice parent; - NMDeviceGenericPrivate _priv; -}; - -struct _NMDeviceGenericClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceGeneric, nm_device_generic, NM_TYPE_DEVICE) - -#define NM_DEVICE_GENERIC_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceGeneric, NM_IS_DEVICE_GENERIC, NMDevice) - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - int ifindex = nm_device_get_ifindex(device); - - if (ifindex > 0 - && nm_platform_link_supports_carrier_detect(nm_device_get_platform(device), ifindex)) - return NM_DEVICE_CAP_CARRIER_DETECT; - else - return NM_DEVICE_CAP_NONE; -} - -static const char * -get_type_description(NMDevice *device) -{ - if (NM_DEVICE_GENERIC_GET_PRIVATE(device)->type_description) - return NM_DEVICE_GENERIC_GET_PRIVATE(device)->type_description; - return NM_DEVICE_CLASS(nm_device_generic_parent_class)->get_type_description(device); -} - -static void -realize_start_notify(NMDevice *device, const NMPlatformLink *plink) -{ - NMDeviceGeneric * self = NM_DEVICE_GENERIC(device); - NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE(self); - int ifindex; - - NM_DEVICE_CLASS(nm_device_generic_parent_class)->realize_start_notify(device, plink); - - nm_clear_g_free(&priv->type_description); - ifindex = nm_device_get_ip_ifindex(NM_DEVICE(self)); - if (ifindex > 0) - priv->type_description = - g_strdup(nm_platform_link_get_type_name(nm_device_get_platform(device), ifindex)); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingConnection *s_con; - - if (!NM_DEVICE_CLASS(nm_device_generic_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_con = nm_connection_get_setting_connection(connection); - if (!nm_setting_connection_get_interface_name(s_con)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "generic profiles need an interface name"); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMSettingConnection *s_con; - - if (!nm_connection_get_setting_generic(connection)) - nm_connection_add_setting(connection, nm_setting_generic_new()); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - g_object_set(G_OBJECT(s_con), - NM_SETTING_CONNECTION_INTERFACE_NAME, - nm_device_get_iface(device), - NULL); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceGeneric * self = NM_DEVICE_GENERIC(object); - NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_TYPE_DESCRIPTION: - g_value_set_string(value, priv->type_description); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMDeviceGeneric * self = NM_DEVICE_GENERIC(object); - NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_TYPE_DESCRIPTION: - priv->type_description = g_value_dup_string(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_generic_init(NMDeviceGeneric *self) -{} - -static GObject * -constructor(GType type, guint n_construct_params, GObjectConstructParam *construct_params) -{ - GObject *object; - - object = G_OBJECT_CLASS(nm_device_generic_parent_class) - ->constructor(type, n_construct_params, construct_params); - - nm_device_set_unmanaged_flags((NMDevice *) object, NM_UNMANAGED_BY_DEFAULT, TRUE); - - return object; -} - -NMDevice * -nm_device_generic_new(const NMPlatformLink *plink, gboolean nm_plugin_missing) -{ - g_return_val_if_fail(plink != NULL, NULL); - - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_GENERIC, - NM_DEVICE_IFACE, - plink->name, - NM_DEVICE_TYPE_DESC, - "Generic", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_GENERIC, - NM_DEVICE_NM_PLUGIN_MISSING, - nm_plugin_missing, - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceGeneric * self = NM_DEVICE_GENERIC(object); - NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE(self); - - nm_clear_g_free(&priv->type_description); - - G_OBJECT_CLASS(nm_device_generic_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_generic = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_GENERIC, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( - "TypeDescription", - "s", - NM_DEVICE_GENERIC_TYPE_DESCRIPTION), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_generic_class_init(NMDeviceGenericClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->constructor = constructor; - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_generic); - - device_class->connection_type_supported = NM_SETTING_GENERIC_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_GENERIC_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_ANY); - - device_class->realize_start_notify = realize_start_notify; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->get_type_description = get_type_description; - device_class->check_connection_compatible = check_connection_compatible; - device_class->update_connection = update_connection; - - obj_properties[PROP_TYPE_DESCRIPTION] = - g_param_spec_string(NM_DEVICE_GENERIC_TYPE_DESCRIPTION, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/nm-device-generic.h b/src/devices/nm-device-generic.h deleted file mode 100644 index 4acc4dc9..00000000 --- a/src/devices/nm-device-generic.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_GENERIC_H__ -#define __NETWORKMANAGER_DEVICE_GENERIC_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_GENERIC (nm_device_generic_get_type()) -#define NM_DEVICE_GENERIC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_GENERIC, NMDeviceGeneric)) -#define NM_DEVICE_GENERIC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_GENERIC, NMDeviceGenericClass)) -#define NM_IS_DEVICE_GENERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_GENERIC)) -#define NM_IS_DEVICE_GENERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_GENERIC)) -#define NM_DEVICE_GENERIC_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_GENERIC, NMDeviceGenericClass)) - -#define NM_DEVICE_GENERIC_TYPE_DESCRIPTION "type-description" - -typedef struct _NMDeviceGeneric NMDeviceGeneric; -typedef struct _NMDeviceGenericClass NMDeviceGenericClass; - -GType nm_device_generic_get_type(void); - -NMDevice *nm_device_generic_new(const NMPlatformLink *plink, gboolean nm_plugin_missing); - -#endif /* __NETWORKMANAGER_DEVICE_GENERIC_H__ */ diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c deleted file mode 100644 index bae5db64..00000000 --- a/src/devices/nm-device-infiniband.c +++ /dev/null @@ -1,504 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 - 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-infiniband.h" - -#include <linux/if.h> -#include <linux/if_infiniband.h> - -#include "NetworkManagerUtils.h" -#include "nm-device-private.h" -#include "nm-act-request.h" -#include "nm-ip4-config.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-core-internal.h" - -#define NM_DEVICE_INFINIBAND_IS_PARTITION "is-partition" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_IS_PARTITION, ); - -typedef struct { - gboolean is_partition; - int parent_ifindex; - int p_key; -} NMDeviceInfinibandPrivate; - -struct _NMDeviceInfiniband { - NMDevice parent; - NMDeviceInfinibandPrivate _priv; -}; - -struct _NMDeviceInfinibandClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceInfiniband, nm_device_infiniband, NM_TYPE_DEVICE) - -#define NM_DEVICE_INFINIBAND_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceInfiniband, NM_IS_DEVICE_INFINIBAND, NMDevice) - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - guint32 caps = NM_DEVICE_CAP_CARRIER_DETECT; - - if (NM_DEVICE_INFINIBAND_GET_PRIVATE(device)->is_partition) - caps |= NM_DEVICE_CAP_IS_SOFTWARE; - - return caps; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - nm_auto_close int dirfd = -1; - NMSettingInfiniband *s_infiniband; - char ifname_verified[IFNAMSIZ]; - const char * transport_mode; - gboolean ok; - - s_infiniband = nm_device_get_applied_setting(device, NM_TYPE_SETTING_INFINIBAND); - - g_return_val_if_fail(s_infiniband, NM_ACT_STAGE_RETURN_FAILURE); - - transport_mode = nm_setting_infiniband_get_transport_mode(s_infiniband); - - dirfd = nm_platform_sysctl_open_netdir(nm_device_get_platform(device), - nm_device_get_ifindex(device), - ifname_verified); - if (dirfd < 0) { - if (nm_streq(transport_mode, "datagram")) - return NM_ACT_STAGE_RETURN_SUCCESS; - else { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_INFINIBAND_MODE); - return NM_ACT_STAGE_RETURN_FAILURE; - } - } - - /* With some drivers the interface must be down to set transport mode */ - nm_device_take_down(device, TRUE); - ok = nm_platform_sysctl_set(nm_device_get_platform(device), - NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname_verified, "mode"), - transport_mode); - nm_device_bring_up(device, TRUE, NULL); - - if (!ok) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static guint32 -get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - return nm_device_get_configured_mtu_from_connection(device, - NM_TYPE_SETTING_INFINIBAND, - out_source); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingInfiniband *s_infiniband; - - if (!NM_DEVICE_CLASS(nm_device_infiniband_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (nm_device_is_real(device)) { - const char *mac; - const char *hw_addr; - - s_infiniband = nm_connection_get_setting_infiniband(connection); - - mac = nm_setting_infiniband_get_mac_address(s_infiniband); - if (mac) { - hw_addr = nm_device_get_permanent_hw_address(device); - if (!hw_addr || !nm_utils_hwaddr_matches(mac, -1, hw_addr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "MAC address mismatches"); - return FALSE; - } - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingInfiniband *s_infiniband; - - s_infiniband = nm_connection_get_setting_infiniband(connection); - if (!s_infiniband) { - s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new(); - nm_connection_add_setting(connection, NM_SETTING(s_infiniband)); - } - - nm_utils_complete_generic( - nm_device_get_platform(device), - connection, - NM_SETTING_INFINIBAND_SETTING_NAME, - existing_connections, - NULL, - _("InfiniBand connection"), - NULL, - nm_setting_infiniband_get_mac_address(s_infiniband) ? NULL : nm_device_get_iface(device), - TRUE); - - if (!nm_setting_infiniband_get_transport_mode(s_infiniband)) - g_object_set(G_OBJECT(s_infiniband), - NM_SETTING_INFINIBAND_TRANSPORT_MODE, - "datagram", - NULL); - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband(connection); - const char * mac = nm_device_get_permanent_hw_address(device); - const char * transport_mode = "datagram"; - int ifindex; - - if (!s_infiniband) { - s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new(); - nm_connection_add_setting(connection, (NMSetting *) s_infiniband); - } - - if (mac && !nm_utils_hwaddr_matches(mac, -1, NULL, INFINIBAND_ALEN)) - g_object_set(s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL); - - ifindex = nm_device_get_ifindex(device); - if (ifindex > 0) { - if (!nm_platform_link_infiniband_get_properties(nm_device_get_platform(device), - ifindex, - NULL, - NULL, - &transport_mode)) - transport_mode = "datagram"; - } - g_object_set(G_OBJECT(s_infiniband), - NM_SETTING_INFINIBAND_TRANSPORT_MODE, - transport_mode, - NULL); -} - -static gboolean -can_reapply_change(NMDevice * device, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error) -{ - NMDeviceClass *device_class; - - if (nm_streq(setting_name, NM_SETTING_INFINIBAND_SETTING_NAME)) { - return nm_device_hash_check_invalid_keys( - diffs, - NM_SETTING_INFINIBAND_SETTING_NAME, - error, - NM_SETTING_INFINIBAND_MTU); /* reapplied with IP config */ - } - - device_class = NM_DEVICE_CLASS(nm_device_infiniband_parent_class); - return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE(device); - NMSettingInfiniband * s_infiniband; - int r; - - s_infiniband = nm_connection_get_setting_infiniband(connection); - g_assert(s_infiniband); - - /* Can only create partitions at this time */ - priv->p_key = nm_setting_infiniband_get_p_key(s_infiniband); - if (priv->p_key < 0) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "only InfiniBand partitions can be created"); - return FALSE; - } - - if (!parent) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "InfiniBand partitions can not be created without a parent interface"); - return FALSE; - } - - if (!NM_IS_DEVICE_INFINIBAND(parent)) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "Parent interface %s must be an InfiniBand interface", - nm_device_get_iface(parent)); - return FALSE; - } - - priv->parent_ifindex = nm_device_get_ifindex(parent); - if (priv->parent_ifindex <= 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "failed to get InfiniBand parent %s ifindex", - nm_device_get_iface(parent)); - return FALSE; - } - - r = nm_platform_link_infiniband_add(nm_device_get_platform(device), - priv->parent_ifindex, - priv->p_key, - out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create InfiniBand P_Key interface '%s' for '%s': %s", - nm_device_get_iface(device), - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - priv->is_partition = TRUE; - return TRUE; -} - -static gboolean -unrealize(NMDevice *device, GError **error) -{ - NMDeviceInfinibandPrivate *priv; - int r; - - g_return_val_if_fail(NM_IS_DEVICE_INFINIBAND(device), FALSE); - - priv = NM_DEVICE_INFINIBAND_GET_PRIVATE(device); - - if (priv->p_key < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Only InfiniBand partitions can be removed"); - return FALSE; - } - - r = nm_platform_link_infiniband_delete(nm_device_get_platform(device), - priv->parent_ifindex, - priv->p_key); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to remove InfiniBand P_Key interface '%s': %s", - nm_device_get_iface(device), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - case PROP_IS_PARTITION: - g_value_set_boolean(value, NM_DEVICE_INFINIBAND_GET_PRIVATE(object)->is_partition); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - case PROP_IS_PARTITION: - NM_DEVICE_INFINIBAND_GET_PRIVATE(object)->is_partition = g_value_get_boolean(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_infiniband_init(NMDeviceInfiniband *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_infiniband = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_INFINIBAND, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", - "b", - NM_DEVICE_CARRIER), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_infiniband_class_init(NMDeviceInfinibandClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - object_class->set_property = set_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_infiniband); - - device_class->connection_type_supported = NM_SETTING_INFINIBAND_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_INFINIBAND_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_INFINIBAND); - - device_class->can_reapply_change = can_reapply_change; - device_class->create_and_realize = create_and_realize; - device_class->unrealize = unrealize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->check_connection_compatible = check_connection_compatible; - device_class->complete_connection = complete_connection; - device_class->update_connection = update_connection; - - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->get_configured_mtu = get_configured_mtu; - - obj_properties[PROP_IS_PARTITION] = - g_param_spec_boolean(NM_DEVICE_INFINIBAND_IS_PARTITION, - "", - "", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_INFINIBAND_DEVICE_FACTORY (nm_infiniband_device_factory_get_type()) -#define NM_INFINIBAND_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - NM_TYPE_INFINIBAND_DEVICE_FACTORY, \ - NMInfinibandDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - gboolean is_partition = FALSE; - - if (plink) - is_partition = (plink->parent > 0 || plink->parent == NM_PLATFORM_LINK_OTHER_NETNS); - else if (connection) { - NMSettingInfiniband *s_infiniband; - - s_infiniband = nm_connection_get_setting_infiniband(connection); - g_return_val_if_fail(s_infiniband, NULL); - is_partition = !!nm_setting_infiniband_get_parent(s_infiniband) - || (nm_setting_infiniband_get_p_key(s_infiniband) >= 0 - && nm_setting_infiniband_get_mac_address(s_infiniband)); - } - - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_INFINIBAND, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "InfiniBand", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_INFINIBAND, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_INFINIBAND, - /* NOTE: Partition should probably be a different link type! */ - NM_DEVICE_INFINIBAND_IS_PARTITION, - is_partition, - NULL); -} - -static const char * -get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSettingInfiniband *s_infiniband; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_INFINIBAND_SETTING_NAME), - NULL); - - s_infiniband = nm_connection_get_setting_infiniband(connection); - g_assert(s_infiniband); - - return nm_setting_infiniband_get_parent(s_infiniband); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - NMSettingInfiniband *s_infiniband; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_INFINIBAND_SETTING_NAME), - NULL); - - s_infiniband = nm_connection_get_setting_infiniband(connection); - g_assert(s_infiniband); - - if (!parent_iface) - return NULL; - - g_return_val_if_fail(g_strcmp0(parent_iface, nm_setting_infiniband_get_parent(s_infiniband)) - == 0, - NULL); - - return g_strdup(nm_setting_infiniband_get_virtual_interface_name(s_infiniband)); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - INFINIBAND, - Infiniband, - infiniband, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_INFINIBAND) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_INFINIBAND_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); diff --git a/src/devices/nm-device-infiniband.h b/src/devices/nm-device-infiniband.h deleted file mode 100644 index d8be8f21..00000000 --- a/src/devices/nm-device-infiniband.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_INFINIBAND_H__ -#define __NETWORKMANAGER_DEVICE_INFINIBAND_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_INFINIBAND (nm_device_infiniband_get_type()) -#define NM_DEVICE_INFINIBAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfiniband)) -#define NM_DEVICE_INFINIBAND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandClass)) -#define NM_IS_DEVICE_INFINIBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_INFINIBAND)) -#define NM_IS_DEVICE_INFINIBAND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_INFINIBAND)) -#define NM_DEVICE_INFINIBAND_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandClass)) - -typedef struct _NMDeviceInfiniband NMDeviceInfiniband; -typedef struct _NMDeviceInfinibandClass NMDeviceInfinibandClass; - -GType nm_device_infiniband_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_INFINIBAND_H__ */ diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c deleted file mode 100644 index e01cc7ff..00000000 --- a/src/devices/nm-device-ip-tunnel.c +++ /dev/null @@ -1,1298 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ip-tunnel.h" - -#include <netinet/in.h> -#include <linux/if.h> -#include <linux/ip.h> -#include <linux/if_tunnel.h> -#include <linux/ip6_tunnel.h> - -#include "nm-device-private.h" -#include "nm-manager.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-core-internal.h" -#include "settings/nm-settings.h" -#include "nm-act-request.h" -#include "nm-ip4-config.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceIPTunnel); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIPTunnel, - PROP_MODE, - PROP_LOCAL, - PROP_REMOTE, - PROP_TTL, - PROP_TOS, - PROP_PATH_MTU_DISCOVERY, - PROP_INPUT_KEY, - PROP_OUTPUT_KEY, - PROP_ENCAPSULATION_LIMIT, - PROP_FLOW_LABEL, - PROP_FLAGS, ); - -typedef struct { - NMIPTunnelMode mode; - char * local; - char * remote; - guint8 ttl; - guint8 tos; - gboolean path_mtu_discovery; - int addr_family; - char * input_key; - char * output_key; - guint8 encap_limit; - guint32 flow_label; - NMIPTunnelFlags flags; -} NMDeviceIPTunnelPrivate; - -struct _NMDeviceIPTunnel { - NMDevice parent; - NMDeviceIPTunnelPrivate _priv; -}; - -struct _NMDeviceIPTunnelClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceIPTunnel, nm_device_ip_tunnel, NM_TYPE_DEVICE) - -#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceIPTunnel, NM_IS_DEVICE_IP_TUNNEL, NMDevice) - -/*****************************************************************************/ - -static guint32 -ip6tnl_flags_setting_to_plat(NMIPTunnelFlags flags) -{ - G_STATIC_ASSERT(NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT == IP6_TNL_F_IGN_ENCAP_LIMIT); - G_STATIC_ASSERT(NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS == IP6_TNL_F_USE_ORIG_TCLASS); - G_STATIC_ASSERT(NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL == IP6_TNL_F_USE_ORIG_FLOWLABEL); - G_STATIC_ASSERT(NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV == IP6_TNL_F_MIP6_DEV); - G_STATIC_ASSERT(NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY == IP6_TNL_F_RCV_DSCP_COPY); - G_STATIC_ASSERT(NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK == IP6_TNL_F_USE_ORIG_FWMARK); - - /* NOTE: "accidentally", the numeric values correspond. - * For flags added in the future, that might no longer - * be the case. */ - return flags & _NM_IP_TUNNEL_FLAG_ALL_IP6TNL; -} - -static NMIPTunnelFlags -ip6tnl_flags_plat_to_setting(guint32 flags) -{ - return flags & ((guint32) _NM_IP_TUNNEL_FLAG_ALL_IP6TNL); -} - -/*****************************************************************************/ - -static gboolean -address_equal_pp(int addr_family, const char *a, const char *b) -{ - const NMIPAddr *addr_a = &nm_ip_addr_zero; - const NMIPAddr *addr_b = &nm_ip_addr_zero; - NMIPAddr addr_a_val; - NMIPAddr addr_b_val; - - nm_assert_addr_family(addr_family); - - if (a) { - if (!nm_utils_parse_inaddr_bin(addr_family, a, NULL, &addr_a_val)) - nm_assert_not_reached(); - addr_a = &addr_a_val; - } - if (b) { - if (!nm_utils_parse_inaddr_bin(addr_family, b, NULL, &addr_b_val)) - nm_assert_not_reached(); - addr_b = &addr_b_val; - } - - return nm_ip_addr_equal(addr_family, addr_a, addr_b); -} - -static gboolean -address_set(int addr_family, char **p_addr, const NMIPAddr *addr_new) -{ - nm_assert_addr_family(addr_family); - nm_assert(p_addr); - nm_assert(!*p_addr || nm_utils_ipaddr_is_normalized(addr_family, *p_addr)); - - if (!addr_new || nm_ip_addr_is_null(addr_family, addr_new)) { - if (nm_clear_g_free(p_addr)) - return TRUE; - return FALSE; - } - - if (*p_addr) { - NMIPAddr addr_val; - - if (!nm_utils_parse_inaddr_bin(addr_family, *p_addr, NULL, &addr_val)) - nm_assert_not_reached(); - - if (nm_ip_addr_equal(addr_family, &addr_val, addr_new)) - return FALSE; - - g_free(*p_addr); - } - - *p_addr = nm_utils_inet_ntop_dup(addr_family, addr_new); - return TRUE; -} - -static void -update_properties_from_ifindex(NMDevice *device, int ifindex) -{ - NMDeviceIPTunnel * self = NM_DEVICE_IP_TUNNEL(device); - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self); - int parent_ifindex = 0; - NMIPAddr local = NM_IP_ADDR_INIT; - NMIPAddr remote = NM_IP_ADDR_INIT; - guint8 ttl = 0; - guint8 tos = 0; - guint8 encap_limit = 0; - gboolean pmtud = FALSE; - guint32 flow_label = 0; - NMIPTunnelFlags flags = NM_IP_TUNNEL_FLAG_NONE; - char * key; - - if (ifindex <= 0) { -clear: - nm_device_parent_set_ifindex(device, 0); - if (priv->local) { - nm_clear_g_free(&priv->local); - _notify(self, PROP_LOCAL); - } - if (priv->remote) { - nm_clear_g_free(&priv->remote); - _notify(self, PROP_REMOTE); - } - if (priv->input_key) { - nm_clear_g_free(&priv->input_key); - _notify(self, PROP_INPUT_KEY); - } - if (priv->output_key) { - nm_clear_g_free(&priv->output_key); - _notify(self, PROP_OUTPUT_KEY); - } - - goto out; - } - - if (NM_IN_SET(priv->mode, NM_IP_TUNNEL_MODE_GRE, NM_IP_TUNNEL_MODE_GRETAP)) { - const NMPlatformLnkGre *lnk; - - if (priv->mode == NM_IP_TUNNEL_MODE_GRE) - lnk = nm_platform_link_get_lnk_gre(nm_device_get_platform(device), ifindex, NULL); - else - lnk = nm_platform_link_get_lnk_gretap(nm_device_get_platform(device), ifindex, NULL); - if (!lnk) { - _LOGW(LOGD_PLATFORM, "could not read %s properties", "gre"); - goto clear; - } - - parent_ifindex = lnk->parent_ifindex; - local.addr4 = lnk->local; - remote.addr4 = lnk->remote; - ttl = lnk->ttl; - tos = lnk->tos; - pmtud = lnk->path_mtu_discovery; - - if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->input_key); - if (g_strcmp0(priv->input_key, key)) { - g_free(priv->input_key); - priv->input_key = key; - _notify(self, PROP_INPUT_KEY); - } else - g_free(key); - } else { - if (priv->input_key) { - nm_clear_g_free(&priv->input_key); - _notify(self, PROP_INPUT_KEY); - } - } - - if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->output_key); - if (g_strcmp0(priv->output_key, key)) { - g_free(priv->output_key); - priv->output_key = key; - _notify(self, PROP_OUTPUT_KEY); - } else - g_free(key); - } else { - if (priv->output_key) { - nm_clear_g_free(&priv->output_key); - _notify(self, PROP_OUTPUT_KEY); - } - } - } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) { - const NMPlatformLnkSit *lnk; - - lnk = nm_platform_link_get_lnk_sit(nm_device_get_platform(device), ifindex, NULL); - if (!lnk) { - _LOGW(LOGD_PLATFORM, "could not read %s properties", "sit"); - goto clear; - } - - parent_ifindex = lnk->parent_ifindex; - local.addr4 = lnk->local; - remote.addr4 = lnk->remote; - ttl = lnk->ttl; - tos = lnk->tos; - pmtud = lnk->path_mtu_discovery; - } else if (priv->mode == NM_IP_TUNNEL_MODE_IPIP) { - const NMPlatformLnkIpIp *lnk; - - lnk = nm_platform_link_get_lnk_ipip(nm_device_get_platform(device), ifindex, NULL); - if (!lnk) { - _LOGW(LOGD_PLATFORM, "could not read %s properties", "ipip"); - goto clear; - } - - parent_ifindex = lnk->parent_ifindex; - local.addr4 = lnk->local; - remote.addr4 = lnk->remote; - ttl = lnk->ttl; - tos = lnk->tos; - pmtud = lnk->path_mtu_discovery; - } else if (NM_IN_SET(priv->mode, - NM_IP_TUNNEL_MODE_IPIP6, - NM_IP_TUNNEL_MODE_IP6IP6, - NM_IP_TUNNEL_MODE_IP6GRE, - NM_IP_TUNNEL_MODE_IP6GRETAP)) { - const NMPlatformLnkIp6Tnl *lnk; - NMPlatform * plat = nm_device_get_platform(device); - - if (priv->mode == NM_IP_TUNNEL_MODE_IP6GRE) - lnk = nm_platform_link_get_lnk_ip6gre(plat, ifindex, NULL); - else if (priv->mode == NM_IP_TUNNEL_MODE_IP6GRETAP) - lnk = nm_platform_link_get_lnk_ip6gretap(plat, ifindex, NULL); - else - lnk = nm_platform_link_get_lnk_ip6tnl(plat, ifindex, NULL); - - if (!lnk) { - _LOGW(LOGD_PLATFORM, "could not read %s properties", "ip6tnl"); - goto clear; - } - - parent_ifindex = lnk->parent_ifindex; - local.addr6 = lnk->local; - remote.addr6 = lnk->remote; - ttl = lnk->ttl; - tos = lnk->tclass; - encap_limit = lnk->encap_limit; - flow_label = lnk->flow_label; - flags = ip6tnl_flags_plat_to_setting(lnk->flags); - - if (NM_IN_SET(priv->mode, NM_IP_TUNNEL_MODE_IP6GRE, NM_IP_TUNNEL_MODE_IP6GRETAP)) { - if (NM_FLAGS_HAS(lnk->input_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->input_key); - if (g_strcmp0(priv->input_key, key)) { - g_free(priv->input_key); - priv->input_key = key; - _notify(self, PROP_INPUT_KEY); - } else - g_free(key); - } else { - if (priv->input_key) { - nm_clear_g_free(&priv->input_key); - _notify(self, PROP_INPUT_KEY); - } - } - - if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY)) { - key = g_strdup_printf("%u", lnk->output_key); - if (g_strcmp0(priv->output_key, key)) { - g_free(priv->output_key); - priv->output_key = key; - _notify(self, PROP_OUTPUT_KEY); - } else - g_free(key); - } else { - if (priv->output_key) { - nm_clear_g_free(&priv->output_key); - _notify(self, PROP_OUTPUT_KEY); - } - } - } - } else - g_return_if_reached(); - - nm_device_parent_set_ifindex(device, parent_ifindex); - - if (address_set(priv->addr_family, &priv->local, &local)) - _notify(self, PROP_LOCAL); - if (address_set(priv->addr_family, &priv->remote, &remote)) - _notify(self, PROP_REMOTE); - -out: - - if (priv->ttl != ttl) { - priv->ttl = ttl; - _notify(self, PROP_TTL); - } - - if (priv->tos != tos) { - priv->tos = tos; - _notify(self, PROP_TOS); - } - - if (priv->path_mtu_discovery != pmtud) { - priv->path_mtu_discovery = pmtud; - _notify(self, PROP_PATH_MTU_DISCOVERY); - } - - if (priv->encap_limit != encap_limit) { - priv->encap_limit = encap_limit; - _notify(self, PROP_ENCAPSULATION_LIMIT); - } - - if (priv->flow_label != flow_label) { - priv->flow_label = flow_label; - _notify(self, PROP_FLOW_LABEL); - } - - if (priv->flags != flags) { - priv->flags = flags; - _notify(self, PROP_FLAGS); - } -} - -static void -update_properties(NMDevice *device) -{ - update_properties_from_ifindex(device, nm_device_get_ifindex(device)); -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_ip_tunnel_parent_class)->link_changed(device, pllink); - update_properties(device); -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingIPTunnel *s_ip_tunnel; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_IP_TUNNEL_SETTING_NAME, - existing_connections, - NULL, - _("IP tunnel connection"), - NULL, - NULL, - TRUE); - - s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - if (!s_ip_tunnel) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'tunnel' setting is required."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceIPTunnel * self = NM_DEVICE_IP_TUNNEL(device); - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self); - NMSettingIPTunnel * s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - - if (!s_ip_tunnel) { - s_ip_tunnel = (NMSettingIPTunnel *) nm_setting_ip_tunnel_new(); - nm_connection_add_setting(connection, (NMSetting *) s_ip_tunnel); - } - - if (nm_setting_ip_tunnel_get_mode(s_ip_tunnel) != priv->mode) - g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_MODE, priv->mode, NULL); - - g_object_set( - s_ip_tunnel, - NM_SETTING_IP_TUNNEL_PARENT, - nm_device_parent_find_for_connection(device, nm_setting_ip_tunnel_get_parent(s_ip_tunnel)), - NULL); - - if (!address_equal_pp(priv->addr_family, - nm_setting_ip_tunnel_get_local(s_ip_tunnel), - priv->local)) - g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_LOCAL, priv->local, NULL); - - if (!address_equal_pp(priv->addr_family, - nm_setting_ip_tunnel_get_remote(s_ip_tunnel), - priv->remote)) - g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_REMOTE, priv->remote, NULL); - - if (nm_setting_ip_tunnel_get_ttl(s_ip_tunnel) != priv->ttl) - g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_TTL, priv->ttl, NULL); - - if (nm_setting_ip_tunnel_get_tos(s_ip_tunnel) != priv->tos) - g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_TOS, priv->tos, NULL); - - if (nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel) != priv->path_mtu_discovery) { - g_object_set(G_OBJECT(s_ip_tunnel), - NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY, - priv->path_mtu_discovery, - NULL); - } - - if (nm_setting_ip_tunnel_get_encapsulation_limit(s_ip_tunnel) != priv->encap_limit) { - g_object_set(G_OBJECT(s_ip_tunnel), - NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, - priv->encap_limit, - NULL); - } - - if (nm_setting_ip_tunnel_get_flow_label(s_ip_tunnel) != priv->flow_label) { - g_object_set(G_OBJECT(s_ip_tunnel), - NM_SETTING_IP_TUNNEL_FLOW_LABEL, - priv->flow_label, - NULL); - } - - if (NM_IN_SET(priv->mode, - NM_IP_TUNNEL_MODE_GRE, - NM_IP_TUNNEL_MODE_GRETAP, - NM_IP_TUNNEL_MODE_IP6GRE, - NM_IP_TUNNEL_MODE_IP6GRETAP)) { - if (g_strcmp0(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), priv->input_key)) { - g_object_set(G_OBJECT(s_ip_tunnel), - NM_SETTING_IP_TUNNEL_INPUT_KEY, - priv->input_key, - NULL); - } - if (g_strcmp0(nm_setting_ip_tunnel_get_output_key(s_ip_tunnel), priv->output_key)) { - g_object_set(G_OBJECT(s_ip_tunnel), - NM_SETTING_IP_TUNNEL_OUTPUT_KEY, - priv->output_key, - NULL); - } - } -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceIPTunnel * self = NM_DEVICE_IP_TUNNEL(device); - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self); - NMSettingIPTunnel * s_ip_tunnel; - const char * parent; - - if (!NM_DEVICE_CLASS(nm_device_ip_tunnel_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - - if (nm_setting_ip_tunnel_get_mode(s_ip_tunnel) != priv->mode) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "incompatible IP tunnel mode"); - return FALSE; - } - - if (nm_device_is_real(device)) { - /* Check parent interface; could be an interface name or a UUID */ - parent = nm_setting_ip_tunnel_get_parent(s_ip_tunnel); - if (parent && !nm_device_match_parent(device, parent)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "IP tunnel parent mismatches"); - return FALSE; - } - - if (!address_equal_pp(priv->addr_family, - nm_setting_ip_tunnel_get_local(s_ip_tunnel), - priv->local)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "local IP tunnel address mismatches"); - return FALSE; - } - - if (!address_equal_pp(priv->addr_family, - nm_setting_ip_tunnel_get_remote(s_ip_tunnel), - priv->remote)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "remote IP tunnel address mismatches"); - return FALSE; - } - - if (nm_setting_ip_tunnel_get_ttl(s_ip_tunnel) != priv->ttl) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "TTL of IP tunnel mismatches"); - return FALSE; - } - - if (nm_setting_ip_tunnel_get_tos(s_ip_tunnel) != priv->tos) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "TOS of IP tunnel mismatches"); - return FALSE; - } - - if (priv->addr_family == AF_INET) { - if (nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel) - != priv->path_mtu_discovery) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "MTU discovery setting of IP tunnel mismatches"); - return FALSE; - } - } else { - if (nm_setting_ip_tunnel_get_encapsulation_limit(s_ip_tunnel) != priv->encap_limit) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "encapsulation limit of IP tunnel mismatches"); - return FALSE; - } - - if (nm_setting_ip_tunnel_get_flow_label(s_ip_tunnel) != priv->flow_label) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "flow-label of IP tunnel mismatches"); - return FALSE; - } - } - } - - return TRUE; -} - -static NMIPTunnelMode -platform_link_to_tunnel_mode(const NMPlatformLink *link) -{ - const NMPlatformLnkIp6Tnl *lnk; - - switch (link->type) { - case NM_LINK_TYPE_GRE: - return NM_IP_TUNNEL_MODE_GRE; - case NM_LINK_TYPE_GRETAP: - return NM_IP_TUNNEL_MODE_GRETAP; - case NM_LINK_TYPE_IP6TNL: - lnk = nm_platform_link_get_lnk_ip6tnl(NM_PLATFORM_GET, link->ifindex, NULL); - if (lnk) { - if (lnk->proto == IPPROTO_IPIP) - return NM_IP_TUNNEL_MODE_IPIP6; - if (lnk->proto == IPPROTO_IPV6) - return NM_IP_TUNNEL_MODE_IP6IP6; - } - return NM_IP_TUNNEL_MODE_UNKNOWN; - case NM_LINK_TYPE_IP6GRE: - return NM_IP_TUNNEL_MODE_IP6GRE; - case NM_LINK_TYPE_IP6GRETAP: - return NM_IP_TUNNEL_MODE_IP6GRETAP; - case NM_LINK_TYPE_IPIP: - return NM_IP_TUNNEL_MODE_IPIP; - case NM_LINK_TYPE_SIT: - return NM_IP_TUNNEL_MODE_SIT; - default: - g_return_val_if_reached(NM_IP_TUNNEL_MODE_UNKNOWN); - } -} - -static NMLinkType -tunnel_mode_to_link_type(NMIPTunnelMode tunnel_mode) -{ - switch (tunnel_mode) { - case NM_IP_TUNNEL_MODE_GRE: - return NM_LINK_TYPE_GRE; - case NM_IP_TUNNEL_MODE_GRETAP: - return NM_LINK_TYPE_GRETAP; - case NM_IP_TUNNEL_MODE_IPIP6: - case NM_IP_TUNNEL_MODE_IP6IP6: - return NM_LINK_TYPE_IP6TNL; - case NM_IP_TUNNEL_MODE_IP6GRE: - return NM_LINK_TYPE_IP6GRE; - case NM_IP_TUNNEL_MODE_IP6GRETAP: - return NM_LINK_TYPE_IP6GRETAP; - case NM_IP_TUNNEL_MODE_IPIP: - return NM_LINK_TYPE_IPIP; - case NM_IP_TUNNEL_MODE_SIT: - return NM_LINK_TYPE_SIT; - case NM_IP_TUNNEL_MODE_VTI: - case NM_IP_TUNNEL_MODE_VTI6: - case NM_IP_TUNNEL_MODE_ISATAP: - return NM_LINK_TYPE_UNKNOWN; - case NM_IP_TUNNEL_MODE_UNKNOWN: - break; - } - g_return_val_if_reached(NM_LINK_TYPE_UNKNOWN); -} - -/*****************************************************************************/ - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char * iface = nm_device_get_iface(device); - NMSettingIPTunnel * s_ip_tunnel; - NMPlatformLnkGre lnk_gre = {}; - NMPlatformLnkSit lnk_sit = {}; - NMPlatformLnkIpIp lnk_ipip = {}; - NMPlatformLnkIp6Tnl lnk_ip6tnl = {}; - const char * str; - gint64 val; - NMIPTunnelMode mode; - int r; - gs_free char * hwaddr = NULL; - guint8 mac_address[ETH_ALEN]; - gboolean mac_address_valid = FALSE; - - s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - nm_assert(NM_IS_SETTING_IP_TUNNEL(s_ip_tunnel)); - - mode = nm_setting_ip_tunnel_get_mode(s_ip_tunnel); - - if (_nm_ip_tunnel_mode_is_layer2(mode) - && nm_device_hw_addr_get_cloned(device, connection, FALSE, &hwaddr, NULL, NULL) && hwaddr) { - /* FIXME: we set the MAC address when creating the interface, while the - * NMDevice is still unrealized. As we afterwards realize the device, it - * forgets the parameters for the cloned MAC address, and in stage 1 - * it might create a different MAC address. That should be fixed by - * better handling device realization. */ - if (!nm_utils_hwaddr_aton(hwaddr, mac_address, ETH_ALEN)) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Invalid hardware address '%s'", - hwaddr); - g_return_val_if_reached(FALSE); - } - - mac_address_valid = TRUE; - } - - switch (mode) { - case NM_IP_TUNNEL_MODE_GRETAP: - lnk_gre.is_tap = TRUE; - /* fall-through */ - case NM_IP_TUNNEL_MODE_GRE: - if (parent) - lnk_gre.parent_ifindex = nm_device_get_ifindex(parent); - - str = nm_setting_ip_tunnel_get_local(s_ip_tunnel); - if (str) - inet_pton(AF_INET, str, &lnk_gre.local); - - str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel); - g_assert(str); - inet_pton(AF_INET, str, &lnk_gre.remote); - - lnk_gre.ttl = nm_setting_ip_tunnel_get_ttl(s_ip_tunnel); - lnk_gre.tos = nm_setting_ip_tunnel_get_tos(s_ip_tunnel); - lnk_gre.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel); - - val = _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), - 10, - 0, - G_MAXUINT32, - -1); - if (val != -1) { - lnk_gre.input_key = val; - lnk_gre.input_flags = NM_GRE_KEY; - } - - val = _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_output_key(s_ip_tunnel), - 10, - 0, - G_MAXUINT32, - -1); - if (val != -1) { - lnk_gre.output_key = val; - lnk_gre.output_flags = NM_GRE_KEY; - } - - r = nm_platform_link_gre_add(nm_device_get_platform(device), - iface, - mac_address_valid ? mac_address : NULL, - mac_address_valid ? ETH_ALEN : 0, - &lnk_gre, - out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create GRE interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - break; - case NM_IP_TUNNEL_MODE_SIT: - if (parent) - lnk_sit.parent_ifindex = nm_device_get_ifindex(parent); - - str = nm_setting_ip_tunnel_get_local(s_ip_tunnel); - if (str) - inet_pton(AF_INET, str, &lnk_sit.local); - - str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel); - g_assert(str); - inet_pton(AF_INET, str, &lnk_sit.remote); - - lnk_sit.ttl = nm_setting_ip_tunnel_get_ttl(s_ip_tunnel); - lnk_sit.tos = nm_setting_ip_tunnel_get_tos(s_ip_tunnel); - lnk_sit.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel); - - r = nm_platform_link_sit_add(nm_device_get_platform(device), iface, &lnk_sit, out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create SIT interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - break; - case NM_IP_TUNNEL_MODE_IPIP: - if (parent) - lnk_ipip.parent_ifindex = nm_device_get_ifindex(parent); - - str = nm_setting_ip_tunnel_get_local(s_ip_tunnel); - if (str) - inet_pton(AF_INET, str, &lnk_ipip.local); - - str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel); - g_assert(str); - inet_pton(AF_INET, str, &lnk_ipip.remote); - - lnk_ipip.ttl = nm_setting_ip_tunnel_get_ttl(s_ip_tunnel); - lnk_ipip.tos = nm_setting_ip_tunnel_get_tos(s_ip_tunnel); - lnk_ipip.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel); - - r = nm_platform_link_ipip_add(nm_device_get_platform(device), iface, &lnk_ipip, out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create IPIP interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - break; - case NM_IP_TUNNEL_MODE_IPIP6: - case NM_IP_TUNNEL_MODE_IP6IP6: - case NM_IP_TUNNEL_MODE_IP6GRE: - case NM_IP_TUNNEL_MODE_IP6GRETAP: - if (parent) - lnk_ip6tnl.parent_ifindex = nm_device_get_ifindex(parent); - - str = nm_setting_ip_tunnel_get_local(s_ip_tunnel); - if (str) - inet_pton(AF_INET6, str, &lnk_ip6tnl.local); - - str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel); - g_assert(str); - inet_pton(AF_INET6, str, &lnk_ip6tnl.remote); - - lnk_ip6tnl.ttl = nm_setting_ip_tunnel_get_ttl(s_ip_tunnel); - lnk_ip6tnl.tclass = nm_setting_ip_tunnel_get_tos(s_ip_tunnel); - lnk_ip6tnl.encap_limit = nm_setting_ip_tunnel_get_encapsulation_limit(s_ip_tunnel); - lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label(s_ip_tunnel); - lnk_ip6tnl.flags = - ip6tnl_flags_setting_to_plat(nm_setting_ip_tunnel_get_flags(s_ip_tunnel)); - - if (NM_IN_SET(mode, NM_IP_TUNNEL_MODE_IP6GRE, NM_IP_TUNNEL_MODE_IP6GRETAP)) { - val = _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), - 10, - 0, - G_MAXUINT32, - -1); - if (val != -1) { - lnk_ip6tnl.input_key = val; - lnk_ip6tnl.input_flags = NM_GRE_KEY; - } - - val = _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_output_key(s_ip_tunnel), - 10, - 0, - G_MAXUINT32, - -1); - if (val != -1) { - lnk_ip6tnl.output_key = val; - lnk_ip6tnl.output_flags = NM_GRE_KEY; - } - - lnk_ip6tnl.is_gre = TRUE; - lnk_ip6tnl.is_tap = (mode == NM_IP_TUNNEL_MODE_IP6GRETAP); - - r = nm_platform_link_ip6gre_add(nm_device_get_platform(device), - iface, - mac_address_valid ? mac_address : NULL, - mac_address_valid ? ETH_ALEN : 0, - &lnk_ip6tnl, - out_plink); - } else { - lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode(s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 - ? IPPROTO_IPIP - : IPPROTO_IPV6; - r = nm_platform_link_ip6tnl_add(nm_device_get_platform(device), - iface, - &lnk_ip6tnl, - out_plink); - } - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create IPv6 tunnel interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - break; - default: - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create IP tunnel interface '%s' for '%s': mode %d not supported", - iface, - nm_connection_get_id(connection), - (int) nm_setting_ip_tunnel_get_mode(s_ip_tunnel)); - return FALSE; - } - - return TRUE; -} - -static guint32 -get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - return nm_device_get_configured_mtu_from_connection(device, - NM_TYPE_SETTING_IP_TUNNEL, - out_source); -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static void -unrealize_notify(NMDevice *device) -{ - NM_DEVICE_CLASS(nm_device_ip_tunnel_parent_class)->unrealize_notify(device); - - update_properties_from_ifindex(device, 0); -} - -static gboolean -can_reapply_change(NMDevice * device, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error) -{ - NMDeviceClass *device_class; - - /* Only handle ip-tunnel setting here, delegate other settings to parent class */ - if (nm_streq(setting_name, NM_SETTING_IP_TUNNEL_SETTING_NAME)) { - return nm_device_hash_check_invalid_keys( - diffs, - NM_SETTING_IP_TUNNEL_SETTING_NAME, - error, - NM_SETTING_IP_TUNNEL_MTU); /* reapplied with IP config */ - } - - device_class = NM_DEVICE_CLASS(nm_device_ip_tunnel_parent_class); - return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceIPTunnel * self = NM_DEVICE_IP_TUNNEL(device); - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self); - - if (_nm_ip_tunnel_mode_is_layer2(priv->mode) - && !nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) { - *out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_MODE: - g_value_set_uint(value, priv->mode); - break; - case PROP_LOCAL: - g_value_set_string(value, priv->local); - break; - case PROP_REMOTE: - g_value_set_string(value, priv->remote); - break; - case PROP_TTL: - g_value_set_uchar(value, priv->ttl); - break; - case PROP_TOS: - g_value_set_uchar(value, priv->tos); - break; - case PROP_PATH_MTU_DISCOVERY: - g_value_set_boolean(value, priv->path_mtu_discovery); - break; - case PROP_INPUT_KEY: - g_value_set_string(value, priv->input_key); - break; - case PROP_OUTPUT_KEY: - g_value_set_string(value, priv->output_key); - break; - case PROP_ENCAPSULATION_LIMIT: - g_value_set_uchar(value, priv->encap_limit); - break; - case PROP_FLOW_LABEL: - g_value_set_uint(value, priv->flow_label); - break; - case PROP_FLAGS: - g_value_set_uint(value, priv->flags); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_MODE: - priv->mode = g_value_get_uint(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - } -} - -/*****************************************************************************/ - -static void -nm_device_ip_tunnel_init(NMDeviceIPTunnel *self) -{} - -static void -constructed(GObject *object) -{ - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(object); - - if (NM_IN_SET(priv->mode, - NM_IP_TUNNEL_MODE_IPIP6, - NM_IP_TUNNEL_MODE_IP6IP6, - NM_IP_TUNNEL_MODE_IP6GRE, - NM_IP_TUNNEL_MODE_IP6GRETAP)) - priv->addr_family = AF_INET6; - else - priv->addr_family = AF_INET; - - G_OBJECT_CLASS(nm_device_ip_tunnel_parent_class)->constructed(object); -} - -static void -dispose(GObject *object) -{ - NMDeviceIPTunnel * self = NM_DEVICE_IP_TUNNEL(object); - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self); - - nm_clear_g_free(&priv->local); - nm_clear_g_free(&priv->remote); - nm_clear_g_free(&priv->input_key); - nm_clear_g_free(&priv->output_key); - - G_OBJECT_CLASS(nm_device_ip_tunnel_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_ip_tunnel = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_IP_TUNNEL, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "u", NM_DEVICE_IP_TUNNEL_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Local", - "s", - NM_DEVICE_IP_TUNNEL_LOCAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Remote", - "s", - NM_DEVICE_IP_TUNNEL_REMOTE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ttl", "y", NM_DEVICE_IP_TUNNEL_TTL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Tos", "y", NM_DEVICE_IP_TUNNEL_TOS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( - "PathMtuDiscovery", - "b", - NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("InputKey", - "s", - NM_DEVICE_IP_TUNNEL_INPUT_KEY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("OutputKey", - "s", - NM_DEVICE_IP_TUNNEL_OUTPUT_KEY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( - "EncapsulationLimit", - "y", - NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("FlowLabel", - "u", - NM_DEVICE_IP_TUNNEL_FLOW_LABEL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Flags", - "u", - NM_DEVICE_IP_TUNNEL_FLAGS), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ip_tunnel_class_init(NMDeviceIPTunnelClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_ip_tunnel); - - device_class->connection_type_supported = NM_SETTING_IP_TUNNEL_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_IP_TUNNEL_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_GRE, - NM_LINK_TYPE_GRETAP, - NM_LINK_TYPE_IP6TNL, - NM_LINK_TYPE_IP6GRE, - NM_LINK_TYPE_IP6GRETAP, - NM_LINK_TYPE_IPIP, - NM_LINK_TYPE_SIT); - - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->link_changed = link_changed; - device_class->can_reapply_change = can_reapply_change; - device_class->complete_connection = complete_connection; - device_class->update_connection = update_connection; - device_class->check_connection_compatible = check_connection_compatible; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->get_configured_mtu = get_configured_mtu; - device_class->unrealize_notify = unrealize_notify; - - obj_properties[PROP_MODE] = - g_param_spec_uint(NM_DEVICE_IP_TUNNEL_MODE, - "", - "", - 0, - G_MAXUINT, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LOCAL] = g_param_spec_string(NM_DEVICE_IP_TUNNEL_LOCAL, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_REMOTE] = g_param_spec_string(NM_DEVICE_IP_TUNNEL_REMOTE, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_TTL] = g_param_spec_uchar(NM_DEVICE_IP_TUNNEL_TTL, - "", - "", - 0, - 255, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_TOS] = g_param_spec_uchar(NM_DEVICE_IP_TUNNEL_TOS, - "", - "", - 0, - 255, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_PATH_MTU_DISCOVERY] = - g_param_spec_boolean(NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_INPUT_KEY] = g_param_spec_string(NM_DEVICE_IP_TUNNEL_INPUT_KEY, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_OUTPUT_KEY] = - g_param_spec_string(NM_DEVICE_IP_TUNNEL_OUTPUT_KEY, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ENCAPSULATION_LIMIT] = - g_param_spec_uchar(NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, - "", - "", - 0, - 255, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_FLOW_LABEL] = g_param_spec_uint(NM_DEVICE_IP_TUNNEL_FLOW_LABEL, - "", - "", - 0, - (1 << 20) - 1, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_FLAGS] = g_param_spec_uint(NM_DEVICE_IP_TUNNEL_FLAGS, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_IP_TUNNEL_DEVICE_FACTORY (nm_ip_tunnel_device_factory_get_type()) -#define NM_IP_TUNNEL_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_IP_TUNNEL_DEVICE_FACTORY, NMIPTunnelDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - NMSettingIPTunnel *s_ip_tunnel; - NMIPTunnelMode mode; - NMLinkType link_type; - - if (connection) { - s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - mode = nm_setting_ip_tunnel_get_mode(s_ip_tunnel); - link_type = tunnel_mode_to_link_type(mode); - } else { - link_type = plink->type; - mode = platform_link_to_tunnel_mode(plink); - } - - if (mode == NM_IP_TUNNEL_MODE_UNKNOWN || link_type == NM_LINK_TYPE_UNKNOWN) - return NULL; - - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_IP_TUNNEL, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "IPTunnel", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_IP_TUNNEL, - NM_DEVICE_LINK_TYPE, - link_type, - NM_DEVICE_IP_TUNNEL_MODE, - mode, - NULL); -} - -static const char * -get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSettingIPTunnel *s_ip_tunnel; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), - NULL); - - s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - g_assert(s_ip_tunnel); - - return nm_setting_ip_tunnel_get_parent(s_ip_tunnel); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - const char * ifname; - NMSettingIPTunnel *s_ip_tunnel; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), - NULL); - - s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection); - g_assert(s_ip_tunnel); - - if (nm_setting_ip_tunnel_get_parent(s_ip_tunnel) && !parent_iface) - return NULL; - - ifname = nm_connection_get_interface_name(connection); - - return g_strdup(ifname); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - IP_TUNNEL, - IPTunnel, - ip_tunnel, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_GRE, - NM_LINK_TYPE_GRETAP, - NM_LINK_TYPE_SIT, - NM_LINK_TYPE_IPIP, - NM_LINK_TYPE_IP6TNL, - NM_LINK_TYPE_IP6GRE, - NM_LINK_TYPE_IP6GRETAP) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_IP_TUNNEL_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); diff --git a/src/devices/nm-device-ip-tunnel.h b/src/devices/nm-device-ip-tunnel.h deleted file mode 100644 index 0d9211ec..00000000 --- a/src/devices/nm-device-ip-tunnel.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__ -#define __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__ - -#include "nm-core-types.h" -#include "nm-device.h" - -#define NM_TYPE_DEVICE_IP_TUNNEL (nm_device_ip_tunnel_get_type()) -#define NM_DEVICE_IP_TUNNEL(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel)) -#define NM_DEVICE_IP_TUNNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) -#define NM_IS_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IP_TUNNEL)) -#define NM_IS_DEVICE_IP_TUNNEL_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_IP_TUNNEL)) -#define NM_DEVICE_IP_TUNNEL_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) - -#define NM_DEVICE_IP_TUNNEL_MODE "mode" -#define NM_DEVICE_IP_TUNNEL_LOCAL "local" -#define NM_DEVICE_IP_TUNNEL_REMOTE "remote" -#define NM_DEVICE_IP_TUNNEL_TTL "ttl" -#define NM_DEVICE_IP_TUNNEL_TOS "tos" -#define NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery" -#define NM_DEVICE_IP_TUNNEL_INPUT_KEY "input-key" -#define NM_DEVICE_IP_TUNNEL_OUTPUT_KEY "output-key" -#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit" -#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label" -#define NM_DEVICE_IP_TUNNEL_FLAGS "flags" - -typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; -typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass; - -GType nm_device_ip_tunnel_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__ */ diff --git a/src/devices/nm-device-logging.h b/src/devices/nm-device-logging.h deleted file mode 100644 index d1291020..00000000 --- a/src/devices/nm-device-logging.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_LOGGING_H__ -#define __NETWORKMANAGER_DEVICE_LOGGING_H__ - -#include "nm-device.h" - -#define _LOG_DECLARE_SELF(t) \ - _nm_unused static inline NMDevice *_nm_device_log_self_to_device(t *self) \ - { \ - return (NMDevice *) self; \ - } - -#undef _NMLOG_ENABLED -#define _NMLOG_ENABLED(level, domain) (nm_logging_enabled((level), (domain))) -#define _NMLOG(level, domain, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - const NMLogDomain _domain = (domain); \ - \ - if (nm_logging_enabled(_level, _domain)) { \ - typeof(*self) *const _self = (self); \ - const char *const _ifname = \ - _nm_device_get_iface(_nm_device_log_self_to_device(_self)); \ - \ - nm_log_obj(_level, \ - _domain, \ - _ifname, \ - NULL, \ - _self, \ - "device", \ - "%s%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - NM_PRINT_FMT_QUOTED(_ifname, "(", _ifname, ")", "[null]") \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -#endif /* __NETWORKMANAGER_DEVICE_LOGGING_H__ */ diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c deleted file mode 100644 index 7d738b42..00000000 --- a/src/devices/nm-device-macsec.c +++ /dev/null @@ -1,1088 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-macsec.h" - -#include "nm-act-request.h" -#include "nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-manager.h" -#include "nm-setting-macsec.h" -#include "nm-core-internal.h" -#include "supplicant/nm-supplicant-manager.h" -#include "supplicant/nm-supplicant-interface.h" -#include "supplicant/nm-supplicant-config.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceMacsec); - -/*****************************************************************************/ - -#define SUPPLICANT_LNK_TIMEOUT_SEC 15 - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceMacsec, - PROP_SCI, - PROP_CIPHER_SUITE, - PROP_ICV_LENGTH, - PROP_WINDOW, - PROP_ENCODING_SA, - PROP_ENCRYPT, - PROP_PROTECT, - PROP_INCLUDE_SCI, - PROP_ES, - PROP_SCB, - PROP_REPLAY_PROTECT, - PROP_VALIDATION, ); - -typedef struct { - NMPlatformLnkMacsec props; - gulong parent_state_id; - gulong parent_mtu_id; - - struct { - NMSupplicantManager * mgr; - NMSupplMgrCreateIfaceHandle *create_handle; - NMSupplicantInterface * iface; - - gulong iface_state_id; - - guint con_timeout_id; - guint lnk_timeout_id; - - bool is_associated : 1; - } supplicant; - - NMActRequestGetSecretsCallId *macsec_secrets_id; -} NMDeviceMacsecPrivate; - -struct _NMDeviceMacsec { - NMDevice parent; - NMDeviceMacsecPrivate _priv; -}; - -struct _NMDeviceMacsecClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceMacsec, nm_device_macsec, NM_TYPE_DEVICE) - -#define NM_DEVICE_MACSEC_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceMacsec, NM_IS_DEVICE_MACSEC, NMDevice) - -/******************************************************************/ - -static void macsec_secrets_cancel(NMDeviceMacsec *self); - -/******************************************************************/ - -static NM_UTILS_LOOKUP_STR_DEFINE(validation_mode_to_string, - guint8, - NM_UTILS_LOOKUP_DEFAULT_WARN("<unknown>"), - NM_UTILS_LOOKUP_STR_ITEM(0, "disable"), - NM_UTILS_LOOKUP_STR_ITEM(1, "check"), - NM_UTILS_LOOKUP_STR_ITEM(2, "strict"), ); - -static void -parent_state_changed(NMDevice * parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceMacsec *self = NM_DEVICE_MACSEC(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void -parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) -{ - /* the MTU of a MACsec device is limited by the parent's MTU. - * - * When the parent's MTU changes, try to re-set the MTU. */ - nm_device_commit_mtu(user_data); -} - -static void -parent_changed_notify(NMDevice *device, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent) -{ - NMDeviceMacsec * self = NM_DEVICE_MACSEC(device); - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - NM_DEVICE_CLASS(nm_device_macsec_parent_class) - ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); - nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); - - if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - priv->parent_mtu_id = g_signal_connect(new_parent, - "notify::" NM_DEVICE_MTU, - G_CALLBACK(parent_mtu_maybe_changed), - device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); - } - - /* Recheck availability now that the parent has changed */ - if (new_ifindex > 0) { - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_PARENT_CHANGED, - NM_DEVICE_STATE_REASON_PARENT_CHANGED); - } -} - -static void -update_properties(NMDevice *device) -{ - NMDeviceMacsec * self; - NMDeviceMacsecPrivate * priv; - const NMPlatformLink * plink = NULL; - const NMPlatformLnkMacsec *props = NULL; - int ifindex; - - g_return_if_fail(NM_IS_DEVICE_MACSEC(device)); - self = NM_DEVICE_MACSEC(device); - priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - ifindex = nm_device_get_ifindex(device); - g_return_if_fail(ifindex > 0); - props = nm_platform_link_get_lnk_macsec(nm_device_get_platform(device), ifindex, &plink); - - if (!props) { - _LOGW(LOGD_PLATFORM, "could not get macsec properties"); - return; - } - - g_object_freeze_notify((GObject *) device); - - if (priv->props.parent_ifindex != props->parent_ifindex) - nm_device_parent_set_ifindex(device, props->parent_ifindex); - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START \ - { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - - CHECK_PROPERTY_CHANGED(sci, PROP_SCI); - CHECK_PROPERTY_CHANGED(cipher_suite, PROP_CIPHER_SUITE); - CHECK_PROPERTY_CHANGED(window, PROP_WINDOW); - CHECK_PROPERTY_CHANGED(icv_length, PROP_ICV_LENGTH); - CHECK_PROPERTY_CHANGED(encoding_sa, PROP_ENCODING_SA); - CHECK_PROPERTY_CHANGED(validation, PROP_VALIDATION); - CHECK_PROPERTY_CHANGED(encrypt, PROP_ENCRYPT); - CHECK_PROPERTY_CHANGED(protect, PROP_PROTECT); - CHECK_PROPERTY_CHANGED(include_sci, PROP_INCLUDE_SCI); - CHECK_PROPERTY_CHANGED(es, PROP_ES); - CHECK_PROPERTY_CHANGED(scb, PROP_SCB); - CHECK_PROPERTY_CHANGED(replay_protect, PROP_REPLAY_PROTECT); - - g_object_thaw_notify((GObject *) device); -} - -static NMSupplicantConfig * -build_supplicant_config(NMDeviceMacsec *self, GError **error) -{ - gs_unref_object NMSupplicantConfig *config = NULL; - NMSettingMacsec * s_macsec; - NMSetting8021x * s_8021x; - NMConnection * connection; - const char * con_uuid; - guint32 mtu; - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - - g_return_val_if_fail(connection, NULL); - - con_uuid = nm_connection_get_uuid(connection); - mtu = nm_platform_link_get_mtu(nm_device_get_platform(NM_DEVICE(self)), - nm_device_get_ifindex(NM_DEVICE(self))); - - config = nm_supplicant_config_new(NM_SUPPL_CAP_MASK_NONE); - - s_macsec = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_MACSEC); - - g_return_val_if_fail(s_macsec, NULL); - - if (!nm_supplicant_config_add_setting_macsec(config, s_macsec, error)) { - g_prefix_error(error, "macsec-setting: "); - return NULL; - } - - if (nm_setting_macsec_get_mode(s_macsec) == NM_SETTING_MACSEC_MODE_EAP) { - s_8021x = nm_connection_get_setting_802_1x(connection); - if (!nm_supplicant_config_add_setting_8021x(config, s_8021x, con_uuid, mtu, TRUE, error)) { - g_prefix_error(error, "802-1x-setting: "); - return NULL; - } - } - - return g_steal_pointer(&config); -} - -static void -supplicant_interface_release(NMDeviceMacsec *self) -{ - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - nm_clear_pointer(&priv->supplicant.create_handle, - nm_supplicant_manager_create_interface_cancel); - - nm_clear_g_source(&priv->supplicant.lnk_timeout_id); - nm_clear_g_source(&priv->supplicant.con_timeout_id); - nm_clear_g_signal_handler(priv->supplicant.iface, &priv->supplicant.iface_state_id); - - if (priv->supplicant.iface) { - nm_supplicant_interface_disconnect(priv->supplicant.iface); - g_clear_object(&priv->supplicant.iface); - } -} - -static void -macsec_secrets_cb(NMActRequest * req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * connection, - GError * error, - gpointer user_data) -{ - NMDeviceMacsec * self = NM_DEVICE_MACSEC(user_data); - NMDevice * device = NM_DEVICE(self); - NMDeviceMacsecPrivate *priv; - - g_return_if_fail(NM_IS_DEVICE_MACSEC(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - g_return_if_fail(priv->macsec_secrets_id == call_id); - - priv->macsec_secrets_id = NULL; - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - g_return_if_fail(req == nm_device_get_act_request(device)); - g_return_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_NEED_AUTH); - g_return_if_fail(nm_act_request_get_settings_connection(req) == connection); - - if (error) { - _LOGW(LOGD_ETHER, "%s", error->message); - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -macsec_secrets_cancel(NMDeviceMacsec *self) -{ - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - if (priv->macsec_secrets_id) - nm_act_request_cancel_secrets(NULL, priv->macsec_secrets_id); - nm_assert(!priv->macsec_secrets_id); -} - -static void -macsec_secrets_get_secrets(NMDeviceMacsec * self, - const char * setting_name, - NMSecretAgentGetSecretsFlags flags) -{ - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - NMActRequest * req; - - macsec_secrets_cancel(self); - - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv->macsec_secrets_id = - nm_act_request_get_secrets(req, TRUE, setting_name, flags, NULL, macsec_secrets_cb, self); - g_return_if_fail(priv->macsec_secrets_id); -} - -static gboolean -supplicant_lnk_timeout_cb(gpointer user_data) -{ - NMDeviceMacsec * self = NM_DEVICE_MACSEC(user_data); - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - NMDevice * dev = NM_DEVICE(self); - NMActRequest * req; - NMConnection * applied_connection; - const char * setting_name; - - priv->supplicant.lnk_timeout_id = 0; - - req = nm_device_get_act_request(dev); - - if (nm_device_get_state(dev) == NM_DEVICE_STATE_ACTIVATED) { - nm_device_state_changed(dev, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); - return G_SOURCE_REMOVE; - } - - /* Disconnect event during initial authentication and credentials - * ARE checked - we are likely to have wrong key. Ask the user for - * another one. - */ - if (nm_device_get_state(dev) != NM_DEVICE_STATE_CONFIG) - goto time_out; - - nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(req)); - - applied_connection = nm_act_request_get_applied_connection(req); - setting_name = nm_connection_need_secrets(applied_connection, NULL); - if (!setting_name) - goto time_out; - - _LOGI(LOGD_DEVICE | LOGD_ETHER, - "Activation: disconnected during authentication, asking for new key."); - supplicant_interface_release(self); - - nm_device_state_changed(dev, - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - macsec_secrets_get_secrets(self, setting_name, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); - - return G_SOURCE_REMOVE; - -time_out: - _LOGW(LOGD_DEVICE | LOGD_ETHER, "link timed out."); - nm_device_state_changed(dev, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - - return G_SOURCE_REMOVE; -} - -static void -supplicant_iface_state_is_completed(NMDeviceMacsec *self, NMSupplicantInterfaceState state) -{ - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - if (state == NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) { - nm_clear_g_source(&priv->supplicant.lnk_timeout_id); - nm_clear_g_source(&priv->supplicant.con_timeout_id); - - nm_device_bring_up(NM_DEVICE(self), TRUE, NULL); - - /* If this is the initial association during device activation, - * schedule the next activation stage. - */ - if (nm_device_get_state(NM_DEVICE(self)) == NM_DEVICE_STATE_CONFIG) { - _LOGI(LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) successful."); - nm_device_activate_schedule_stage3_ip_config_start(NM_DEVICE(self)); - } - return; - } - - if (!priv->supplicant.lnk_timeout_id && !priv->supplicant.con_timeout_id) - priv->supplicant.lnk_timeout_id = - g_timeout_add_seconds(SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self); -} - -static void -supplicant_iface_assoc_cb(NMSupplicantInterface *iface, GError *error, gpointer user_data) -{ - NMDeviceMacsec * self; - NMDeviceMacsecPrivate *priv; - - if (nm_utils_error_is_cancelled_or_disposing(error)) - return; - - self = user_data; - priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - if (error) { - supplicant_interface_release(self); - nm_device_queue_state(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - return; - } - - nm_assert(!priv->supplicant.lnk_timeout_id); - nm_assert(!priv->supplicant.is_associated); - - priv->supplicant.is_associated = TRUE; - supplicant_iface_state_is_completed(self, - nm_supplicant_interface_get_state(priv->supplicant.iface)); -} - -static gboolean -supplicant_iface_start(NMDeviceMacsec *self) -{ - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - gs_unref_object NMSupplicantConfig *config = NULL; - gs_free_error GError *error = NULL; - - config = build_supplicant_config(self, &error); - if (!config) { - _LOGE(LOGD_DEVICE, "Activation: couldn't build security configuration: %s", error->message); - supplicant_interface_release(self); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - return FALSE; - } - - nm_supplicant_interface_disconnect(priv->supplicant.iface); - nm_supplicant_interface_assoc(priv->supplicant.iface, config, supplicant_iface_assoc_cb, self); - return TRUE; -} - -static void -supplicant_iface_state_cb(NMSupplicantInterface *iface, - int new_state_i, - int old_state_i, - int disconnect_reason, - gpointer user_data) -{ - NMDeviceMacsec * self = NM_DEVICE_MACSEC(user_data); - NMDeviceMacsecPrivate * priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - NMSupplicantInterfaceState new_state = new_state_i; - NMSupplicantInterfaceState old_state = old_state_i; - - _LOGI(LOGD_DEVICE, - "supplicant interface state: %s -> %s", - nm_supplicant_interface_state_to_string(old_state), - nm_supplicant_interface_state_to_string(new_state)); - - if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - supplicant_interface_release(self); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return; - } - - if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { - if (!supplicant_iface_start(self)) - return; - } - - if (priv->supplicant.is_associated) - supplicant_iface_state_is_completed(self, new_state); -} - -static gboolean -handle_auth_or_fail(NMDeviceMacsec *self, NMActRequest *req, gboolean new_secrets) -{ - const char * setting_name; - NMConnection *applied_connection; - - if (!nm_device_auth_retries_try_next(NM_DEVICE(self))) - return FALSE; - - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_NONE); - - nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(req)); - - applied_connection = nm_act_request_get_applied_connection(req); - setting_name = nm_connection_need_secrets(applied_connection, NULL); - if (!setting_name) { - _LOGI(LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return FALSE; - } - - macsec_secrets_get_secrets( - self, - setting_name, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION - | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0)); - return TRUE; -} - -static gboolean -supplicant_connection_timeout_cb(gpointer user_data) -{ - NMDeviceMacsec * self = NM_DEVICE_MACSEC(user_data); - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMActRequest * req; - NMSettingsConnection * connection; - guint64 timestamp = 0; - gboolean new_secrets = TRUE; - - priv->supplicant.con_timeout_id = 0; - - /* Authentication failed; either driver problems, the encryption key is - * wrong, the passwords or certificates were wrong or the Ethernet switch's - * port is not configured for 802.1x. */ - _LOGW(LOGD_DEVICE, "Activation: (macsec) association took too long."); - - supplicant_interface_release(self); - - req = nm_device_get_act_request(device); - connection = nm_act_request_get_settings_connection(req); - g_return_val_if_fail(connection, G_SOURCE_REMOVE); - - /* Ask for new secrets only if we've never activated this connection - * before. If we've connected before, don't bother the user with dialogs, - * just retry or fail, and if we never connect the user can fix the - * password somewhere else. */ - if (nm_settings_connection_get_timestamp(connection, ×tamp)) - new_secrets = !timestamp; - - if (!handle_auth_or_fail(self, req, new_secrets)) { - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return G_SOURCE_REMOVE; - } - - _LOGW(LOGD_DEVICE, "Activation: (macsec) asking for new secrets"); - - if (!priv->supplicant.lnk_timeout_id && priv->supplicant.iface) { - NMSupplicantInterfaceState state; - - state = nm_supplicant_interface_get_state(priv->supplicant.iface); - if (state != NM_SUPPLICANT_INTERFACE_STATE_COMPLETED - && nm_supplicant_interface_state_is_operational(state)) - priv->supplicant.lnk_timeout_id = - g_timeout_add_seconds(SUPPLICANT_LNK_TIMEOUT_SEC, supplicant_lnk_timeout_cb, self); - } - - return G_SOURCE_REMOVE; -} - -static void -supplicant_interface_create_cb(NMSupplicantManager * supplicant_manager, - NMSupplMgrCreateIfaceHandle *handle, - NMSupplicantInterface * iface, - GError * error, - gpointer user_data) -{ - NMDeviceMacsec * self; - NMDeviceMacsecPrivate *priv; - guint timeout; - - if (nm_utils_error_is_cancelled(error)) - return; - - self = user_data; - priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - nm_assert(priv->supplicant.create_handle == handle); - - priv->supplicant.create_handle = NULL; - - if (error) { - _LOGE(LOGD_DEVICE, "Couldn't initialize supplicant interface: %s", error->message); - supplicant_interface_release(self); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return; - } - - priv->supplicant.iface = g_object_ref(iface); - priv->supplicant.is_associated = FALSE; - - priv->supplicant.iface_state_id = g_signal_connect(priv->supplicant.iface, - NM_SUPPLICANT_INTERFACE_STATE, - G_CALLBACK(supplicant_iface_state_cb), - self); - - timeout = nm_device_get_supplicant_timeout(NM_DEVICE(self)); - priv->supplicant.con_timeout_id = - g_timeout_add_seconds(timeout, supplicant_connection_timeout_cb, self); - - if (nm_supplicant_interface_state_is_operational(nm_supplicant_interface_get_state(iface))) - supplicant_iface_start(self); -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceMacsec * self = NM_DEVICE_MACSEC(device); - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - NMConnection * connection; - NMDevice * parent; - const char * setting_name; - int ifindex; - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - if (!priv->supplicant.mgr) - priv->supplicant.mgr = g_object_ref(nm_supplicant_manager_get()); - - /* If we need secrets, get them */ - setting_name = nm_connection_need_secrets(connection, NULL); - if (setting_name) { - NMActRequest *req = nm_device_get_act_request(NM_DEVICE(self)); - - _LOGI(LOGD_DEVICE, - "Activation: connection '%s' has security, but secrets are required.", - nm_connection_get_id(connection)); - - if (!handle_auth_or_fail(self, req, FALSE)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - _LOGI(LOGD_DEVICE | LOGD_ETHER, - "Activation: connection '%s' requires no security. No secrets needed.", - nm_connection_get_id(connection)); - - supplicant_interface_release(self); - - parent = nm_device_parent_get_device(NM_DEVICE(self)); - g_return_val_if_fail(parent, NM_ACT_STAGE_RETURN_FAILURE); - ifindex = nm_device_get_ifindex(parent); - g_return_val_if_fail(ifindex > 0, NM_ACT_STAGE_RETURN_FAILURE); - - priv->supplicant.create_handle = - nm_supplicant_manager_create_interface(priv->supplicant.mgr, - ifindex, - NM_SUPPLICANT_DRIVER_MACSEC, - supplicant_interface_create_cb, - self); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceMacsec *self = NM_DEVICE_MACSEC(device); - - supplicant_interface_release(self); -} - -/******************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - /* We assume MACsec interfaces always support carrier detect */ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -/******************************************************************/ - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_macsec_parent_class)->is_available(device, flags); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char * iface = nm_device_get_iface(device); - NMSettingMacsec * s_macsec; - NMPlatformLnkMacsec lnk = {}; - int parent_ifindex; - const char * hw_addr; - union { - struct { - guint8 mac[6]; - guint16 port; - } s; - guint64 u; - } sci; - int r; - - s_macsec = nm_connection_get_setting_macsec(connection); - g_assert(s_macsec); - - if (!parent) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "MACsec devices can not be created without a parent interface"); - return FALSE; - } - - lnk.encrypt = nm_setting_macsec_get_encrypt(s_macsec); - - hw_addr = nm_device_get_hw_address(parent); - if (!hw_addr) { - g_set_error(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "can't read parent MAC"); - return FALSE; - } - - nm_utils_hwaddr_aton(hw_addr, sci.s.mac, ETH_ALEN); - sci.s.port = htons(nm_setting_macsec_get_port(s_macsec)); - lnk.sci = be64toh(sci.u); - lnk.validation = nm_setting_macsec_get_validation(s_macsec); - lnk.include_sci = nm_setting_macsec_get_send_sci(s_macsec); - - parent_ifindex = nm_device_get_ifindex(parent); - g_warn_if_fail(parent_ifindex > 0); - - r = nm_platform_link_macsec_add(nm_device_get_platform(device), - iface, - parent_ifindex, - &lnk, - out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create macsec interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - nm_device_parent_set_ifindex(device, parent_ifindex); - - return TRUE; -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_macsec_parent_class)->link_changed(device, pllink); - update_properties(device); -} - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - if (new_state > NM_DEVICE_STATE_ACTIVATED) - macsec_secrets_cancel(NM_DEVICE_MACSEC(device)); -} - -/******************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceMacsec * self = NM_DEVICE_MACSEC(object); - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_SCI: - g_value_set_uint64(value, priv->props.sci); - break; - case PROP_CIPHER_SUITE: - g_value_set_uint64(value, priv->props.cipher_suite); - break; - case PROP_ICV_LENGTH: - g_value_set_uchar(value, priv->props.icv_length); - break; - case PROP_WINDOW: - g_value_set_uint(value, priv->props.window); - break; - case PROP_ENCODING_SA: - g_value_set_uchar(value, priv->props.encoding_sa); - break; - case PROP_ENCRYPT: - g_value_set_boolean(value, priv->props.encrypt); - break; - case PROP_PROTECT: - g_value_set_boolean(value, priv->props.protect); - break; - case PROP_INCLUDE_SCI: - g_value_set_boolean(value, priv->props.include_sci); - break; - case PROP_ES: - g_value_set_boolean(value, priv->props.es); - break; - case PROP_SCB: - g_value_set_boolean(value, priv->props.scb); - break; - case PROP_REPLAY_PROTECT: - g_value_set_boolean(value, priv->props.replay_protect); - break; - case PROP_VALIDATION: - g_value_set_string(value, validation_mode_to_string(priv->props.validation)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -nm_device_macsec_init(NMDeviceMacsec *self) -{} - -static void -dispose(GObject *object) -{ - NMDeviceMacsec *self = NM_DEVICE_MACSEC(object); - - macsec_secrets_cancel(self); - supplicant_interface_release(self); - - G_OBJECT_CLASS(nm_device_macsec_parent_class)->dispose(object); - - nm_assert(NM_DEVICE_MACSEC_GET_PRIVATE(self)->parent_state_id == 0); - nm_assert(NM_DEVICE_MACSEC_GET_PRIVATE(self)->parent_mtu_id == 0); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_macsec = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_MACSEC, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Sci", "t", NM_DEVICE_MACSEC_SCI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("IcvLength", - "y", - NM_DEVICE_MACSEC_ICV_LENGTH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("CipherSuite", - "t", - NM_DEVICE_MACSEC_CIPHER_SUITE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Window", - "u", - NM_DEVICE_MACSEC_WINDOW), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("EncodingSa", - "y", - NM_DEVICE_MACSEC_ENCODING_SA), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Validation", - "s", - NM_DEVICE_MACSEC_VALIDATION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Encrypt", - "b", - NM_DEVICE_MACSEC_ENCRYPT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Protect", - "b", - NM_DEVICE_MACSEC_PROTECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("IncludeSci", - "b", - NM_DEVICE_MACSEC_INCLUDE_SCI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Es", "b", NM_DEVICE_MACSEC_ES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Scb", "b", NM_DEVICE_MACSEC_SCB), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ReplayProtect", - "b", - NM_DEVICE_MACSEC_REPLAY_PROTECT), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_macsec_class_init(NMDeviceMacsecClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - object_class->dispose = dispose; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_macsec); - - device_class->connection_type_supported = NM_SETTING_MACSEC_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_MACSEC_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_MACSEC); - device_class->mtu_parent_delta = 32; - - device_class->act_stage2_config = act_stage2_config; - device_class->create_and_realize = create_and_realize; - device_class->deactivate = deactivate; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->link_changed = link_changed; - device_class->is_available = is_available; - device_class->parent_changed_notify = parent_changed_notify; - device_class->state_changed = device_state_changed; - device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; - - obj_properties[PROP_SCI] = g_param_spec_uint64(NM_DEVICE_MACSEC_SCI, - "", - "", - 0, - G_MAXUINT64, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_CIPHER_SUITE] = - g_param_spec_uint64(NM_DEVICE_MACSEC_CIPHER_SUITE, - "", - "", - 0, - G_MAXUINT64, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ICV_LENGTH] = g_param_spec_uchar(NM_DEVICE_MACSEC_ICV_LENGTH, - "", - "", - 0, - G_MAXUINT8, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_WINDOW] = g_param_spec_uint(NM_DEVICE_MACSEC_WINDOW, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ENCODING_SA] = - g_param_spec_uchar(NM_DEVICE_MACSEC_ENCODING_SA, - "", - "", - 0, - 3, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_VALIDATION] = - g_param_spec_string(NM_DEVICE_MACSEC_VALIDATION, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ENCRYPT] = g_param_spec_boolean(NM_DEVICE_MACSEC_ENCRYPT, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PROTECT] = g_param_spec_boolean(NM_DEVICE_MACSEC_PROTECT, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_INCLUDE_SCI] = - g_param_spec_boolean(NM_DEVICE_MACSEC_INCLUDE_SCI, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ES] = g_param_spec_boolean(NM_DEVICE_MACSEC_ES, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_SCB] = g_param_spec_boolean(NM_DEVICE_MACSEC_SCB, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_REPLAY_PROTECT] = - g_param_spec_boolean(NM_DEVICE_MACSEC_REPLAY_PROTECT, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*************************************************************/ - -#define NM_TYPE_MACSEC_DEVICE_FACTORY (nm_macsec_device_factory_get_type()) -#define NM_MACSEC_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACSEC_DEVICE_FACTORY, NMMacsecDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_MACSEC, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Macsec", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_MACSEC, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_MACSEC, - NULL); -} - -static const char * -get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSettingMacsec *s_macsec; - NMSettingWired * s_wired; - const char * parent = NULL; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_MACSEC_SETTING_NAME), NULL); - - s_macsec = nm_connection_get_setting_macsec(connection); - g_assert(s_macsec); - - parent = nm_setting_macsec_get_parent(s_macsec); - if (parent) - return parent; - - /* Try the hardware address from the MACsec connection's hardware setting */ - s_wired = nm_connection_get_setting_wired(connection); - if (s_wired) - return nm_setting_wired_get_mac_address(s_wired); - - return NULL; -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - NMSettingMacsec *s_macsec; - const char * ifname; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_MACSEC_SETTING_NAME), NULL); - - s_macsec = nm_connection_get_setting_macsec(connection); - g_assert(s_macsec); - - if (!parent_iface) - return NULL; - - ifname = nm_connection_get_interface_name(connection); - return g_strdup(ifname); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - MACSEC, - Macsec, - macsec, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_MACSEC) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_MACSEC_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;) diff --git a/src/devices/nm-device-macsec.h b/src/devices/nm-device-macsec.h deleted file mode 100644 index 9a2f230b..00000000 --- a/src/devices/nm-device-macsec.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NM_DEVICE_MACSEC_H__ -#define __NM_DEVICE_MACSEC_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_MACSEC (nm_device_macsec_get_type()) -#define NM_DEVICE_MACSEC(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsec)) -#define NM_DEVICE_MACSEC_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsecClass)) -#define NM_IS_DEVICE_MACSEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MACSEC)) -#define NM_IS_DEVICE_MACSEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_MACSEC)) -#define NM_DEVICE_MACSEC_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_MACSEC, NMDeviceMacsecClass)) - -#define NM_DEVICE_MACSEC_SCI "sci" -#define NM_DEVICE_MACSEC_CIPHER_SUITE "cipher-suite" -#define NM_DEVICE_MACSEC_ICV_LENGTH "icv-length" -#define NM_DEVICE_MACSEC_WINDOW "window" -#define NM_DEVICE_MACSEC_ENCODING_SA "encoding-sa" -#define NM_DEVICE_MACSEC_VALIDATION "validation" -#define NM_DEVICE_MACSEC_ENCRYPT "encrypt" -#define NM_DEVICE_MACSEC_PROTECT "protect" -#define NM_DEVICE_MACSEC_INCLUDE_SCI "include-sci" -#define NM_DEVICE_MACSEC_ES "es" -#define NM_DEVICE_MACSEC_SCB "scb" -#define NM_DEVICE_MACSEC_REPLAY_PROTECT "replay-protect" - -typedef struct _NMDeviceMacsec NMDeviceMacsec; -typedef struct _NMDeviceMacsecClass NMDeviceMacsecClass; - -GType nm_device_macsec_get_type(void); - -#endif /* __NM_DEVICE_MACSEC_H__ */ diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c deleted file mode 100644 index d9e71c8c..00000000 --- a/src/devices/nm-device-macvlan.c +++ /dev/null @@ -1,665 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-macvlan.h" - -#include <linux/if_link.h> - -#include "nm-device-private.h" -#include "settings/nm-settings.h" -#include "nm-act-request.h" -#include "nm-manager.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-setting-macvlan.h" -#include "nm-setting-wired.h" -#include "nm-active-connection.h" -#include "nm-ip4-config.h" -#include "nm-utils.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceMacvlan); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceMacvlan, PROP_MODE, PROP_NO_PROMISC, PROP_TAP, ); - -typedef struct { - gulong parent_state_id; - gulong parent_mtu_id; - NMPlatformLnkMacvlan props; -} NMDeviceMacvlanPrivate; - -struct _NMDeviceMacvlan { - NMDevice parent; - NMDeviceMacvlanPrivate _priv; -}; - -struct _NMDeviceMacvlanClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceMacvlan, nm_device_macvlan, NM_TYPE_DEVICE) - -#define NM_DEVICE_MACVLAN_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceMacvlan, NM_IS_DEVICE_MACVLAN, NMDevice) - -/*****************************************************************************/ - -static int modes[][2] = { - {NM_SETTING_MACVLAN_MODE_VEPA, MACVLAN_MODE_VEPA}, - {NM_SETTING_MACVLAN_MODE_BRIDGE, MACVLAN_MODE_BRIDGE}, - {NM_SETTING_MACVLAN_MODE_PRIVATE, MACVLAN_MODE_PRIVATE}, - {NM_SETTING_MACVLAN_MODE_PASSTHRU, MACVLAN_MODE_PASSTHRU}, -}; - -static int -setting_mode_to_platform(int mode) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS(modes); i++) { - if (modes[i][0] == mode) - return modes[i][1]; - } - - return 0; -} - -static int -platform_mode_to_setting(int mode) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS(modes); i++) { - if (modes[i][1] == mode) - return modes[i][0]; - } - - return 0; -} - -static const char * -platform_mode_to_string(guint mode) -{ - switch (mode) { - case MACVLAN_MODE_PRIVATE: - return "private"; - case MACVLAN_MODE_VEPA: - return "vepa"; - case MACVLAN_MODE_BRIDGE: - return "bridge"; - case MACVLAN_MODE_PASSTHRU: - return "passthru"; - default: - return "unknown"; - } -} - -/*****************************************************************************/ - -static void -parent_state_changed(NMDevice * parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceMacvlan *self = NM_DEVICE_MACVLAN(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void -parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) -{ - /* the MTU of a macvlan/macvtap device is limited by the parent's MTU. - * - * When the parent's MTU changes, try to re-set the MTU. */ - nm_device_commit_mtu(user_data); -} - -static void -parent_changed_notify(NMDevice *device, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent) -{ - NMDeviceMacvlan * self = NM_DEVICE_MACVLAN(device); - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE(self); - - NM_DEVICE_CLASS(nm_device_macvlan_parent_class) - ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); - nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); - - if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - priv->parent_mtu_id = g_signal_connect(new_parent, - "notify::" NM_DEVICE_MTU, - G_CALLBACK(parent_mtu_maybe_changed), - device); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); - } - - if (new_ifindex > 0) { - /* Recheck availability now that the parent has changed */ - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_PARENT_CHANGED, - NM_DEVICE_STATE_REASON_PARENT_CHANGED); - } -} - -static void -update_properties(NMDevice *device) -{ - NMDeviceMacvlan * self = NM_DEVICE_MACVLAN(device); - NMDeviceMacvlanPrivate * priv = NM_DEVICE_MACVLAN_GET_PRIVATE(self); - GObject * object = G_OBJECT(device); - const NMPlatformLnkMacvlan *props; - const NMPlatformLink * plink; - - if (priv->props.tap) - props = nm_platform_link_get_lnk_macvtap(nm_device_get_platform(device), - nm_device_get_ifindex(device), - &plink); - else - props = nm_platform_link_get_lnk_macvlan(nm_device_get_platform(device), - nm_device_get_ifindex(device), - &plink); - - if (!props) { - _LOGW(LOGD_PLATFORM, - "could not get %s properties", - priv->props.tap ? "macvtap" : "macvlan"); - return; - } - - g_object_freeze_notify(object); - - nm_device_parent_set_ifindex(device, plink->parent); - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START \ - { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - - CHECK_PROPERTY_CHANGED(mode, PROP_MODE); - CHECK_PROPERTY_CHANGED(no_promisc, PROP_NO_PROMISC); - - g_object_thaw_notify(object); -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_macvlan_parent_class)->link_changed(device, pllink); - update_properties(device); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char * iface = nm_device_get_iface(device); - NMSettingMacvlan * s_macvlan; - NMPlatformLnkMacvlan lnk = {}; - int parent_ifindex; - int r; - - s_macvlan = nm_connection_get_setting_macvlan(connection); - g_return_val_if_fail(s_macvlan, FALSE); - - parent_ifindex = parent ? nm_device_get_ifindex(parent) : 0; - - if (parent_ifindex <= 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "MACVLAN devices can not be created without a parent interface"); - g_return_val_if_fail(!parent, FALSE); - return FALSE; - } - - lnk.mode = setting_mode_to_platform(nm_setting_macvlan_get_mode(s_macvlan)); - if (!lnk.mode) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "unsupported MACVLAN mode %u in connection %s", - nm_setting_macvlan_get_mode(s_macvlan), - nm_connection_get_uuid(connection)); - return FALSE; - } - lnk.no_promisc = !nm_setting_macvlan_get_promiscuous(s_macvlan); - lnk.tap = nm_setting_macvlan_get_tap(s_macvlan); - - r = nm_platform_link_macvlan_add(nm_device_get_platform(device), - iface, - parent_ifindex, - &lnk, - out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create %s interface '%s' for '%s': %s", - lnk.tap ? "macvtap" : "macvlan", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - /* We assume MACVLAN interfaces always support carrier detect */ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -/*****************************************************************************/ - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_macvlan_parent_class)->is_available(device, flags); -} - -/*****************************************************************************/ - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE(device); - NMSettingMacvlan * s_macvlan; - const char * parent = NULL; - - if (!NM_DEVICE_CLASS(nm_device_macvlan_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_macvlan = nm_connection_get_setting_macvlan(connection); - - if (nm_setting_macvlan_get_tap(s_macvlan) != priv->props.tap) { - if (priv->props.tap) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "macvtap device does not match macvlan profile"); - } else { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "macvlan device does not match macvtap profile"); - } - return FALSE; - } - - /* Before the device is realized some properties will not be set */ - if (nm_device_is_real(device)) { - if (setting_mode_to_platform(nm_setting_macvlan_get_mode(s_macvlan)) != priv->props.mode) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "macvlan mode setting differs"); - return FALSE; - } - - if (nm_setting_macvlan_get_promiscuous(s_macvlan) == priv->props.no_promisc) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "macvlan promiscuous setting differs"); - return FALSE; - } - - /* Check parent interface; could be an interface name or a UUID */ - parent = nm_setting_macvlan_get_parent(s_macvlan); - if (parent) { - if (!nm_device_match_parent(device, parent)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "macvlan parent setting differs"); - return FALSE; - } - } else { - /* Parent could be a MAC address in an NMSettingWired */ - if (!nm_device_match_parent_hwaddr(device, connection, TRUE)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "macvlan parent mac setting differs"); - return FALSE; - } - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingMacvlan *s_macvlan; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_MACVLAN_SETTING_NAME, - existing_connections, - NULL, - _("MACVLAN connection"), - NULL, - NULL, - TRUE); - - s_macvlan = nm_connection_get_setting_macvlan(connection); - if (!s_macvlan) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'macvlan' setting is required."); - return FALSE; - } - - /* If there's no MACVLAN interface, no parent, and no hardware address in the - * settings, then there's not enough information to complete the setting. - */ - if (!nm_setting_macvlan_get_parent(s_macvlan) - && !nm_device_match_parent_hwaddr(device, connection, TRUE)) { - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "The 'macvlan' setting had no interface name, parent, or hardware address."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE(device); - NMSettingMacvlan * s_macvlan = nm_connection_get_setting_macvlan(connection); - int new_mode; - - if (!s_macvlan) { - s_macvlan = (NMSettingMacvlan *) nm_setting_macvlan_new(); - nm_connection_add_setting(connection, (NMSetting *) s_macvlan); - } - - new_mode = platform_mode_to_setting(priv->props.mode); - if (new_mode != nm_setting_macvlan_get_mode(s_macvlan)) - g_object_set(s_macvlan, NM_SETTING_MACVLAN_MODE, new_mode, NULL); - - if (priv->props.no_promisc == nm_setting_macvlan_get_promiscuous(s_macvlan)) - g_object_set(s_macvlan, NM_SETTING_MACVLAN_PROMISCUOUS, !priv->props.no_promisc, NULL); - - if (priv->props.tap != nm_setting_macvlan_get_tap(s_macvlan)) - g_object_set(s_macvlan, NM_SETTING_MACVLAN_TAP, !!priv->props.tap, NULL); - - g_object_set( - s_macvlan, - NM_SETTING_MACVLAN_PARENT, - nm_device_parent_find_for_connection(device, nm_setting_macvlan_get_parent(s_macvlan)), - NULL); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_MODE: - g_value_set_string(value, platform_mode_to_string(priv->props.mode)); - break; - case PROP_NO_PROMISC: - g_value_set_boolean(value, priv->props.no_promisc); - break; - case PROP_TAP: - g_value_set_boolean(value, priv->props.tap); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_TAP: - priv->props.tap = g_value_get_boolean(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - } -} - -/*****************************************************************************/ - -static void -nm_device_macvlan_init(NMDeviceMacvlan *self) -{} - -#if NM_MORE_ASSERTS -static void -dispose(GObject *object) -{ - G_OBJECT_CLASS(nm_device_macvlan_parent_class)->dispose(object); - - nm_assert(NM_DEVICE_MACVLAN_GET_PRIVATE(object)->parent_state_id == 0); - nm_assert(NM_DEVICE_MACVLAN_GET_PRIVATE(object)->parent_mtu_id == 0); -} -#endif - -static const NMDBusInterfaceInfoExtended interface_info_device_macvlan = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_MACVLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "s", NM_DEVICE_MACVLAN_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("NoPromisc", - "b", - NM_DEVICE_MACVLAN_NO_PROMISC), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Tab", - "b", - NM_DEVICE_MACVLAN_TAP), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_macvlan_class_init(NMDeviceMacvlanClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - -#if NM_MORE_ASSERTS - object_class->dispose = dispose; -#endif - object_class->get_property = get_property; - object_class->set_property = set_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_macvlan); - - device_class->connection_type_supported = NM_SETTING_MACVLAN_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_MACVLAN_SETTING_NAME; - device_class->link_types = - NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP); - device_class->mtu_parent_delta = 0; - - device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; - device_class->check_connection_compatible = check_connection_compatible; - device_class->complete_connection = complete_connection; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; - device_class->is_available = is_available; - device_class->link_changed = link_changed; - device_class->parent_changed_notify = parent_changed_notify; - device_class->update_connection = update_connection; - - obj_properties[PROP_MODE] = g_param_spec_string(NM_DEVICE_MACVLAN_MODE, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_NO_PROMISC] = - g_param_spec_boolean(NM_DEVICE_MACVLAN_NO_PROMISC, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_TAP] = - g_param_spec_boolean(NM_DEVICE_MACVLAN_TAP, - "", - "", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_MACVLAN_DEVICE_FACTORY (nm_macvlan_device_factory_get_type()) -#define NM_MACVLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MACVLAN_DEVICE_FACTORY, NMMacvlanDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - NMSettingMacvlan *s_macvlan; - NMLinkType link_type; - gboolean tap; - - if (connection) { - s_macvlan = nm_connection_get_setting_macvlan(connection); - g_assert(s_macvlan); - tap = nm_setting_macvlan_get_tap(s_macvlan); - } else { - g_assert(plink); - tap = plink->type == NM_LINK_TYPE_MACVTAP; - } - - link_type = tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN; - - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_MACVLAN, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Macvlan", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_MACVLAN, - NM_DEVICE_LINK_TYPE, - link_type, - NM_DEVICE_MACVLAN_TAP, - tap, - NULL); -} - -static const char * -get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSettingMacvlan *s_macvlan; - NMSettingWired * s_wired; - const char * parent = NULL; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_MACVLAN_SETTING_NAME), NULL); - - s_macvlan = nm_connection_get_setting_macvlan(connection); - g_assert(s_macvlan); - - parent = nm_setting_macvlan_get_parent(s_macvlan); - if (parent) - return parent; - - /* Try the hardware address from the MACVLAN connection's hardware setting */ - s_wired = nm_connection_get_setting_wired(connection); - if (s_wired) - return nm_setting_wired_get_mac_address(s_wired); - - return NULL; -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - NMSettingMacvlan *s_macvlan; - const char * ifname; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_MACVLAN_SETTING_NAME), NULL); - - s_macvlan = nm_connection_get_setting_macvlan(connection); - g_assert(s_macvlan); - - if (!parent_iface) - return NULL; - - ifname = nm_connection_get_interface_name(connection); - return g_strdup(ifname); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - MACVLAN, - Macvlan, - macvlan, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_MACVLAN_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); diff --git a/src/devices/nm-device-macvlan.h b/src/devices/nm-device-macvlan.h deleted file mode 100644 index f36a7a4a..00000000 --- a/src/devices/nm-device-macvlan.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_MACVLAN_H__ -#define __NETWORKMANAGER_DEVICE_MACVLAN_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_MACVLAN (nm_device_macvlan_get_type()) -#define NM_DEVICE_MACVLAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlan)) -#define NM_DEVICE_MACVLAN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanClass)) -#define NM_IS_DEVICE_MACVLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MACVLAN)) -#define NM_IS_DEVICE_MACVLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_MACVLAN)) -#define NM_DEVICE_MACVLAN_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanClass)) - -#define NM_DEVICE_MACVLAN_MODE "mode" -#define NM_DEVICE_MACVLAN_NO_PROMISC "no-promisc" -#define NM_DEVICE_MACVLAN_TAP "tap" - -typedef struct _NMDeviceMacvlan NMDeviceMacvlan; -typedef struct _NMDeviceMacvlanClass NMDeviceMacvlanClass; - -GType nm_device_macvlan_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_MACVLAN_H__ */ diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c deleted file mode 100644 index 82861bda..00000000 --- a/src/devices/nm-device-ppp.c +++ /dev/null @@ -1,375 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ppp.h" - -#include "nm-ip4-config.h" -#include "nm-act-request.h" -#include "nm-device-factory.h" -#include "nm-device-private.h" -#include "nm-manager.h" -#include "nm-setting-pppoe.h" -#include "platform/nm-platform.h" -#include "ppp/nm-ppp-manager.h" -#include "ppp/nm-ppp-manager-call.h" -#include "ppp/nm-ppp-status.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDevicePpp); - -/*****************************************************************************/ - -typedef struct _NMDevicePppPrivate { - NMPPPManager *ppp_manager; - NMIP4Config * ip4_config; -} NMDevicePppPrivate; - -struct _NMDevicePpp { - NMDevice parent; - NMDevicePppPrivate _priv; -}; - -struct _NMDevicePppClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDevicePpp, nm_device_ppp, NM_TYPE_DEVICE) - -#define NM_DEVICE_PPP_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDevicePpp, NM_IS_DEVICE_PPP, NMDevice) - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static void -ppp_state_changed(NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - switch (status) { - case NM_PPP_STATUS_DISCONNECT: - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_PPP_DISCONNECT); - break; - case NM_PPP_STATUS_DEAD: - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PPP_FAILED); - break; - default: - break; - } -} - -static void -ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDevicePpp * self = NM_DEVICE_PPP(device); - gs_free char *old_name = NULL; - gs_free_error GError *error = NULL; - - if (!nm_device_take_over_link(device, ifindex, &old_name, &error)) { - _LOGW(LOGD_DEVICE | LOGD_PPP, - "could not take control of link %d: %s", - ifindex, - error->message); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - if (old_name) - nm_manager_remove_device(NM_MANAGER_GET, old_name, NM_DEVICE_TYPE_PPP); - - nm_device_activate_schedule_stage3_ip_config_start(device); -} - -static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDevicePpp * self = NM_DEVICE_PPP(device); - NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); - - _LOGT(LOGD_DEVICE | LOGD_PPP, "received IPv4 config from pppd"); - - if (nm_device_get_state(device) == NM_DEVICE_STATE_IP_CONFIG) { - if (nm_device_activate_ip4_state_in_conf(device)) { - nm_device_activate_schedule_ip_config_result(device, - AF_INET, - NM_IP_CONFIG_CAST(config)); - return; - } - } else { - if (priv->ip4_config) - g_object_unref(priv->ip4_config); - priv->ip4_config = g_object_ref(config); - } -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingPppoe *s_pppoe; - - if (!NM_DEVICE_CLASS(nm_device_ppp_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_pppoe = nm_connection_get_setting_pppoe(connection); - if (!s_pppoe || !nm_setting_pppoe_get_parent(s_pppoe)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "the connection doesn't specify a PPPoE parent interface"); - return FALSE; - } - - return TRUE; -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDevicePpp * self = NM_DEVICE_PPP(device); - NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); - NMSettingPppoe * s_pppoe; - NMActRequest * req; - GError * error = NULL; - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - s_pppoe = nm_device_get_applied_setting(device, NM_TYPE_SETTING_PPPOE); - g_return_val_if_fail(s_pppoe, NM_ACT_STAGE_RETURN_FAILURE); - - g_clear_object(&priv->ip4_config); - - priv->ppp_manager = nm_ppp_manager_create(nm_setting_pppoe_get_parent(s_pppoe), &error); - - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); - } - - if (!priv->ppp_manager - || !nm_ppp_manager_start(priv->ppp_manager, - req, - nm_setting_pppoe_get_username(s_pppoe), - 30, - 0, - &error)) { - _LOGW(LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", error->message); - g_error_free(error); - - g_clear_object(&priv->ppp_manager); - - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, - G_CALLBACK(ppp_state_changed), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK(ppp_ifindex_set), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), - self); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - if (addr_family == AF_INET) { - NMDevicePpp * self = NM_DEVICE_PPP(device); - NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); - - if (priv->ip4_config) { - if (out_config) - *out_config = g_steal_pointer(&priv->ip4_config); - else - g_clear_object(&priv->ip4_config); - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - /* Wait IPCP termination */ - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - return NM_DEVICE_CLASS(nm_device_ppp_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - int parent_ifindex; - - if (!parent) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "PPP devices can not be created without a parent interface"); - return FALSE; - } - - parent_ifindex = nm_device_get_ifindex(parent); - g_warn_if_fail(parent_ifindex > 0); - - nm_device_parent_set_ifindex(device, parent_ifindex); - - /* The interface is created later */ - - return TRUE; -} - -static void -deactivate(NMDevice *device) -{ - NMDevicePpp * self = NM_DEVICE_PPP(device); - NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); - - if (priv->ppp_manager) { - nm_ppp_manager_stop(priv->ppp_manager, NULL, NULL, NULL); - g_clear_object(&priv->ppp_manager); - } -} - -static void -nm_device_ppp_init(NMDevicePpp *self) -{} - -static void -dispose(GObject *object) -{ - NMDevicePpp * self = NM_DEVICE_PPP(object); - NMDevicePppPrivate *priv = NM_DEVICE_PPP_GET_PRIVATE(self); - - g_clear_object(&priv->ip4_config); - - G_OBJECT_CLASS(nm_device_ppp_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_ppp = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_PPP, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ppp_class_init(NMDevicePppClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->dispose = dispose; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_ppp); - - device_class->connection_type_supported = NM_SETTING_PPPOE_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_PPPOE_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_PPP); - - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->check_connection_compatible = check_connection_compatible; - device_class->create_and_realize = create_and_realize; - device_class->deactivate = deactivate; - device_class->get_generic_capabilities = get_generic_capabilities; -} - -/*****************************************************************************/ - -#define NM_TYPE_PPP_DEVICE_FACTORY (nm_ppp_device_factory_get_type()) -#define NM_PPP_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_DEVICE_FACTORY, NMPppDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_PPP, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Ppp", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_PPP, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_PPP, - NULL); -} - -static gboolean -match_connection(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSettingPppoe *s_pppoe; - - s_pppoe = nm_connection_get_setting_pppoe(connection); - nm_assert(s_pppoe); - - return !!nm_setting_pppoe_get_parent(s_pppoe); -} - -static const char * -get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSettingPppoe *s_pppoe; - - nm_assert(nm_connection_is_type(connection, NM_SETTING_PPPOE_SETTING_NAME)); - - s_pppoe = nm_connection_get_setting_pppoe(connection); - nm_assert(s_pppoe); - - return nm_setting_pppoe_get_parent(s_pppoe); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - nm_assert(nm_connection_is_type(connection, NM_SETTING_PPPOE_SETTING_NAME)); - - if (!parent_iface) - return NULL; - - return g_strdup(nm_connection_get_interface_name(connection)); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - PPP, - Ppp, - ppp, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_PPP) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_PPPOE_SETTING_NAME), - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface; - factory_class->create_device = create_device; - factory_class->match_connection = match_connection;); diff --git a/src/devices/nm-device-ppp.h b/src/devices/nm-device-ppp.h deleted file mode 100644 index 99132a3e..00000000 --- a/src/devices/nm-device-ppp.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_PPP_H__ -#define __NETWORKMANAGER_DEVICE_PPP_H__ - -#define NM_TYPE_DEVICE_PPP (nm_device_ppp_get_type()) -#define NM_DEVICE_PPP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_PPP, NMDevicePpp)) -#define NM_DEVICE_PPP_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_PPP, NMDevicePppClass)) -#define NM_IS_DEVICE_PPP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_PPP)) -#define NM_IS_DEVICE_PPP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_PPP)) -#define NM_DEVICE_PPP_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_PPP, NMDevicePppClass)) - -typedef struct _NMDevicePpp NMDevicePpp; -typedef struct _NMDevicePppClass NMDevicePppClass; - -GType nm_device_ppp_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_PPP_H__ */ diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h deleted file mode 100644 index 5f8eff18..00000000 --- a/src/devices/nm-device-private.h +++ /dev/null @@ -1,213 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2007 - 2008 Novell, Inc. - * Copyright (C) 2007 - 2011 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_PRIVATE_H__ -#define __NETWORKMANAGER_DEVICE_PRIVATE_H__ - -#include "nm-device.h" - -/* This file should only be used by subclasses of NMDevice */ - -typedef enum { - NM_DEVICE_STAGE_STATE_INIT = 0, - NM_DEVICE_STAGE_STATE_PENDING = 1, - NM_DEVICE_STAGE_STATE_COMPLETED = 2, -} NMDeviceStageState; - -typedef enum { - NM_DEVICE_IP_STATE_NONE, - NM_DEVICE_IP_STATE_WAIT, - NM_DEVICE_IP_STATE_CONF, - NM_DEVICE_IP_STATE_DONE, - NM_DEVICE_IP_STATE_FAIL, -} NMDeviceIPState; - -enum NMActStageReturn { - NM_ACT_STAGE_RETURN_FAILURE = 0, /* Hard failure of activation */ - NM_ACT_STAGE_RETURN_SUCCESS, /* Activation stage done */ - NM_ACT_STAGE_RETURN_POSTPONE, /* Long-running operation in progress */ - NM_ACT_STAGE_RETURN_IP_WAIT, /* IP config stage is waiting (state IP_WAIT) */ - NM_ACT_STAGE_RETURN_IP_DONE, /* IP config stage is done (state IP_DONE), - * For the ip-config stage, this is similar to - * NM_ACT_STAGE_RETURN_SUCCESS, except that no - * IP config should be committed. */ - NM_ACT_STAGE_RETURN_IP_FAIL, /* IP config stage failed (state IP_FAIL), activation may proceed */ -}; - -#define NM_DEVICE_CAP_NONSTANDARD_CARRIER 0x80000000 -#define NM_DEVICE_CAP_IS_NON_KERNEL 0x40000000 - -#define NM_DEVICE_CAP_INTERNAL_MASK 0xc0000000 - -void nm_device_arp_announce(NMDevice *self); - -NMSettings *nm_device_get_settings(NMDevice *self); - -NMManager *nm_device_get_manager(NMDevice *self); - -gboolean nm_device_set_ip_ifindex(NMDevice *self, int ifindex); - -gboolean nm_device_set_ip_iface(NMDevice *self, const char *iface); - -void nm_device_activate_schedule_stage3_ip_config_start(NMDevice *device); - -gboolean nm_device_activate_stage3_ip4_start(NMDevice *self); - -gboolean nm_device_activate_stage3_ip6_start(NMDevice *self); - -gboolean nm_device_bring_up(NMDevice *self, gboolean wait, gboolean *no_firmware); - -void nm_device_take_down(NMDevice *self, gboolean block); - -gboolean nm_device_take_over_link(NMDevice *self, int ifindex, char **old_name, GError **error); - -gboolean nm_device_hw_addr_set(NMDevice * device, - const char *addr, - const char *detail, - gboolean set_permanent); -gboolean nm_device_hw_addr_set_cloned(NMDevice *device, NMConnection *connection, gboolean is_wifi); -gboolean nm_device_hw_addr_reset(NMDevice *device, const char *detail); - -void nm_device_set_firmware_missing(NMDevice *self, gboolean missing); - -void nm_device_activate_schedule_stage1_device_prepare(NMDevice *device, gboolean do_sync); -void nm_device_activate_schedule_stage2_device_config(NMDevice *device, gboolean do_sync); - -void -nm_device_activate_schedule_ip_config_result(NMDevice *device, int addr_family, NMIPConfig *config); - -void nm_device_activate_schedule_ip_config_timeout(NMDevice *device, int addr_family); - -NMDeviceIPState nm_device_activate_get_ip_state(NMDevice *self, int addr_family); - -static inline gboolean -nm_device_activate_ip4_state_in_conf(NMDevice *self) -{ - return nm_device_activate_get_ip_state(self, AF_INET) == NM_DEVICE_IP_STATE_CONF; -} - -static inline gboolean -nm_device_activate_ip4_state_in_wait(NMDevice *self) -{ - return nm_device_activate_get_ip_state(self, AF_INET) == NM_DEVICE_IP_STATE_WAIT; -} - -static inline gboolean -nm_device_activate_ip4_state_done(NMDevice *self) -{ - return nm_device_activate_get_ip_state(self, AF_INET) == NM_DEVICE_IP_STATE_DONE; -} - -static inline gboolean -nm_device_activate_ip6_state_in_conf(NMDevice *self) -{ - return nm_device_activate_get_ip_state(self, AF_INET6) == NM_DEVICE_IP_STATE_CONF; -} - -static inline gboolean -nm_device_activate_ip6_state_in_wait(NMDevice *self) -{ - return nm_device_activate_get_ip_state(self, AF_INET6) == NM_DEVICE_IP_STATE_WAIT; -} - -static inline gboolean -nm_device_activate_ip6_state_done(NMDevice *self) -{ - return nm_device_activate_get_ip_state(self, AF_INET6) == NM_DEVICE_IP_STATE_DONE; -} - -void nm_device_set_dhcp_anycast_address(NMDevice *device, const char *addr); - -gboolean nm_device_dhcp4_renew(NMDevice *device, gboolean release); -gboolean nm_device_dhcp6_renew(NMDevice *device, gboolean release); - -void nm_device_recheck_available_connections(NMDevice *device); - -void -nm_device_master_check_slave_physical_port(NMDevice *self, NMDevice *slave, NMLogDomain log_domain); - -void nm_device_set_carrier(NMDevice *self, gboolean carrier); - -void nm_device_queue_recheck_assume(NMDevice *device); -void nm_device_queue_recheck_available(NMDevice * device, - NMDeviceStateReason available_reason, - NMDeviceStateReason unavailable_reason); - -void nm_device_set_dev2_ip_config(NMDevice *device, int addr_family, NMIPConfig *config); - -gboolean nm_device_hw_addr_is_explict(NMDevice *device); - -void nm_device_ip_method_failed(NMDevice *self, int addr_family, NMDeviceStateReason reason); - -gboolean nm_device_sysctl_ip_conf_set(NMDevice * self, - int addr_family, - const char *property, - const char *value); - -NMIP4Config *nm_device_ip4_config_new(NMDevice *self); - -NMIP6Config *nm_device_ip6_config_new(NMDevice *self); - -NMIPConfig *nm_device_ip_config_new(NMDevice *self, int addr_family); - -NML3ConfigData *nm_device_create_l3_config_data(NMDevice *self); - -/*****************************************************************************/ - -gint64 nm_device_get_configured_mtu_from_connection_default(NMDevice * self, - const char *property_name, - guint32 max_mtu); - -guint32 nm_device_get_configured_mtu_from_connection(NMDevice * device, - GType setting_type, - NMDeviceMtuSource *out_source); - -guint32 nm_device_get_configured_mtu_for_wired(NMDevice * self, - NMDeviceMtuSource *out_source, - gboolean * out_force); - -guint32 nm_device_get_configured_mtu_wired_parent(NMDevice * self, - NMDeviceMtuSource *out_source, - gboolean * out_force); - -void nm_device_commit_mtu(NMDevice *self); - -/*****************************************************************************/ - -#define NM_DEVICE_DEFINE_LINK_TYPES(...) \ - ((NM_NARG(__VA_ARGS__) == 0) ? NULL : ({ \ - static const NMLinkType _types[NM_NARG(__VA_ARGS__) + 1] = { \ - __VA_ARGS__ _NM_MACRO_COMMA_IF_ARGS(__VA_ARGS__) NM_LINK_TYPE_NONE, \ - }; \ - \ - nm_assert(_types[NM_NARG(__VA_ARGS__)] == NM_LINK_TYPE_NONE); \ - _types; \ - })) - -gboolean _nm_device_hash_check_invalid_keys(GHashTable * hash, - const char * setting_name, - GError ** error, - const char *const *whitelist); -#define nm_device_hash_check_invalid_keys(hash, setting_name, error, ...) \ - _nm_device_hash_check_invalid_keys(hash, setting_name, error, NM_MAKE_STRV(__VA_ARGS__)) - -gboolean nm_device_match_parent(NMDevice *device, const char *parent); -gboolean nm_device_match_parent_hwaddr(NMDevice * device, - NMConnection *connection, - gboolean fail_if_no_hwaddr); - -/*****************************************************************************/ - -void nm_device_auth_request(NMDevice * self, - GDBusMethodInvocation * context, - NMConnection * connection, - const char * permission, - gboolean allow_interaction, - GCancellable * cancellable, - NMManagerDeviceAuthRequestFunc callback, - gpointer user_data); - -#endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c deleted file mode 100644 index 94805255..00000000 --- a/src/devices/nm-device-tun.c +++ /dev/null @@ -1,571 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-tun.h" - -#include <stdlib.h> -#include <sys/types.h> -#include <linux/if_tun.h> - -#include "nm-act-request.h" -#include "nm-device-private.h" -#include "nm-ip4-config.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-setting-tun.h" -#include "nm-core-internal.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceTun); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceTun, - PROP_OWNER, - PROP_GROUP, - PROP_MODE, - PROP_NO_PI, - PROP_VNET_HDR, - PROP_MULTI_QUEUE, ); - -typedef struct { - NMPlatformLnkTun props; -} NMDeviceTunPrivate; - -struct _NMDeviceTun { - NMDevice parent; - NMDeviceTunPrivate _priv; -}; - -struct _NMDeviceTunClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE) - -#define NM_DEVICE_TUN_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceTun, NM_IS_DEVICE_TUN, NMDevice) - -/*****************************************************************************/ - -static void -update_properties_from_struct(NMDeviceTun *self, const NMPlatformLnkTun *props) -{ - NMDeviceTunPrivate * priv = NM_DEVICE_TUN_GET_PRIVATE(self); - const NMPlatformLnkTun props0 = {}; - - if (!props) { - /* allow passing %NULL to reset all properties. */ - props = &props0; - } - - g_object_freeze_notify(G_OBJECT(self)); - -#define CHECK_PROPERTY_CHANGED_VALID(field, prop) \ - G_STMT_START \ - { \ - if (priv->props.field != props->field \ - || priv->props.field##_valid != props->field##_valid) { \ - priv->props.field##_valid = props->field##_valid; \ - priv->props.field = props->field; \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START \ - { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - - CHECK_PROPERTY_CHANGED_VALID(owner, PROP_OWNER); - CHECK_PROPERTY_CHANGED_VALID(group, PROP_GROUP); - CHECK_PROPERTY_CHANGED(type, PROP_MODE); - CHECK_PROPERTY_CHANGED(pi, PROP_NO_PI); - CHECK_PROPERTY_CHANGED(vnet_hdr, PROP_VNET_HDR); - CHECK_PROPERTY_CHANGED(multi_queue, PROP_MULTI_QUEUE); - - g_object_thaw_notify(G_OBJECT(self)); -} - -static void -update_properties(NMDeviceTun *self) -{ - NMPlatformLnkTun props_storage; - const NMPlatformLnkTun *props = NULL; - int ifindex; - - ifindex = nm_device_get_ifindex(NM_DEVICE(self)); - if (ifindex > 0 - && nm_platform_link_tun_get_properties(nm_device_get_platform(NM_DEVICE(self)), - ifindex, - &props_storage)) - props = &props_storage; - - update_properties_from_struct(self, props); -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_tun_parent_class)->link_changed(device, pllink); - update_properties(NM_DEVICE_TUN(device)); -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingTun *s_tun; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_TUN_SETTING_NAME, - existing_connections, - NULL, - _("TUN connection"), - NULL, - NULL, - TRUE); - - s_tun = nm_connection_get_setting_tun(connection); - if (!s_tun) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'tun' setting is required."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceTun * self = NM_DEVICE_TUN(device); - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE(self); - NMSettingTun * s_tun; - NMSettingTunMode mode; - char s_buf[100]; - const char * str; - - /* Note: since we read tun properties from sysctl for older kernels, - * we don't get proper change notifications. Make sure that all our - * tun properties are up to date at this point. We should not do this, - * if we would entirely rely on netlink events. */ - update_properties(NM_DEVICE_TUN(device)); - - switch (priv->props.type) { - case IFF_TUN: - mode = NM_SETTING_TUN_MODE_TUN; - break; - case IFF_TAP: - mode = NM_SETTING_TUN_MODE_TAP; - break; - default: - /* Huh? */ - return; - } - - s_tun = nm_connection_get_setting_tun(connection); - if (!s_tun) { - s_tun = (NMSettingTun *) nm_setting_tun_new(); - nm_connection_add_setting(connection, (NMSetting *) s_tun); - } - - if (mode != nm_setting_tun_get_mode(s_tun)) - g_object_set(G_OBJECT(s_tun), NM_SETTING_TUN_MODE, (guint) mode, NULL); - - str = priv->props.owner_valid ? nm_sprintf_buf(s_buf, "%" G_GINT32_FORMAT, priv->props.owner) - : NULL; - if (!nm_streq0(str, nm_setting_tun_get_owner(s_tun))) - g_object_set(G_OBJECT(s_tun), NM_SETTING_TUN_OWNER, str, NULL); - - str = priv->props.group_valid ? nm_sprintf_buf(s_buf, "%" G_GINT32_FORMAT, priv->props.group) - : NULL; - if (!nm_streq0(str, nm_setting_tun_get_group(s_tun))) - g_object_set(G_OBJECT(s_tun), NM_SETTING_TUN_GROUP, str, NULL); - - if (priv->props.pi != nm_setting_tun_get_pi(s_tun)) - g_object_set(G_OBJECT(s_tun), NM_SETTING_TUN_PI, (gboolean) priv->props.pi, NULL); - if (priv->props.vnet_hdr != nm_setting_tun_get_vnet_hdr(s_tun)) - g_object_set(G_OBJECT(s_tun), - NM_SETTING_TUN_VNET_HDR, - (gboolean) priv->props.vnet_hdr, - NULL); - if (priv->props.multi_queue != nm_setting_tun_get_multi_queue(s_tun)) - g_object_set(G_OBJECT(s_tun), - NM_SETTING_TUN_MULTI_QUEUE, - (gboolean) priv->props.multi_queue, - NULL); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char * iface = nm_device_get_iface(device); - NMPlatformLnkTun props = {}; - NMSettingTun * s_tun; - gint64 owner; - gint64 group; - int r; - - s_tun = nm_connection_get_setting_tun(connection); - g_return_val_if_fail(s_tun, FALSE); - - switch (nm_setting_tun_get_mode(s_tun)) { - case NM_SETTING_TUN_MODE_TAP: - props.type = IFF_TAP; - break; - case NM_SETTING_TUN_MODE_TUN: - props.type = IFF_TUN; - break; - default: - g_return_val_if_reached(FALSE); - } - - owner = _nm_utils_ascii_str_to_int64(nm_setting_tun_get_owner(s_tun), 10, 0, G_MAXINT32, -1); - if (owner != -1) { - props.owner_valid = TRUE; - props.owner = owner; - } - group = _nm_utils_ascii_str_to_int64(nm_setting_tun_get_group(s_tun), 10, 0, G_MAXINT32, -1); - if (group != -1) { - props.group_valid = TRUE; - props.group = group; - } - - props.pi = nm_setting_tun_get_pi(s_tun); - props.vnet_hdr = nm_setting_tun_get_vnet_hdr(s_tun); - props.multi_queue = nm_setting_tun_get_multi_queue(s_tun); - props.persist = TRUE; - - r = nm_platform_link_tun_add(nm_device_get_platform(device), iface, &props, out_plink, NULL); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create TUN/TAP interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -static gboolean -_same_og(const char *str, gboolean og_valid, guint32 og_num) -{ - gint64 v; - - v = _nm_utils_ascii_str_to_int64(str, 10, 0, G_MAXINT32, -1); - return (!og_valid && (v == (gint64) -1)) || (og_valid && (((guint32) v) == og_num)); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceTun * self = NM_DEVICE_TUN(device); - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE(self); - NMSettingTunMode mode; - NMSettingTun * s_tun; - - if (!NM_DEVICE_CLASS(nm_device_tun_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (nm_device_is_real(device)) { - switch (priv->props.type) { - case IFF_TUN: - mode = NM_SETTING_TUN_MODE_TUN; - break; - case IFF_TAP: - mode = NM_SETTING_TUN_MODE_TAP; - break; - default: - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "invalid tun type on device"); - return FALSE; - } - - s_tun = nm_connection_get_setting_tun(connection); - - if (mode != nm_setting_tun_get_mode(s_tun)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "tun mode setting mismatches"); - return FALSE; - } - if (!_same_og(nm_setting_tun_get_owner(s_tun), - priv->props.owner_valid, - priv->props.owner)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "tun owner setting mismatches"); - return FALSE; - } - if (!_same_og(nm_setting_tun_get_group(s_tun), - priv->props.group_valid, - priv->props.group)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "tun group setting mismatches"); - return FALSE; - } - if (nm_setting_tun_get_pi(s_tun) != priv->props.pi) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "tun pi setting mismatches"); - return FALSE; - } - if (nm_setting_tun_get_vnet_hdr(s_tun) != priv->props.vnet_hdr) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "tun vnet-hdr setting mismatches"); - return FALSE; - } - if (nm_setting_tun_get_multi_queue(s_tun) != priv->props.multi_queue) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "tun multi-queue setting mismatches"); - return FALSE; - } - } - - return TRUE; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceTun * self = NM_DEVICE_TUN(device); - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE(self); - - if (priv->props.type == IFF_TUN) { - /* Nothing to do for TUN devices */ - } else { - if (!nm_device_hw_addr_set_cloned(device, - nm_device_get_applied_connection(device), - FALSE)) { - *out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static void -unrealize_notify(NMDevice *device) -{ - NM_DEVICE_CLASS(nm_device_tun_parent_class)->unrealize_notify(device); - update_properties_from_struct(NM_DEVICE_TUN(device), NULL); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceTun * self = NM_DEVICE_TUN(object); - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE(self); - const char * s; - - switch (prop_id) { - case PROP_OWNER: - g_value_set_int64(value, - priv->props.owner_valid ? (gint64) priv->props.owner : (gint64) -1); - break; - case PROP_GROUP: - g_value_set_int64(value, - priv->props.group_valid ? (gint64) priv->props.group : (gint64) -1); - break; - case PROP_MODE: - switch (priv->props.type) { - case IFF_TUN: - s = "tun"; - break; - case IFF_TAP: - s = "tap"; - break; - default: - s = NULL; - break; - } - g_value_set_static_string(value, s); - break; - case PROP_NO_PI: - g_value_set_boolean(value, !priv->props.pi); - break; - case PROP_VNET_HDR: - g_value_set_boolean(value, priv->props.vnet_hdr); - break; - case PROP_MULTI_QUEUE: - g_value_set_boolean(value, priv->props.multi_queue); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_tun_init(NMDeviceTun *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_tun = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_TUN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Owner", "x", NM_DEVICE_TUN_OWNER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Group", "x", NM_DEVICE_TUN_GROUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "s", NM_DEVICE_TUN_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("NoPi", "b", NM_DEVICE_TUN_NO_PI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("VnetHdr", - "b", - NM_DEVICE_TUN_VNET_HDR), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("MultiQueue", - "b", - NM_DEVICE_TUN_MULTI_QUEUE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_tun_class_init(NMDeviceTunClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_tun); - - device_class->connection_type_supported = NM_SETTING_TUN_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_TUN_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_TUN); - - device_class->link_changed = link_changed; - device_class->complete_connection = complete_connection; - device_class->check_connection_compatible = check_connection_compatible; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->unrealize_notify = unrealize_notify; - device_class->update_connection = update_connection; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - - obj_properties[PROP_OWNER] = g_param_spec_int64(NM_DEVICE_TUN_OWNER, - "", - "", - -1, - G_MAXUINT32, - -1, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_GROUP] = g_param_spec_int64(NM_DEVICE_TUN_GROUP, - "", - "", - -1, - G_MAXUINT32, - -1, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MODE] = g_param_spec_string(NM_DEVICE_TUN_MODE, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_NO_PI] = g_param_spec_boolean(NM_DEVICE_TUN_NO_PI, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_VNET_HDR] = g_param_spec_boolean(NM_DEVICE_TUN_VNET_HDR, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MULTI_QUEUE] = - g_param_spec_boolean(NM_DEVICE_TUN_MULTI_QUEUE, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_TUN_DEVICE_FACTORY (nm_tun_device_factory_get_type()) -#define NM_TUN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TUN_DEVICE_FACTORY, NMTunDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - g_return_val_if_fail(!plink || plink->type == NM_LINK_TYPE_TUN, NULL); - g_return_val_if_fail(!connection - || nm_streq0(nm_connection_get_connection_type(connection), - NM_SETTING_TUN_SETTING_NAME), - NULL); - - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_TUN, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Tun", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_TUN, - NM_DEVICE_LINK_TYPE, - (guint) NM_LINK_TYPE_TUN, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - TUN, - Tun, - tun, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_TUN) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_TUN_SETTING_NAME), - factory_class->create_device = create_device;); diff --git a/src/devices/nm-device-tun.h b/src/devices/nm-device-tun.h deleted file mode 100644 index 32d515c1..00000000 --- a/src/devices/nm-device-tun.h +++ /dev/null @@ -1,32 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_TUN_H__ -#define __NETWORKMANAGER_DEVICE_TUN_H__ - -#include "nm-device-generic.h" - -#define NM_TYPE_DEVICE_TUN (nm_device_tun_get_type()) -#define NM_DEVICE_TUN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TUN, NMDeviceTun)) -#define NM_DEVICE_TUN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_TUN, NMDeviceTunClass)) -#define NM_IS_DEVICE_TUN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_TUN)) -#define NM_IS_DEVICE_TUN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_TUN)) -#define NM_DEVICE_TUN_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_TUN, NMDeviceTunClass)) - -#define NM_DEVICE_TUN_OWNER "owner" -#define NM_DEVICE_TUN_GROUP "group" -#define NM_DEVICE_TUN_MODE "mode" -#define NM_DEVICE_TUN_NO_PI "no-pi" -#define NM_DEVICE_TUN_VNET_HDR "vnet-hdr" -#define NM_DEVICE_TUN_MULTI_QUEUE "multi-queue" - -typedef struct _NMDeviceTun NMDeviceTun; -typedef struct _NMDeviceTunClass NMDeviceTunClass; - -GType nm_device_tun_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_TUN_H__ */ diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c deleted file mode 100644 index f61bc99f..00000000 --- a/src/devices/nm-device-veth.c +++ /dev/null @@ -1,178 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <stdlib.h> - -#include "nm-device-veth.h" -#include "nm-device-private.h" -#include "nm-manager.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceVeth); - -/*****************************************************************************/ - -struct _NMDeviceVeth { - NMDeviceEthernet parent; -}; - -struct _NMDeviceVethClass { - NMDeviceEthernetClass parent; -}; - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceVeth, PROP_PEER, ); - -/*****************************************************************************/ - -G_DEFINE_TYPE(NMDeviceVeth, nm_device_veth, NM_TYPE_DEVICE_ETHERNET) - -/*****************************************************************************/ - -static void -update_properties(NMDevice *device) -{ - NMDevice *peer; - int ifindex, peer_ifindex; - - ifindex = nm_device_get_ifindex(device); - - if (!nm_platform_link_veth_get_properties(nm_device_get_platform(device), - ifindex, - &peer_ifindex)) - peer_ifindex = 0; - - nm_device_parent_set_ifindex(device, peer_ifindex); - - peer = nm_device_parent_get_device(device); - if (peer && NM_IS_DEVICE_VETH(peer) && nm_device_parent_get_ifindex(peer) <= 0) - update_properties(peer); -} - -static gboolean -can_unmanaged_external_down(NMDevice *self) -{ - /* Unless running in a container, an udev rule causes these to be - * unmanaged. If there's no udev then we're probably in a container - * and should IFF_UP and configure the veth ourselves even if we - * didn't create it. */ - return FALSE; -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_veth_parent_class)->link_changed(device, pllink); - update_properties(device); -} - -/*****************************************************************************/ - -static void -nm_device_veth_init(NMDeviceVeth *self) -{} - -static void -parent_changed_notify(NMDevice *device, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent) -{ - NM_DEVICE_CLASS(nm_device_veth_parent_class) - ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - _notify(NM_DEVICE_VETH(device), PROP_PEER); -} - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceVeth *self = NM_DEVICE_VETH(object); - NMDevice * peer; - - switch (prop_id) { - case PROP_PEER: - peer = nm_device_parent_get_device(NM_DEVICE(self)); - if (peer && !NM_IS_DEVICE_VETH(peer)) - peer = NULL; - nm_dbus_utils_g_value_set_object_path(value, peer); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static const NMDBusInterfaceInfoExtended interface_info_device_veth = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_VETH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Peer", - "o", - NM_DEVICE_VETH_PEER), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_veth_class_init(NMDeviceVethClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_veth); - - device_class->connection_type_supported = NULL; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_VETH); - - device_class->can_unmanaged_external_down = can_unmanaged_external_down; - device_class->link_changed = link_changed; - device_class->parent_changed_notify = parent_changed_notify; - - obj_properties[PROP_PEER] = g_param_spec_string(NM_DEVICE_VETH_PEER, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_VETH_DEVICE_FACTORY (nm_veth_device_factory_get_type()) -#define NM_VETH_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VETH_DEVICE_FACTORY, NMVethDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_VETH, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Veth", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_VETH, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_VETH, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL(VETH, - Veth, - veth, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_VETH), - factory_class->create_device = create_device;); diff --git a/src/devices/nm-device-veth.h b/src/devices/nm-device-veth.h deleted file mode 100644 index e3867446..00000000 --- a/src/devices/nm-device-veth.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_VETH_H__ -#define __NETWORKMANAGER_DEVICE_VETH_H__ - -#include "nm-device-ethernet.h" - -#define NM_TYPE_DEVICE_VETH (nm_device_veth_get_type()) -#define NM_DEVICE_VETH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VETH, NMDeviceVeth)) -#define NM_DEVICE_VETH_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VETH, NMDeviceVethClass)) -#define NM_IS_DEVICE_VETH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VETH)) -#define NM_IS_DEVICE_VETH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_VETH)) -#define NM_DEVICE_VETH_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_VETH, NMDeviceVethClass)) - -#define NM_DEVICE_VETH_PEER "peer" - -typedef struct _NMDeviceVeth NMDeviceVeth; -typedef struct _NMDeviceVethClass NMDeviceVethClass; - -GType nm_device_veth_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_VETH_H__ */ diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c deleted file mode 100644 index bb6fdc05..00000000 --- a/src/devices/nm-device-vlan.c +++ /dev/null @@ -1,688 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 - 2012 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-vlan.h" - -#include <sys/socket.h> - -#include "nm-manager.h" -#include "nm-utils.h" -#include "NetworkManagerUtils.h" -#include "nm-device-private.h" -#include "settings/nm-settings.h" -#include "nm-act-request.h" -#include "nm-ip4-config.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-manager.h" -#include "nm-core-internal.h" -#include "platform/nmp-object.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceVlan); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceVlan, PROP_VLAN_ID, ); - -typedef struct { - gulong parent_state_id; - gulong parent_hwaddr_id; - gulong parent_mtu_id; - guint vlan_id; -} NMDeviceVlanPrivate; - -struct _NMDeviceVlan { - NMDevice parent; - NMDeviceVlanPrivate _priv; -}; - -struct _NMDeviceVlanClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) - -#define NM_DEVICE_VLAN_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceVlan, NM_IS_DEVICE_VLAN, NMDevice) - -/*****************************************************************************/ - -static void -parent_state_changed(NMDevice * parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN(user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged_by_flags(NM_DEVICE(self), - NM_UNMANAGED_PARENT, - !nm_device_get_managed(parent, FALSE), - reason); -} - -static void -parent_mtu_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) -{ - /* the MTU of a VLAN device is limited by the parent's MTU. - * - * When the parent's MTU changes, try to re-set the MTU. */ - nm_device_commit_mtu(user_data); -} - -static void -parent_hwaddr_maybe_changed(NMDevice *parent, GParamSpec *pspec, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceVlan * self = NM_DEVICE_VLAN(device); - NMConnection * connection; - const char * new_mac, *old_mac; - NMSettingIPConfig *s_ip6; - - /* Never touch assumed devices */ - if (nm_device_sys_iface_state_is_external_or_assume(device)) - return; - - connection = nm_device_get_applied_connection(device); - if (!connection) - return; - - /* Update the VLAN MAC only if configuration does not specify one */ - if (nm_device_hw_addr_is_explict(device)) - return; - - old_mac = nm_device_get_hw_address(device); - new_mac = nm_device_get_hw_address(parent); - if (nm_streq0(old_mac, new_mac)) - return; - - _LOGD(LOGD_VLAN, - "parent hardware address changed to %s%s%s", - NM_PRINT_FMT_QUOTE_STRING(new_mac)); - if (new_mac) { - nm_device_hw_addr_set(device, new_mac, "vlan-parent", TRUE); - nm_device_arp_announce(device); - /* When changing the hw address the interface is taken down, - * removing the IPv6 configuration; reapply it. - */ - s_ip6 = nm_connection_get_setting_ip6_config(connection); - if (s_ip6) - nm_device_reactivate_ip6_config(device, s_ip6, s_ip6); - } -} - -static void -parent_changed_notify(NMDevice *device, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent) -{ - NMDeviceVlan * self = NM_DEVICE_VLAN(device); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE(self); - - NM_DEVICE_CLASS(nm_device_vlan_parent_class) - ->parent_changed_notify(device, old_ifindex, old_parent, new_ifindex, new_parent); - - /* note that @self doesn't have to clear @parent_state_id on dispose, - * because NMDevice's dispose() will unset the parent, which in turn calls - * parent_changed_notify(). */ - nm_clear_g_signal_handler(old_parent, &priv->parent_state_id); - nm_clear_g_signal_handler(old_parent, &priv->parent_hwaddr_id); - nm_clear_g_signal_handler(old_parent, &priv->parent_mtu_id); - - if (new_parent) { - priv->parent_state_id = g_signal_connect(new_parent, - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(parent_state_changed), - device); - - priv->parent_hwaddr_id = g_signal_connect(new_parent, - "notify::" NM_DEVICE_HW_ADDRESS, - G_CALLBACK(parent_hwaddr_maybe_changed), - device); - parent_hwaddr_maybe_changed(new_parent, NULL, self); - - priv->parent_mtu_id = g_signal_connect(new_parent, - "notify::" NM_DEVICE_MTU, - G_CALLBACK(parent_mtu_maybe_changed), - device); - parent_mtu_maybe_changed(new_parent, NULL, self); - - /* Set parent-dependent unmanaged flag */ - nm_device_set_unmanaged_by_flags(device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed(new_parent, FALSE), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); - } - - /* Recheck availability now that the parent has changed */ - if (new_ifindex > 0) { - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_PARENT_CHANGED, - NM_DEVICE_STATE_REASON_PARENT_CHANGED); - } -} - -static void -update_properties(NMDevice *device) -{ - NMDeviceVlanPrivate * priv; - const NMPlatformLink * plink = NULL; - const NMPlatformLnkVlan *plnk = NULL; - int ifindex; - int parent_ifindex = 0; - guint vlan_id; - - g_return_if_fail(NM_IS_DEVICE_VLAN(device)); - - priv = NM_DEVICE_VLAN_GET_PRIVATE(device); - - ifindex = nm_device_get_ifindex(device); - - if (ifindex > 0) - plnk = nm_platform_link_get_lnk_vlan(nm_device_get_platform(device), ifindex, &plink); - - if (plnk && plink->parent > 0) - parent_ifindex = plink->parent; - - g_object_freeze_notify((GObject *) device); - - nm_device_parent_set_ifindex(device, parent_ifindex); - - vlan_id = plnk ? plnk->id : 0; - if (vlan_id != priv->vlan_id) { - priv->vlan_id = vlan_id; - _notify((NMDeviceVlan *) device, PROP_VLAN_ID); - } - - g_object_thaw_notify((GObject *) device); -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_vlan_parent_class)->link_changed(device, pllink); - update_properties(device); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE(device); - const char * iface = nm_device_get_iface(device); - NMSettingVlan * s_vlan; - int parent_ifindex; - guint vlan_id; - int r; - - s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - - if (!parent) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "VLAN devices can not be created without a parent interface"); - return FALSE; - } - - parent_ifindex = nm_device_get_ifindex(parent); - if (parent_ifindex <= 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_MISSING_DEPENDENCIES, - "cannot retrieve ifindex of interface %s (%s)", - nm_device_get_iface(parent), - nm_device_get_type_desc(parent)); - return FALSE; - } - - if (!nm_device_supports_vlans(parent)) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "no support for VLANs on interface %s of type %s", - nm_device_get_iface(parent), - nm_device_get_type_desc(parent)); - return FALSE; - } - - vlan_id = nm_setting_vlan_get_id(s_vlan); - - r = nm_platform_link_vlan_add(nm_device_get_platform(device), - iface, - parent_ifindex, - vlan_id, - nm_setting_vlan_get_flags(s_vlan), - out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create VLAN interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - nm_device_parent_set_ifindex(device, parent_ifindex); - if (vlan_id != priv->vlan_id) { - priv->vlan_id = vlan_id; - _notify((NMDeviceVlan *) device, PROP_VLAN_ID); - } - - return TRUE; -} - -static void -unrealize_notify(NMDevice *device) -{ - NMDeviceVlan * self = NM_DEVICE_VLAN(device); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE(self); - - NM_DEVICE_CLASS(nm_device_vlan_parent_class)->unrealize_notify(device); - - if (priv->vlan_id != 0) { - priv->vlan_id = 0; - _notify(self, PROP_VLAN_ID); - } -} - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - /* We assume VLAN interfaces always support carrier detect */ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -/*****************************************************************************/ - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_vlan_parent_class)->is_available(device, flags); -} - -/*****************************************************************************/ - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE(device); - NMSettingVlan * s_vlan; - const char * parent; - - if (!NM_DEVICE_CLASS(nm_device_vlan_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (nm_device_is_real(device)) { - s_vlan = nm_connection_get_setting_vlan(connection); - - if (nm_setting_vlan_get_id(s_vlan) != priv->vlan_id) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vlan id setting mismatches"); - return FALSE; - } - - /* Check parent interface; could be an interface name or a UUID */ - parent = nm_setting_vlan_get_parent(s_vlan); - if (parent) { - if (!nm_device_match_parent(device, parent)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vlan parent setting differs"); - return FALSE; - } - } else { - /* Parent could be a MAC address in an NMSettingWired */ - if (!nm_device_match_parent_hwaddr(device, connection, TRUE)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vlan parent mac setting differs"); - return FALSE; - } - } - } - - return TRUE; -} - -static gboolean -check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - if (!nm_device_is_real(device)) - return TRUE; - - return NM_DEVICE_CLASS(nm_device_vlan_parent_class) - ->check_connection_available(device, connection, flags, specific_object, error); -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingVlan *s_vlan; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_VLAN_SETTING_NAME, - existing_connections, - NULL, - _("VLAN connection"), - NULL, - NULL, - TRUE); - - s_vlan = nm_connection_get_setting_vlan(connection); - if (!s_vlan) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'vlan' setting is required."); - return FALSE; - } - - /* If there's no VLAN interface, no parent, and no hardware address in the - * settings, then there's not enough information to complete the setting. - */ - if (!nm_setting_vlan_get_parent(s_vlan) - && !nm_device_match_parent_hwaddr(device, connection, TRUE)) { - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "The 'vlan' setting had no interface name, parent, or hardware address."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceVlanPrivate * priv = NM_DEVICE_VLAN_GET_PRIVATE(device); - NMSettingVlan * s_vlan = nm_connection_get_setting_vlan(connection); - int ifindex = nm_device_get_ifindex(device); - const NMPlatformLink *plink; - const NMPObject * polnk; - guint vlan_id; - guint vlan_flags; - - if (!s_vlan) { - s_vlan = (NMSettingVlan *) nm_setting_vlan_new(); - nm_connection_add_setting(connection, (NMSetting *) s_vlan); - } - - polnk = nm_platform_link_get_lnk(nm_device_get_platform(device), - ifindex, - NM_LINK_TYPE_VLAN, - &plink); - - if (polnk) - vlan_id = polnk->lnk_vlan.id; - else - vlan_id = priv->vlan_id; - if (vlan_id != nm_setting_vlan_get_id(s_vlan)) - g_object_set(s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL); - - g_object_set(s_vlan, - NM_SETTING_VLAN_PARENT, - nm_device_parent_find_for_connection(device, nm_setting_vlan_get_parent(s_vlan)), - NULL); - - if (polnk) - vlan_flags = polnk->lnk_vlan.flags; - else - vlan_flags = NM_VLAN_FLAG_REORDER_HEADERS; - if (vlan_flags != nm_setting_vlan_get_flags(s_vlan)) - g_object_set(s_vlan, NM_SETTING_VLAN_FLAGS, (NMVlanFlags) vlan_flags, NULL); - - if (polnk) { - _nm_setting_vlan_set_priorities(s_vlan, - NM_VLAN_INGRESS_MAP, - polnk->_lnk_vlan.ingress_qos_map, - polnk->_lnk_vlan.n_ingress_qos_map); - _nm_setting_vlan_set_priorities(s_vlan, - NM_VLAN_EGRESS_MAP, - polnk->_lnk_vlan.egress_qos_map, - polnk->_lnk_vlan.n_egress_qos_map); - } else { - _nm_setting_vlan_set_priorities(s_vlan, NM_VLAN_INGRESS_MAP, NULL, 0); - _nm_setting_vlan_set_priorities(s_vlan, NM_VLAN_EGRESS_MAP, NULL, 0); - } -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDevice * parent_device; - NMSettingVlan *s_vlan; - - /* Change MAC address to parent's one if needed */ - parent_device = nm_device_parent_get_device(device); - if (parent_device) { - parent_hwaddr_maybe_changed(parent_device, NULL, device); - parent_mtu_maybe_changed(parent_device, NULL, device); - } - - s_vlan = nm_device_get_applied_setting(device, NM_TYPE_SETTING_VLAN); - if (s_vlan) { - gs_free NMVlanQosMapping *ingress_map = NULL; - gs_free NMVlanQosMapping *egress_map = NULL; - guint n_ingress_map = 0; - guint n_egress_map = 0; - - _nm_setting_vlan_get_priorities(s_vlan, NM_VLAN_INGRESS_MAP, &ingress_map, &n_ingress_map); - _nm_setting_vlan_get_priorities(s_vlan, NM_VLAN_EGRESS_MAP, &egress_map, &n_egress_map); - - nm_platform_link_vlan_change(nm_device_get_platform(device), - nm_device_get_ifindex(device), - NM_VLAN_FLAGS_ALL, - nm_setting_vlan_get_flags(s_vlan), - TRUE, - ingress_map, - n_ingress_map, - TRUE, - egress_map, - n_egress_map); - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_VLAN_ID: - g_value_set_uint(value, priv->vlan_id); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_vlan_init(NMDeviceVlan *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_vlan = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_VLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("VlanId", - "u", - NM_DEVICE_VLAN_ID), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_vlan_class_init(NMDeviceVlanClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_vlan); - - device_class->connection_type_supported = NM_SETTING_VLAN_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_VLAN_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_VLAN); - device_class->mtu_parent_delta = 0; /* VLANs can have the same MTU of parent */ - - device_class->create_and_realize = create_and_realize; - device_class->link_changed = link_changed; - device_class->unrealize_notify = unrealize_notify; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; - device_class->is_available = is_available; - device_class->parent_changed_notify = parent_changed_notify; - - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - device_class->update_connection = update_connection; - - obj_properties[PROP_VLAN_ID] = g_param_spec_uint(NM_DEVICE_VLAN_ID, - "", - "", - 0, - 4095, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_VLAN_DEVICE_FACTORY (nm_vlan_device_factory_get_type()) -#define NM_VLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VLAN_DEVICE_FACTORY, NMVlanDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_VLAN, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_DRIVER, - "8021q", - NM_DEVICE_TYPE_DESC, - "VLAN", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_VLAN, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_VLAN, - NULL); -} - -static const char * -get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSettingVlan * s_vlan; - NMSettingWired *s_wired; - const char * parent = NULL; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_VLAN_SETTING_NAME), NULL); - - s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - - parent = nm_setting_vlan_get_parent(s_vlan); - if (parent) - return parent; - - /* Try the hardware address from the VLAN connection's hardware setting */ - s_wired = nm_connection_get_setting_wired(connection); - if (s_wired) - return nm_setting_wired_get_mac_address(s_wired); - - return NULL; -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - const char * ifname; - NMSettingVlan *s_vlan; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_VLAN_SETTING_NAME), NULL); - - s_vlan = nm_connection_get_setting_vlan(connection); - g_assert(s_vlan); - - if (!parent_iface) - return NULL; - - ifname = nm_connection_get_interface_name(connection); - if (ifname) - return g_strdup(ifname); - - /* If the connection doesn't specify the interface name for the VLAN - * device, we create one for it using the VLAN ID and the parent - * interface's name. - */ - return nm_utils_new_vlan_name(parent_iface, nm_setting_vlan_get_id(s_vlan)); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - VLAN, - Vlan, - vlan, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_VLAN) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_VLAN_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); diff --git a/src/devices/nm-device-vlan.h b/src/devices/nm-device-vlan.h deleted file mode 100644 index 5bf11cd9..00000000 --- a/src/devices/nm-device-vlan.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2012 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_VLAN_H__ -#define __NETWORKMANAGER_DEVICE_VLAN_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_VLAN (nm_device_vlan_get_type()) -#define NM_DEVICE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlan)) -#define NM_DEVICE_VLAN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VLAN, NMDeviceVlanClass)) -#define NM_IS_DEVICE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VLAN)) -#define NM_IS_DEVICE_VLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_VLAN)) -#define NM_DEVICE_VLAN_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlanClass)) - -typedef enum { - NM_VLAN_ERROR_CONNECTION_NOT_VLAN = 0, /*< nick=ConnectionNotVlan >*/ - NM_VLAN_ERROR_CONNECTION_INVALID, /*< nick=ConnectionInvalid >*/ - NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE, /*< nick=ConnectionIncompatible >*/ -} NMVlanError; - -#define NM_DEVICE_VLAN_ID "vlan-id" - -typedef struct _NMDeviceVlan NMDeviceVlan; -typedef struct _NMDeviceVlanClass NMDeviceVlanClass; - -GType nm_device_vlan_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_VLAN_H__ */ diff --git a/src/devices/nm-device-vrf.c b/src/devices/nm-device-vrf.c deleted file mode 100644 index ae0ecc60..00000000 --- a/src/devices/nm-device-vrf.c +++ /dev/null @@ -1,375 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ - -#include "nm-default.h" - -#include "nm-device-vrf.h" - -#include "nm-core-internal.h" -#include "nm-device-factory.h" -#include "nm-device-private.h" -#include "nm-manager.h" -#include "nm-setting-vrf.h" -#include "platform/nm-platform.h" -#include "settings/nm-settings.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceVrf); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceVrf, PROP_TABLE, ); - -typedef struct { - NMPlatformLnkVrf props; -} NMDeviceVrfPrivate; - -struct _NMDeviceVrf { - NMDevice parent; - NMDeviceVrfPrivate _priv; -}; - -struct _NMDeviceVrfClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceVrf, nm_device_vrf, NM_TYPE_DEVICE) - -#define NM_DEVICE_VRF_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceVrf, NM_IS_DEVICE_VRF, NMDevice) - -/*****************************************************************************/ - -static void -do_update_properties(NMDeviceVrf *self, const NMPlatformLnkVrf *props) -{ - NMDeviceVrfPrivate *priv = NM_DEVICE_VRF_GET_PRIVATE(self); - GObject * object = G_OBJECT(self); - NMPlatformLnkVrf props_null; - - if (!props) { - props_null = (NMPlatformLnkVrf){}; - props = &props_null; - } - - g_object_freeze_notify(object); - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START \ - { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - - CHECK_PROPERTY_CHANGED(table, PROP_TABLE); - - g_object_thaw_notify(object); -} - -static void -update_properties(NMDevice *device) -{ - NMDeviceVrf * self = NM_DEVICE_VRF(device); - const NMPlatformLnkVrf *props; - - props = nm_platform_link_get_lnk_vrf(nm_device_get_platform(device), - nm_device_get_ifindex(device), - NULL); - if (!props) { - _LOGW(LOGD_PLATFORM, "could not get vrf properties"); - return; - } - - do_update_properties(self, props); -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_vrf_parent_class)->link_changed(device, pllink); - update_properties(device); -} - -static void -unrealize_notify(NMDevice *device) -{ - NMDeviceVrf *self = NM_DEVICE_VRF(device); - - NM_DEVICE_CLASS(nm_device_vrf_parent_class)->unrealize_notify(device); - - do_update_properties(self, NULL); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char * iface = nm_device_get_iface(device); - NMPlatformLnkVrf props = {}; - NMSettingVrf * s_vrf; - int r; - - s_vrf = _nm_connection_get_setting(connection, NM_TYPE_SETTING_VRF); - nm_assert(s_vrf); - - props.table = nm_setting_vrf_get_table(s_vrf); - - r = nm_platform_link_vrf_add(nm_device_get_platform(device), iface, &props, out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create VRF interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceVrfPrivate *priv = NM_DEVICE_VRF_GET_PRIVATE(device); - NMSettingVrf * s_vrf; - - if (!NM_DEVICE_CLASS(nm_device_vrf_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (nm_device_is_real(device)) { - s_vrf = _nm_connection_get_setting(connection, NM_TYPE_SETTING_VRF); - - if (priv->props.table != nm_setting_vrf_get_table(s_vrf)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vrf table mismatches"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingVrf *s_vrf; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_VRF_SETTING_NAME, - existing_connections, - NULL, - _("VRF connection"), - NULL, - NULL, - TRUE); - - s_vrf = _nm_connection_get_setting(connection, NM_TYPE_SETTING_VRF); - if (!s_vrf) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'vrf' setting is required."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceVrfPrivate *priv = NM_DEVICE_VRF_GET_PRIVATE(device); - NMSettingVrf * s_vrf = _nm_connection_get_setting(connection, NM_TYPE_SETTING_VRF); - - if (!s_vrf) { - s_vrf = (NMSettingVrf *) nm_setting_vrf_new(); - nm_connection_add_setting(connection, (NMSetting *) s_vrf); - } - - if (priv->props.table != nm_setting_vrf_get_table(s_vrf)) - g_object_set(G_OBJECT(s_vrf), NM_SETTING_VRF_TABLE, priv->props.table, NULL); -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - NMDeviceVrf *self = NM_DEVICE_VRF(device); - gboolean success = TRUE; - const char * slave_iface = nm_device_get_ip_iface(slave); - - nm_device_master_check_slave_physical_port(device, slave, LOGD_DEVICE); - - if (configure) { - nm_device_take_down(slave, TRUE); - success = nm_platform_link_enslave(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - nm_device_get_ip_ifindex(slave)); - nm_device_bring_up(slave, TRUE, NULL); - - if (!success) - return FALSE; - - _LOGI(LOGD_DEVICE, "enslaved VRF slave %s", slave_iface); - } else - _LOGI(LOGD_BOND, "VRF slave %s was enslaved", slave_iface); - - return TRUE; -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{ - NMDeviceVrf *self = NM_DEVICE_VRF(device); - gboolean success; - int ifindex_slave; - int ifindex; - - if (configure) { - ifindex = nm_device_get_ifindex(device); - if (ifindex <= 0 || !nm_platform_link_get(nm_device_get_platform(device), ifindex)) - configure = FALSE; - } - - ifindex_slave = nm_device_get_ip_ifindex(slave); - - if (ifindex_slave <= 0) - _LOGD(LOGD_DEVICE, "VRF slave %s is already released", nm_device_get_ip_iface(slave)); - - if (configure) { - if (ifindex_slave > 0) { - success = nm_platform_link_release(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - ifindex_slave); - - if (success) { - _LOGI(LOGD_DEVICE, "released VRF slave %s", nm_device_get_ip_iface(slave)); - } else { - _LOGW(LOGD_DEVICE, "failed to release VRF slave %s", nm_device_get_ip_iface(slave)); - } - } - } else { - if (ifindex_slave > 0) { - _LOGI(LOGD_DEVICE, "VRF slave %s was released", nm_device_get_ip_iface(slave)); - } - } -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceVrfPrivate *priv = NM_DEVICE_VRF_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_TABLE: - g_value_set_uint(value, priv->props.table); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_vrf_init(NMDeviceVrf *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_vrf = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_VRF, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Table", "u", NM_DEVICE_VRF_TABLE), ), ), -}; - -static void -nm_device_vrf_class_init(NMDeviceVrfClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_vrf); - - device_class->connection_type_supported = NM_SETTING_VRF_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_VRF_SETTING_NAME; - device_class->is_master = TRUE; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_VRF); - - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; - device_class->link_changed = link_changed; - device_class->unrealize_notify = unrealize_notify; - device_class->create_and_realize = create_and_realize; - device_class->check_connection_compatible = check_connection_compatible; - device_class->complete_connection = complete_connection; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->update_connection = update_connection; - - obj_properties[PROP_TABLE] = g_param_spec_uint(NM_DEVICE_VRF_TABLE, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_VRF_DEVICE_FACTORY (nm_vrf_device_factory_get_type()) -#define NM_VRF_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VRF_DEVICE_FACTORY, NMVrfDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return g_object_new(NM_TYPE_DEVICE_VRF, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Vrf", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_VRF, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_VRF, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - VRF, - Vrf, - vrf, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_VRF) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_VRF_SETTING_NAME), - factory_class->create_device = create_device;); diff --git a/src/devices/nm-device-vrf.h b/src/devices/nm-device-vrf.h deleted file mode 100644 index eb09bd95..00000000 --- a/src/devices/nm-device-vrf.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ - -#ifndef __NETWORKMANAGER_DEVICE_VRF_H__ -#define __NETWORKMANAGER_DEVICE_VRF_H__ - -#include "nm-device-generic.h" - -#define NM_TYPE_DEVICE_VRF (nm_device_vrf_get_type()) -#define NM_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrf)) -#define NM_DEVICE_VRF_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VRF, NMDeviceVrfClass)) -#define NM_IS_DEVICE_VRF(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VRF)) -#define NM_IS_DEVICE_VRF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_VRF)) -#define NM_DEVICE_VRF_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_VRF, NMDeviceVrfClass)) - -#define NM_DEVICE_VRF_TABLE "table" - -typedef struct _NMDeviceVrf NMDeviceVrf; -typedef struct _NMDeviceVrfClass NMDeviceVrfClass; - -GType nm_device_vrf_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_VRF_H__ */ diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c deleted file mode 100644 index 083f29c6..00000000 --- a/src/devices/nm-device-vxlan.c +++ /dev/null @@ -1,811 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-vxlan.h" - -#include "nm-device-private.h" -#include "nm-manager.h" -#include "platform/nm-platform.h" -#include "nm-utils.h" -#include "nm-device-factory.h" -#include "nm-setting-vxlan.h" -#include "nm-setting-wired.h" -#include "settings/nm-settings.h" -#include "nm-act-request.h" -#include "nm-ip4-config.h" -#include "nm-core-internal.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceVxlan); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceVxlan, - PROP_ID, - PROP_LOCAL, - PROP_GROUP, - PROP_TOS, - PROP_TTL, - PROP_LEARNING, - PROP_AGEING, - PROP_LIMIT, - PROP_SRC_PORT_MIN, - PROP_SRC_PORT_MAX, - PROP_DST_PORT, - PROP_PROXY, - PROP_RSC, - PROP_L2MISS, - PROP_L3MISS, ); - -typedef struct { - NMPlatformLnkVxlan props; -} NMDeviceVxlanPrivate; - -struct _NMDeviceVxlan { - NMDevice parent; - NMDeviceVxlanPrivate _priv; -}; - -struct _NMDeviceVxlanClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceVxlan, nm_device_vxlan, NM_TYPE_DEVICE) - -#define NM_DEVICE_VXLAN_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceVxlan, NM_IS_DEVICE_VXLAN, NMDevice) - -/*****************************************************************************/ - -static void -update_properties(NMDevice *device) -{ - NMDeviceVxlan * self = NM_DEVICE_VXLAN(device); - NMDeviceVxlanPrivate * priv = NM_DEVICE_VXLAN_GET_PRIVATE(self); - GObject * object = G_OBJECT(device); - const NMPlatformLnkVxlan *props; - - props = nm_platform_link_get_lnk_vxlan(nm_device_get_platform(device), - nm_device_get_ifindex(device), - NULL); - if (!props) { - _LOGW(LOGD_PLATFORM, "could not get vxlan properties"); - return; - } - - g_object_freeze_notify(object); - - if (priv->props.parent_ifindex != props->parent_ifindex) - nm_device_parent_set_ifindex(device, props->parent_ifindex); - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START \ - { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - -#define CHECK_PROPERTY_CHANGED_IN6ADDR(field, prop) \ - G_STMT_START \ - { \ - if (memcmp(&priv->props.field, &props->field, sizeof(props->field)) != 0) { \ - priv->props.field = props->field; \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - - CHECK_PROPERTY_CHANGED(id, PROP_ID); - CHECK_PROPERTY_CHANGED(local, PROP_LOCAL); - CHECK_PROPERTY_CHANGED_IN6ADDR(local6, PROP_LOCAL); - CHECK_PROPERTY_CHANGED(group, PROP_GROUP); - CHECK_PROPERTY_CHANGED_IN6ADDR(group6, PROP_GROUP); - CHECK_PROPERTY_CHANGED(tos, PROP_TOS); - CHECK_PROPERTY_CHANGED(ttl, PROP_TTL); - CHECK_PROPERTY_CHANGED(learning, PROP_LEARNING); - CHECK_PROPERTY_CHANGED(ageing, PROP_AGEING); - CHECK_PROPERTY_CHANGED(limit, PROP_LIMIT); - CHECK_PROPERTY_CHANGED(src_port_min, PROP_SRC_PORT_MIN); - CHECK_PROPERTY_CHANGED(src_port_max, PROP_SRC_PORT_MAX); - CHECK_PROPERTY_CHANGED(dst_port, PROP_DST_PORT); - CHECK_PROPERTY_CHANGED(proxy, PROP_PROXY); - CHECK_PROPERTY_CHANGED(rsc, PROP_RSC); - CHECK_PROPERTY_CHANGED(l2miss, PROP_L2MISS); - CHECK_PROPERTY_CHANGED(l3miss, PROP_L3MISS); - - g_object_thaw_notify(object); -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_vxlan_parent_class)->link_changed(device, pllink); - update_properties(device); -} - -static void -unrealize_notify(NMDevice *device) -{ - NMDeviceVxlan * self = NM_DEVICE_VXLAN(device); - NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE(self); - guint i; - - NM_DEVICE_CLASS(nm_device_vxlan_parent_class)->unrealize_notify(device); - - memset(&priv->props, 0, sizeof(NMPlatformLnkVxlan)); - - for (i = 1; i < _PROPERTY_ENUMS_LAST; i++) - g_object_notify_by_pspec(G_OBJECT(self), obj_properties[i]); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char * iface = nm_device_get_iface(device); - NMPlatformLnkVxlan props = {}; - NMSettingVxlan * s_vxlan; - const char * str; - int ret; - int r; - - s_vxlan = nm_connection_get_setting_vxlan(connection); - g_assert(s_vxlan); - - if (parent) - props.parent_ifindex = nm_device_get_ifindex(parent); - - props.id = nm_setting_vxlan_get_id(s_vxlan); - - str = nm_setting_vxlan_get_local(s_vxlan); - if (str) { - ret = inet_pton(AF_INET, str, &props.local); - if (ret != 1) - ret = inet_pton(AF_INET6, str, &props.local6); - if (ret != 1) - return FALSE; - } - - str = nm_setting_vxlan_get_remote(s_vxlan); - ret = inet_pton(AF_INET, str, &props.group); - if (ret != 1) - ret = inet_pton(AF_INET6, str, &props.group6); - if (ret != 1) - return FALSE; - - props.tos = nm_setting_vxlan_get_tos(s_vxlan); - props.ttl = nm_setting_vxlan_get_ttl(s_vxlan); - props.learning = nm_setting_vxlan_get_learning(s_vxlan); - props.ageing = nm_setting_vxlan_get_ageing(s_vxlan); - props.limit = nm_setting_vxlan_get_limit(s_vxlan); - props.src_port_min = nm_setting_vxlan_get_source_port_min(s_vxlan); - props.src_port_max = nm_setting_vxlan_get_source_port_max(s_vxlan); - props.dst_port = nm_setting_vxlan_get_destination_port(s_vxlan); - props.proxy = nm_setting_vxlan_get_proxy(s_vxlan); - props.rsc = nm_setting_vxlan_get_rsc(s_vxlan); - props.l2miss = nm_setting_vxlan_get_l2_miss(s_vxlan); - props.l3miss = nm_setting_vxlan_get_l3_miss(s_vxlan); - - r = nm_platform_link_vxlan_add(nm_device_get_platform(device), iface, &props, out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create VXLAN interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -static gboolean -address_matches(const char *str, in_addr_t addr4, struct in6_addr *addr6) -{ - in_addr_t new_addr4 = 0; - struct in6_addr new_addr6 = {}; - - if (!str) { - return addr4 == 0 && !memcmp(addr6, &in6addr_any, sizeof(in6addr_any)); - } - - if (inet_pton(AF_INET, str, &new_addr4) == 1) - return new_addr4 == addr4; - else if (inet_pton(AF_INET6, str, &new_addr6) == 1) - return !memcmp(&new_addr6, addr6, sizeof(new_addr6)); - else - return FALSE; -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE(device); - NMSettingVxlan * s_vxlan; - const char * parent; - - if (!NM_DEVICE_CLASS(nm_device_vxlan_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (nm_device_is_real(device)) { - s_vxlan = nm_connection_get_setting_vxlan(connection); - - parent = nm_setting_vxlan_get_parent(s_vxlan); - if (parent && !nm_device_match_parent(device, parent)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan parent mismatches"); - return FALSE; - } - - if (priv->props.id != nm_setting_vxlan_get_id(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan id mismatches"); - return FALSE; - } - - if (!address_matches(nm_setting_vxlan_get_local(s_vxlan), - priv->props.local, - &priv->props.local6)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan local address mismatches"); - return FALSE; - } - - if (!address_matches(nm_setting_vxlan_get_remote(s_vxlan), - priv->props.group, - &priv->props.group6)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan remote address mismatches"); - return FALSE; - } - - if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan source port min mismatches"); - return FALSE; - } - - if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan source port max mismatches"); - return FALSE; - } - - if (priv->props.dst_port != nm_setting_vxlan_get_destination_port(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan destination port mismatches"); - return FALSE; - } - - if (priv->props.tos != nm_setting_vxlan_get_tos(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan TOS mismatches"); - return FALSE; - } - - if (priv->props.ttl != nm_setting_vxlan_get_ttl(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan TTL mismatches"); - return FALSE; - } - - if (priv->props.learning != nm_setting_vxlan_get_learning(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan learning mismatches"); - return FALSE; - } - - if (priv->props.ageing != nm_setting_vxlan_get_ageing(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan ageing mismatches"); - return FALSE; - } - - if (priv->props.proxy != nm_setting_vxlan_get_proxy(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan proxy mismatches"); - return FALSE; - } - - if (priv->props.rsc != nm_setting_vxlan_get_rsc(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan rsc mismatches"); - return FALSE; - } - - if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan l2miss mismatches"); - return FALSE; - } - - if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss(s_vxlan)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "vxlan l3miss mismatches"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingVxlan *s_vxlan; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_VXLAN_SETTING_NAME, - existing_connections, - NULL, - _("VXLAN connection"), - NULL, - NULL, - TRUE); - - s_vxlan = nm_connection_get_setting_vxlan(connection); - if (!s_vxlan) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'vxlan' setting is required."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE(device); - NMSettingVxlan * s_vxlan = nm_connection_get_setting_vxlan(connection); - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - if (!s_vxlan) { - s_vxlan = (NMSettingVxlan *) nm_setting_vxlan_new(); - nm_connection_add_setting(connection, (NMSetting *) s_vxlan); - } - - if (priv->props.id != nm_setting_vxlan_get_id(s_vxlan)) - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_ID, priv->props.id, NULL); - - g_object_set(s_vxlan, - NM_SETTING_VXLAN_PARENT, - nm_device_parent_find_for_connection(device, nm_setting_vxlan_get_parent(s_vxlan)), - NULL); - - if (!address_matches(nm_setting_vxlan_get_remote(s_vxlan), - priv->props.group, - &priv->props.group6)) { - if (priv->props.group) { - g_object_set(s_vxlan, - NM_SETTING_VXLAN_REMOTE, - _nm_utils_inet4_ntop(priv->props.group, sbuf), - NULL); - } else { - g_object_set(s_vxlan, - NM_SETTING_VXLAN_REMOTE, - _nm_utils_inet6_ntop(&priv->props.group6, sbuf), - NULL); - } - } - - if (!address_matches(nm_setting_vxlan_get_local(s_vxlan), - priv->props.local, - &priv->props.local6)) { - if (priv->props.local) { - g_object_set(s_vxlan, - NM_SETTING_VXLAN_LOCAL, - _nm_utils_inet4_ntop(priv->props.local, sbuf), - NULL); - } else if (memcmp(&priv->props.local6, &in6addr_any, sizeof(in6addr_any))) { - g_object_set(s_vxlan, - NM_SETTING_VXLAN_LOCAL, - _nm_utils_inet6_ntop(&priv->props.local6, sbuf), - NULL); - } - } - - if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), - NM_SETTING_VXLAN_SOURCE_PORT_MIN, - priv->props.src_port_min, - NULL); - } - - if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), - NM_SETTING_VXLAN_SOURCE_PORT_MAX, - priv->props.src_port_max, - NULL); - } - - if (priv->props.dst_port != nm_setting_vxlan_get_destination_port(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), - NM_SETTING_VXLAN_DESTINATION_PORT, - priv->props.dst_port, - NULL); - } - - if (priv->props.tos != nm_setting_vxlan_get_tos(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_TOS, priv->props.tos, NULL); - } - - if (priv->props.ttl != nm_setting_vxlan_get_ttl(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_TTL, priv->props.ttl, NULL); - } - - if (priv->props.learning != nm_setting_vxlan_get_learning(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_LEARNING, priv->props.learning, NULL); - } - - if (priv->props.ageing != nm_setting_vxlan_get_ageing(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_AGEING, priv->props.ageing, NULL); - } - - if (priv->props.proxy != nm_setting_vxlan_get_proxy(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_PROXY, priv->props.proxy, NULL); - } - - if (priv->props.rsc != nm_setting_vxlan_get_rsc(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_RSC, priv->props.rsc, NULL); - } - - if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_L2_MISS, priv->props.l2miss, NULL); - } - - if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss(s_vxlan)) { - g_object_set(G_OBJECT(s_vxlan), NM_SETTING_VXLAN_L3_MISS, priv->props.l3miss, NULL); - } -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_ID: - g_value_set_uint(value, priv->props.id); - break; - case PROP_GROUP: - if (priv->props.group) - g_value_take_string(value, nm_utils_inet4_ntop_dup(priv->props.group)); - else if (!IN6_IS_ADDR_UNSPECIFIED(&priv->props.group6)) - g_value_take_string(value, nm_utils_inet6_ntop_dup(&priv->props.group6)); - break; - case PROP_LOCAL: - if (priv->props.local) - g_value_take_string(value, nm_utils_inet4_ntop_dup(priv->props.local)); - else if (!IN6_IS_ADDR_UNSPECIFIED(&priv->props.local6)) - g_value_take_string(value, nm_utils_inet6_ntop_dup(&priv->props.local6)); - break; - case PROP_TOS: - g_value_set_uchar(value, priv->props.tos); - break; - case PROP_TTL: - g_value_set_uchar(value, priv->props.ttl); - break; - case PROP_LEARNING: - g_value_set_boolean(value, priv->props.learning); - break; - case PROP_AGEING: - g_value_set_uint(value, priv->props.ageing); - break; - case PROP_LIMIT: - g_value_set_uint(value, priv->props.limit); - break; - case PROP_DST_PORT: - g_value_set_uint(value, priv->props.dst_port); - break; - case PROP_SRC_PORT_MIN: - g_value_set_uint(value, priv->props.src_port_min); - break; - case PROP_SRC_PORT_MAX: - g_value_set_uint(value, priv->props.src_port_max); - break; - case PROP_PROXY: - g_value_set_boolean(value, priv->props.proxy); - break; - case PROP_RSC: - g_value_set_boolean(value, priv->props.rsc); - break; - case PROP_L2MISS: - g_value_set_boolean(value, priv->props.l2miss); - break; - case PROP_L3MISS: - g_value_set_boolean(value, priv->props.l3miss); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_vxlan_init(NMDeviceVxlan *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_vxlan = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_VXLAN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Parent", "o", NM_DEVICE_PARENT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Id", "u", NM_DEVICE_VXLAN_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Group", "s", NM_DEVICE_VXLAN_GROUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Local", "s", NM_DEVICE_VXLAN_LOCAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Tos", "y", NM_DEVICE_VXLAN_TOS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ttl", "y", NM_DEVICE_VXLAN_TTL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Learning", - "b", - NM_DEVICE_VXLAN_LEARNING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ageing", "u", NM_DEVICE_VXLAN_AGEING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Limit", "u", NM_DEVICE_VXLAN_LIMIT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DstPort", - "q", - NM_DEVICE_VXLAN_DST_PORT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("SrcPortMin", - "q", - NM_DEVICE_VXLAN_SRC_PORT_MIN), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("SrcPortMax", - "q", - NM_DEVICE_VXLAN_SRC_PORT_MAX), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Proxy", "b", NM_DEVICE_VXLAN_PROXY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Rsc", "b", NM_DEVICE_VXLAN_RSC), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("L2miss", "b", NM_DEVICE_VXLAN_L2MISS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("L3miss", - "b", - NM_DEVICE_VXLAN_L3MISS), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_vxlan_class_init(NMDeviceVxlanClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_vxlan); - - device_class->connection_type_supported = NM_SETTING_VXLAN_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_VXLAN_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_VXLAN); - - device_class->link_changed = link_changed; - device_class->unrealize_notify = unrealize_notify; - device_class->create_and_realize = create_and_realize; - device_class->check_connection_compatible = check_connection_compatible; - device_class->complete_connection = complete_connection; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->update_connection = update_connection; - device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - - obj_properties[PROP_ID] = g_param_spec_uint(NM_DEVICE_VXLAN_ID, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LOCAL] = g_param_spec_string(NM_DEVICE_VXLAN_LOCAL, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_GROUP] = g_param_spec_string(NM_DEVICE_VXLAN_GROUP, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_TOS] = g_param_spec_uchar(NM_DEVICE_VXLAN_TOS, - "", - "", - 0, - 255, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_TTL] = g_param_spec_uchar(NM_DEVICE_VXLAN_TTL, - "", - "", - 0, - 255, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LEARNING] = g_param_spec_boolean(NM_DEVICE_VXLAN_LEARNING, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_AGEING] = g_param_spec_uint(NM_DEVICE_VXLAN_AGEING, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LIMIT] = g_param_spec_uint(NM_DEVICE_VXLAN_LIMIT, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SRC_PORT_MIN] = - g_param_spec_uint(NM_DEVICE_VXLAN_SRC_PORT_MIN, - "", - "", - 0, - 65535, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SRC_PORT_MAX] = - g_param_spec_uint(NM_DEVICE_VXLAN_SRC_PORT_MAX, - "", - "", - 0, - 65535, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_DST_PORT] = g_param_spec_uint(NM_DEVICE_VXLAN_DST_PORT, - "", - "", - 0, - 65535, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_PROXY] = g_param_spec_boolean(NM_DEVICE_VXLAN_PROXY, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_RSC] = g_param_spec_boolean(NM_DEVICE_VXLAN_RSC, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_L2MISS] = g_param_spec_boolean(NM_DEVICE_VXLAN_L2MISS, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_L3MISS] = g_param_spec_boolean(NM_DEVICE_VXLAN_L3MISS, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -#define NM_TYPE_VXLAN_DEVICE_FACTORY (nm_vxlan_device_factory_get_type()) -#define NM_VXLAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_VXLAN_DEVICE_FACTORY, NMVxlanDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_VXLAN, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "Vxlan", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_VXLAN, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_VXLAN, - NULL); -} - -static const char * -get_connection_parent(NMDeviceFactory *factory, NMConnection *connection) -{ - NMSettingVxlan *s_vxlan; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_VXLAN_SETTING_NAME), NULL); - - s_vxlan = nm_connection_get_setting_vxlan(connection); - g_assert(s_vxlan); - - return nm_setting_vxlan_get_parent(s_vxlan); -} - -static char * -get_connection_iface(NMDeviceFactory *factory, NMConnection *connection, const char *parent_iface) -{ - const char * ifname; - NMSettingVxlan *s_vxlan; - - g_return_val_if_fail(nm_connection_is_type(connection, NM_SETTING_VXLAN_SETTING_NAME), NULL); - - s_vxlan = nm_connection_get_setting_vxlan(connection); - g_assert(s_vxlan); - - if (nm_setting_vxlan_get_parent(s_vxlan) && !parent_iface) - return NULL; - - ifname = nm_connection_get_interface_name(connection); - return g_strdup(ifname); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - VXLAN, - Vxlan, - vxlan, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_VXLAN) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_VXLAN_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->get_connection_parent = get_connection_parent; - factory_class->get_connection_iface = get_connection_iface;); diff --git a/src/devices/nm-device-vxlan.h b/src/devices/nm-device-vxlan.h deleted file mode 100644 index 89683b02..00000000 --- a/src/devices/nm-device-vxlan.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013, 2014 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_VXLAN_H__ -#define __NETWORKMANAGER_DEVICE_VXLAN_H__ - -#include "nm-device-generic.h" - -#define NM_TYPE_DEVICE_VXLAN (nm_device_vxlan_get_type()) -#define NM_DEVICE_VXLAN(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlan)) -#define NM_DEVICE_VXLAN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanClass)) -#define NM_IS_DEVICE_VXLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_VXLAN)) -#define NM_IS_DEVICE_VXLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_VXLAN)) -#define NM_DEVICE_VXLAN_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanClass)) - -#define NM_DEVICE_VXLAN_ID "id" -#define NM_DEVICE_VXLAN_GROUP "group" -#define NM_DEVICE_VXLAN_LOCAL "local" -#define NM_DEVICE_VXLAN_TOS "tos" -#define NM_DEVICE_VXLAN_TTL "ttl" -#define NM_DEVICE_VXLAN_LEARNING "learning" -#define NM_DEVICE_VXLAN_AGEING "ageing" -#define NM_DEVICE_VXLAN_LIMIT "limit" -#define NM_DEVICE_VXLAN_DST_PORT "dst-port" -#define NM_DEVICE_VXLAN_SRC_PORT_MIN "src-port-min" -#define NM_DEVICE_VXLAN_SRC_PORT_MAX "src-port-max" -#define NM_DEVICE_VXLAN_PROXY "proxy" -#define NM_DEVICE_VXLAN_RSC "rsc" -#define NM_DEVICE_VXLAN_L2MISS "l2miss" -#define NM_DEVICE_VXLAN_L3MISS "l3miss" - -typedef struct _NMDeviceVxlan NMDeviceVxlan; -typedef struct _NMDeviceVxlanClass NMDeviceVxlanClass; - -GType nm_device_vxlan_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_VXLAN_H__ */ diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c deleted file mode 100644 index 9bd23e65..00000000 --- a/src/devices/nm-device-wireguard.c +++ /dev/null @@ -1,2026 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Javier Arteaga <jarteaga@jbeta.is> - */ - -#include "nm-default.h" - -#include "nm-device-wireguard.h" - -#include <linux/rtnetlink.h> -#include <linux/fib_rules.h> - -#include "nm-setting-wireguard.h" -#include "nm-core-internal.h" -#include "nm-glib-aux/nm-secret-utils.h" -#include "nm-device-private.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" -#include "platform/nmp-rules-manager.h" -#include "nm-device-factory.h" -#include "nm-active-connection.h" -#include "nm-act-request.h" -#include "dns/nm-dns-manager.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceWireGuard); - -/*****************************************************************************/ - -/* TODO: activate profile with peer preshared-key-flags=2. On first activation, the secret is - * requested (good). Enter it and connect. Reactivate the profile, now there is no password - * prompt, as the secret is cached (good??). */ - -/* TODO: unlike for other VPNs, we don't inject a direct route to the peers. That means, - * you might get a routing scenario where the peer (VPN server) is reachable via the VPN. - * How we handle adding routes to external gateway for other peers, has severe issues - * as well. We may use policy-routing like wg-quick does. See also discussions at - * https://www.wireguard.com/netns/#improving-the-classic-solutions */ - -/* TODO: honor the TTL of DNS to determine when to retry resolving endpoints. */ - -/* TODO: when we get multiple IP addresses when resolving a peer endpoint. We currently - * just take the first from GAI. We should only accept AAAA/IPv6 if we also have a suitable - * IPv6 address. The problem is, that we have to recheck that when IP addressing on other - * interfaces changes. This makes it almost too cumbersome to implement. */ - -/*****************************************************************************/ - -G_STATIC_ASSERT(NM_WIREGUARD_PUBLIC_KEY_LEN == NMP_WIREGUARD_PUBLIC_KEY_LEN); -G_STATIC_ASSERT(NM_WIREGUARD_SYMMETRIC_KEY_LEN == NMP_WIREGUARD_SYMMETRIC_KEY_LEN); - -/*****************************************************************************/ - -#define LINK_CONFIG_RATE_LIMIT_NSEC (50 * NM_UTILS_NSEC_PER_MSEC) - -/* a special @next_try_at_nsec timestamp indicating that we should try again as soon as possible. */ -#define NEXT_TRY_AT_NSEC_ASAP ((gint64) G_MAXINT64) - -/* a special @next_try_at_nsec timestamp that is - * - positive (indicating resolve-checks are enabled) - * - already in the past (we use the absolute timestamp of 1nsec for that). */ -#define NEXT_TRY_AT_NSEC_PAST ((gint64) 1) - -/* like %NEXT_TRY_AT_NSEC_ASAP, but used for indicating to retry ASAP for a @retry_in_msec value. - * That is a relative time duration, contrary to @next_try_at_nsec which is an absolute - * timestamp. */ -#define RETRY_IN_MSEC_ASAP ((gint64) G_MAXINT64) - -#define RETRY_IN_MSEC_MAX ((gint64)(30 * 60 * 1000)) - -typedef enum { - LINK_CONFIG_MODE_FULL, - LINK_CONFIG_MODE_REAPPLY, - LINK_CONFIG_MODE_ASSUME, - LINK_CONFIG_MODE_ENDPOINTS, -} LinkConfigMode; - -typedef struct { - GCancellable *cancellable; - - NMSockAddrUnion sockaddr; - - /* the timestamp (in nm_utils_get_monotonic_timestamp_nsec() scale) when we want - * to retry resolving the endpoint (again). - * - * It may be set to %NEXT_TRY_AT_NSEC_ASAP to indicate to re-resolve as soon as possible. - * - * A @sockaddr is either fixed or it has - * - @cancellable set to indicate an ongoing request - * - @next_try_at_nsec set to a positive value, indicating when - * we ought to retry. */ - gint64 next_try_at_nsec; - - guint resolv_fail_count; -} PeerEndpointResolveData; - -typedef struct { - NMWireGuardPeer *peer; - - NMDeviceWireGuard *self; - - CList lst_peers; - - PeerEndpointResolveData ep_resolv; - - /* dirty flag used during _peers_update_all(). */ - bool dirty_update_all : 1; -} PeerData; - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceWireGuard, PROP_PUBLIC_KEY, PROP_LISTEN_PORT, PROP_FWMARK, ); - -typedef struct { - NMDnsManager *dns_manager; - - NMPlatformLnkWireGuard lnk_curr; - NMActRequestGetSecretsCallId *secrets_call_id; - - CList lst_peers_head; - GHashTable *peers; - - gint64 resolve_next_try_at; - gint64 link_config_last_at; - - guint resolve_next_try_id; - guint link_config_delayed_id; - - guint32 auto_default_route_fwmark; - - guint32 auto_default_route_priority; - - bool auto_default_route_enabled_4 : 1; - bool auto_default_route_enabled_6 : 1; - bool auto_default_route_initialized : 1; - bool auto_default_route_refresh : 1; - bool auto_default_route_priority_initialized : 1; - -} NMDeviceWireGuardPrivate; - -struct _NMDeviceWireGuard { - NMDevice parent; - NMDeviceWireGuardPrivate _priv; -}; - -struct _NMDeviceWireGuardClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceWireGuard, nm_device_wireguard, NM_TYPE_DEVICE) - -#define NM_DEVICE_WIREGUARD_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceWireGuard, NM_IS_DEVICE_WIREGUARD, NMDevice) - -/*****************************************************************************/ - -static void _peers_resolve_start(NMDeviceWireGuard *self, PeerData *peer_data); - -static void _peers_resolve_retry_reschedule(NMDeviceWireGuard *self, gint64 new_next_try_at_nsec); - -static gboolean link_config_delayed_resolver_cb(gpointer user_data); - -static gboolean link_config_delayed_ratelimit_cb(gpointer user_data); - -/*****************************************************************************/ - -static NM_UTILS_LOOKUP_STR_DEFINE(_link_config_mode_to_string, - LinkConfigMode, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT(NULL), - NM_UTILS_LOOKUP_ITEM(LINK_CONFIG_MODE_FULL, "full"), - NM_UTILS_LOOKUP_ITEM(LINK_CONFIG_MODE_REAPPLY, "reapply"), - NM_UTILS_LOOKUP_ITEM(LINK_CONFIG_MODE_ASSUME, "assume"), - NM_UTILS_LOOKUP_ITEM(LINK_CONFIG_MODE_ENDPOINTS, "endpoints"), ); - -/*****************************************************************************/ - -static void -_auto_default_route_get_enabled(NMSettingWireGuard *s_wg, - NMConnection * connection, - gboolean * out_enabled_v4, - gboolean * out_enabled_v6) -{ - NMTernary enabled_v4; - NMTernary enabled_v6; - - enabled_v4 = nm_setting_wireguard_get_ip4_auto_default_route(s_wg); - enabled_v6 = nm_setting_wireguard_get_ip6_auto_default_route(s_wg); - - if (enabled_v4 == NM_TERNARY_DEFAULT) { - if (nm_setting_ip_config_get_never_default( - nm_connection_get_setting_ip_config(connection, AF_INET))) - enabled_v4 = FALSE; - } - if (enabled_v6 == NM_TERNARY_DEFAULT) { - if (nm_setting_ip_config_get_never_default( - nm_connection_get_setting_ip_config(connection, AF_INET6))) - enabled_v6 = FALSE; - } - - if (enabled_v4 == NM_TERNARY_DEFAULT || enabled_v6 == NM_TERNARY_DEFAULT) { - guint i, n_peers; - - n_peers = nm_setting_wireguard_get_peers_len(s_wg); - for (i = 0; i < n_peers; i++) { - NMWireGuardPeer *peer = nm_setting_wireguard_get_peer(s_wg, i); - guint n_aips; - guint j; - - n_aips = nm_wireguard_peer_get_allowed_ips_len(peer); - for (j = 0; j < n_aips; j++) { - const char *aip; - gboolean valid; - int prefix; - int addr_family; - - aip = nm_wireguard_peer_get_allowed_ip(peer, j, &valid); - if (!valid) - continue; - if (!nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, aip, &addr_family, NULL, &prefix)) - continue; - if (prefix != 0) - continue; - - if (addr_family == AF_INET) { - if (enabled_v4 == NM_TERNARY_DEFAULT) { - enabled_v4 = TRUE; - if (enabled_v6 != NM_TERNARY_DEFAULT) - goto done; - } - } else { - if (enabled_v6 == NM_TERNARY_DEFAULT) { - enabled_v6 = TRUE; - if (enabled_v4 != NM_TERNARY_DEFAULT) - goto done; - } - } - } - } -done:; - } - - *out_enabled_v4 = (enabled_v4 == TRUE); - *out_enabled_v6 = (enabled_v6 == TRUE); -} - -#define AUTO_RANDOM_RANGE 500u - -static guint32 -_auto_default_route_get_auto_fwmark(const char *uuid) -{ - guint64 rnd_seed; - - /* we use the generated number as fwmark but also as routing table for - * the default-route. - * - * We pick a number - * - * - based on the connection's UUID (as stable seed). - * - larger than 51820u (arbitrarily) - * - one out of AUTO_RANDOM_RANGE - */ - - rnd_seed = c_siphash_hash(NM_HASH_SEED_16(0xb9, - 0x39, - 0x8e, - 0xed, - 0x15, - 0xb3, - 0xd1, - 0xc4, - 0x5f, - 0x45, - 0x00, - 0x4f, - 0xec, - 0xc2, - 0x2b, - 0x7e), - (const guint8 *) uuid, - uuid ? strlen(uuid) + 1u : 0u); - - return 51820u + (rnd_seed % AUTO_RANDOM_RANGE); -} - -#define PRIO_WIDTH 2u - -static guint32 -_auto_default_route_get_auto_priority(const char *uuid) -{ - const guint32 RANGE_TOP = 32766u - 1000u; - guint64 rnd_seed; - - /* we pick a priority for the routing rules as follows: - * - * - use the connection's UUID as stable seed for the "random" number. - * - have it smaller than RANGE_TOP (32766u - 1000u), where 32766u is the priority of the default - * rules - * - we add 2 rules (PRIO_WIDTH). Hence only pick even priorities. - * - pick one out of AUTO_RANDOM_RANGE. */ - - rnd_seed = c_siphash_hash(NM_HASH_SEED_16(0x99, - 0x22, - 0x4d, - 0x7c, - 0x37, - 0xda, - 0x8e, - 0x7b, - 0x2f, - 0x55, - 0x16, - 0x7b, - 0x75, - 0xda, - 0x42, - 0xdc), - (const guint8 *) uuid, - uuid ? strlen(uuid) + 1u : 0u); - - return RANGE_TOP - (((rnd_seed % (PRIO_WIDTH * AUTO_RANDOM_RANGE)) / PRIO_WIDTH) * PRIO_WIDTH); -} - -static void -_auto_default_route_init(NMDeviceWireGuard *self) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - NMConnection * connection; - gboolean enabled_v4 = FALSE; - gboolean enabled_v6 = FALSE; - gboolean refreshing_only; - guint32 new_fwmark = 0; - guint32 old_fwmark; - char sbuf1[100]; - - if (G_LIKELY(priv->auto_default_route_initialized && !priv->auto_default_route_refresh)) - return; - - refreshing_only = priv->auto_default_route_initialized && priv->auto_default_route_refresh; - - old_fwmark = priv->auto_default_route_fwmark; - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - if (connection) { - NMSettingWireGuard *s_wg; - - s_wg = _nm_connection_get_setting(connection, NM_TYPE_SETTING_WIREGUARD); - - new_fwmark = nm_setting_wireguard_get_fwmark(s_wg); - - _auto_default_route_get_enabled(s_wg, connection, &enabled_v4, &enabled_v6); - } - - if ((enabled_v4 || enabled_v6) && new_fwmark == 0u) { - if (refreshing_only) - new_fwmark = old_fwmark; - else - new_fwmark = _auto_default_route_get_auto_fwmark(nm_connection_get_uuid(connection)); - } - - priv->auto_default_route_refresh = FALSE; - priv->auto_default_route_fwmark = new_fwmark; - priv->auto_default_route_enabled_4 = enabled_v4; - priv->auto_default_route_enabled_6 = enabled_v6; - priv->auto_default_route_initialized = TRUE; - - if (connection) { - _LOGT(LOGD_DEVICE, - "auto-default-route is %s for IPv4 and %s for IPv6%s", - priv->auto_default_route_enabled_4 ? "enabled" : "disabled", - priv->auto_default_route_enabled_6 ? "enabled" : "disabled", - priv->auto_default_route_enabled_4 || priv->auto_default_route_enabled_6 - ? nm_sprintf_buf(sbuf1, " (fwmark 0x%x)", priv->auto_default_route_fwmark) - : ""); - } -} - -static GPtrArray * -get_extra_rules(NMDevice *device) -{ - NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(device); - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - gs_unref_ptrarray GPtrArray *extra_rules = NULL; - guint32 priority = 0; - int is_ipv4; - NMConnection * connection; - - _auto_default_route_init(self); - - connection = nm_device_get_applied_connection(device); - if (!connection) - return NULL; - - for (is_ipv4 = 0; is_ipv4 < 2; is_ipv4++) { - NMSettingIPConfig *s_ip; - int addr_family = is_ipv4 ? AF_INET : AF_INET6; - guint32 table_main; - guint32 fwmark; - - if (is_ipv4) { - if (!priv->auto_default_route_enabled_4) - continue; - } else { - if (!priv->auto_default_route_enabled_6) - continue; - } - - if (!extra_rules) { - if (priv->auto_default_route_priority_initialized) - priority = priv->auto_default_route_priority; - else { - priority = - _auto_default_route_get_auto_priority(nm_connection_get_uuid(connection)); - priv->auto_default_route_priority = priority; - priv->auto_default_route_priority_initialized = TRUE; - } - extra_rules = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); - } - - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - table_main = nm_setting_ip_config_get_route_table(s_ip); - if (table_main == 0) - table_main = RT_TABLE_MAIN; - - fwmark = priv->auto_default_route_fwmark; - - G_STATIC_ASSERT_EXPR(PRIO_WIDTH == 2); - - g_ptr_array_add(extra_rules, - nmp_object_new(NMP_OBJECT_TYPE_ROUTING_RULE, - &((const NMPlatformRoutingRule){ - .priority = priority, - .addr_family = addr_family, - .action = FR_ACT_TO_TBL, - .table = table_main, - .suppress_prefixlen_inverse = ~((guint32) 0u), - }))); - - g_ptr_array_add(extra_rules, - nmp_object_new(NMP_OBJECT_TYPE_ROUTING_RULE, - &((const NMPlatformRoutingRule){ - .priority = priority + 1u, - .addr_family = addr_family, - .action = FR_ACT_TO_TBL, - .table = fwmark, - .flags = FIB_RULE_INVERT, - .fwmark = fwmark, - .fwmask = 0xFFFFFFFFu, - }))); - } - - return g_steal_pointer(&extra_rules); -} - -static guint32 -coerce_route_table(NMDevice *device, int addr_family, guint32 route_table, gboolean is_user_config) -{ - NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(device); - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - gboolean auto_default_route_enabled; - - if (route_table != 0u) - return route_table; - - _auto_default_route_init(self); - - auto_default_route_enabled = (addr_family == AF_INET) ? priv->auto_default_route_enabled_4 - : priv->auto_default_route_enabled_6; - - if (auto_default_route_enabled) { - /* we need to enable full-sync mode of all routing tables. */ - _LOGT(LOGD_DEVICE, - "coerce ipv%c.route-table setting to \"main\" (table 254) as we enable " - "auto-default-route handling", - nm_utils_addr_family_to_char(addr_family)); - return RT_TABLE_MAIN; - } - - return 0; -} - -/*****************************************************************************/ - -static gboolean -_peer_data_equal(gconstpointer ptr_a, gconstpointer ptr_b) -{ - const PeerData *peer_data_a = ptr_a; - const PeerData *peer_data_b = ptr_b; - - return nm_streq(nm_wireguard_peer_get_public_key(peer_data_a->peer), - nm_wireguard_peer_get_public_key(peer_data_b->peer)); -} - -static guint -_peer_data_hash(gconstpointer ptr) -{ - const PeerData *peer_data = ptr; - - return nm_hash_str(nm_wireguard_peer_get_public_key(peer_data->peer)); -} - -static PeerData * -_peers_find(NMDeviceWireGuardPrivate *priv, NMWireGuardPeer *peer) -{ - nm_assert(peer); - - G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(PeerData, peer) == 0); - - return g_hash_table_lookup(priv->peers, &peer); -} - -static void -_peers_remove(NMDeviceWireGuardPrivate *priv, PeerData *peer_data) -{ - nm_assert(peer_data); - nm_assert(g_hash_table_lookup(priv->peers, peer_data) == peer_data); - - if (!g_hash_table_remove(priv->peers, peer_data)) - nm_assert_not_reached(); - - c_list_unlink_stale(&peer_data->lst_peers); - nm_wireguard_peer_unref(peer_data->peer); - nm_clear_g_cancellable(&peer_data->ep_resolv.cancellable); - g_slice_free(PeerData, peer_data); - - if (c_list_is_empty(&priv->lst_peers_head)) { - nm_clear_g_source(&priv->resolve_next_try_id); - nm_clear_g_source(&priv->link_config_delayed_id); - } -} - -static PeerData * -_peers_add(NMDeviceWireGuard *self, NMWireGuardPeer *peer) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - PeerData * peer_data; - - nm_assert(peer); - nm_assert(nm_wireguard_peer_is_sealed(peer)); - nm_assert(!_peers_find(priv, peer)); - - peer_data = g_slice_new(PeerData); - *peer_data = (PeerData){ - .self = self, - .peer = nm_wireguard_peer_ref(peer), - .ep_resolv = - { - .sockaddr = NM_SOCK_ADDR_UNION_INIT_UNSPEC, - }, - }; - - c_list_link_tail(&priv->lst_peers_head, &peer_data->lst_peers); - if (!nm_g_hash_table_add(priv->peers, peer_data)) - nm_assert_not_reached(); - return peer_data; -} - -static gboolean -_peers_resolve_retry_timeout(gpointer user_data) -{ - NMDeviceWireGuard * self = user_data; - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - PeerData * peer_data; - gint64 now; - gint64 next; - - priv->resolve_next_try_id = 0; - - _LOGT(LOGD_DEVICE, "wireguard-peers: rechecking peer endpoints..."); - - now = nm_utils_get_monotonic_timestamp_nsec(); - next = G_MAXINT64; - c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) { - if (peer_data->ep_resolv.next_try_at_nsec <= 0) - continue; - - if (peer_data->ep_resolv.cancellable) { - /* we are currently resolving a name. We don't need the global - * watchdog to guard this peer. No need to adjust @next for - * this one, when the currently ongoing resolving completes, we - * may reschedule. Skip. */ - continue; - } - - if (peer_data->ep_resolv.next_try_at_nsec == NEXT_TRY_AT_NSEC_ASAP - || now >= peer_data->ep_resolv.next_try_at_nsec) { - _peers_resolve_start(self, peer_data); - /* same here. Now we are resolving. We don't need the global - * watchdog. Skip w.r.t. finding @next. */ - continue; - } - - if (next > peer_data->ep_resolv.next_try_at_nsec) - next = peer_data->ep_resolv.next_try_at_nsec; - } - if (next < G_MAXINT64) - _peers_resolve_retry_reschedule(self, next); - - return G_SOURCE_REMOVE; -} - -static void -_peers_resolve_retry_reschedule(NMDeviceWireGuard *self, gint64 new_next_try_at_nsec) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - guint32 interval_ms; - gint64 now; - - nm_assert(new_next_try_at_nsec > 0); - nm_assert(new_next_try_at_nsec != NEXT_TRY_AT_NSEC_ASAP); - - if (priv->resolve_next_try_id && priv->resolve_next_try_at <= new_next_try_at_nsec) { - /* we already have an earlier timeout scheduled (possibly for - * another peer that expires sooner). Don't reschedule now. - * Even if the scheduled timeout expires too early, we will - * compute the right next-timeout and reschedule then. */ - return; - } - - now = nm_utils_get_monotonic_timestamp_nsec(); - - /* schedule at most one day ahead. No problem if we expire earlier - * than expected. Also, rate-limit to 500 msec. */ - interval_ms = NM_CLAMP((new_next_try_at_nsec - now) / NM_UTILS_NSEC_PER_MSEC, - (gint64) 500, - (gint64)(24 * 60 * 60 * 1000)); - - _LOGT(LOGD_DEVICE, - "wireguard-peers: schedule rechecking peer endpoints in %u msec", - interval_ms); - - nm_clear_g_source(&priv->resolve_next_try_id); - priv->resolve_next_try_at = new_next_try_at_nsec; - priv->resolve_next_try_id = g_timeout_add(interval_ms, _peers_resolve_retry_timeout, self); -} - -static void -_peers_resolve_retry_reschedule_for_peer(NMDeviceWireGuard *self, - PeerData * peer_data, - gint64 retry_in_msec) -{ - nm_assert(retry_in_msec >= 0); - - if (retry_in_msec == RETRY_IN_MSEC_ASAP) { - _peers_resolve_start(self, peer_data); - return; - } - - peer_data->ep_resolv.next_try_at_nsec = - nm_utils_get_monotonic_timestamp_nsec() + (retry_in_msec * NM_UTILS_NSEC_PER_MSEC); - _peers_resolve_retry_reschedule(self, peer_data->ep_resolv.next_try_at_nsec); -} - -static gint64 -_peers_retry_in_msec(PeerData *peer_data, gboolean after_failure) -{ - if (peer_data->ep_resolv.next_try_at_nsec == NEXT_TRY_AT_NSEC_ASAP) { - peer_data->ep_resolv.resolv_fail_count = 0; - return RETRY_IN_MSEC_ASAP; - } - - if (after_failure) { - if (peer_data->ep_resolv.resolv_fail_count < G_MAXUINT) - peer_data->ep_resolv.resolv_fail_count++; - } else - peer_data->ep_resolv.resolv_fail_count = 0; - - if (!after_failure) - return RETRY_IN_MSEC_MAX; - - if (peer_data->ep_resolv.resolv_fail_count > 20) - return RETRY_IN_MSEC_MAX; - - /* double the retry-time, starting with one second. */ - return NM_MIN(RETRY_IN_MSEC_MAX, (1u << peer_data->ep_resolv.resolv_fail_count) * 500); -} - -static void -_peers_resolve_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - NMDeviceWireGuard *self; - PeerData * peer_data; - gs_free_error GError *resolv_error = NULL; - GList * list; - gboolean changed = FALSE; - NMSockAddrUnion sockaddr; - gint64 retry_in_msec; - char s_sockaddr[100]; - char s_retry[100]; - - list = g_resolver_lookup_by_name_finish(G_RESOLVER(source_object), res, &resolv_error); - - if (nm_utils_error_is_cancelled(resolv_error)) - return; - - peer_data = user_data; - self = peer_data->self; - - g_clear_object(&peer_data->ep_resolv.cancellable); - - nm_assert((!resolv_error) != (!list)); - -#define _retry_in_msec_to_string(retry_in_msec, s_retry) \ - ({ \ - gint64 _retry_in_msec = (retry_in_msec); \ - \ - _retry_in_msec == RETRY_IN_MSEC_ASAP \ - ? "right away" \ - : nm_sprintf_buf(s_retry, "in %" G_GINT64_FORMAT " msec", _retry_in_msec); \ - }) - - if (resolv_error - && !g_error_matches(resolv_error, G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND)) { - retry_in_msec = _peers_retry_in_msec(peer_data, TRUE); - - _LOGT(LOGD_DEVICE, - "wireguard-peer[%s]: failure to resolve endpoint \"%s\": %s (retry %s)", - nm_wireguard_peer_get_public_key(peer_data->peer), - nm_wireguard_peer_get_endpoint(peer_data->peer), - resolv_error->message, - _retry_in_msec_to_string(retry_in_msec, s_retry)); - - _peers_resolve_retry_reschedule_for_peer(self, peer_data, retry_in_msec); - return; - } - - sockaddr = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC; - - if (!resolv_error) { - GList *iter; - - for (iter = list; iter; iter = iter->next) { - GInetAddress *a = iter->data; - GSocketFamily f = g_inet_address_get_family(a); - - if (f == G_SOCKET_FAMILY_IPV4) { - nm_assert(g_inet_address_get_native_size(a) == sizeof(struct in_addr)); - sockaddr.in = (struct sockaddr_in){ - .sin_family = AF_INET, - .sin_port = htons(nm_sock_addr_endpoint_get_port( - _nm_wireguard_peer_get_endpoint(peer_data->peer))), - }; - memcpy(&sockaddr.in.sin_addr, g_inet_address_to_bytes(a), sizeof(struct in_addr)); - break; - } - if (f == G_SOCKET_FAMILY_IPV6) { - nm_assert(g_inet_address_get_native_size(a) == sizeof(struct in6_addr)); - sockaddr.in6 = (struct sockaddr_in6){ - .sin6_family = AF_INET6, - .sin6_port = htons(nm_sock_addr_endpoint_get_port( - _nm_wireguard_peer_get_endpoint(peer_data->peer))), - .sin6_scope_id = 0, - .sin6_flowinfo = 0, - }; - memcpy(&sockaddr.in6.sin6_addr, - g_inet_address_to_bytes(a), - sizeof(struct in6_addr)); - break; - } - } - - g_list_free_full(list, g_object_unref); - } - - if (sockaddr.sa.sa_family == AF_UNSPEC) { - /* we failed to resolve the name. There is no need to reset the previous - * sockaddr. Either it was already AF_UNSPEC, or we had a good name - * from resolving before. In that case, we don't want to throw away - * a possibly good IP address, since WireGuard supports automatic roaming - * anyway. Either the IP address is still good (and we would wrongly - * reject it), or it isn't -- in which case it does not hurt much. */ - } else { - if (nm_sock_addr_union_cmp(&peer_data->ep_resolv.sockaddr, &sockaddr) != 0) - changed = TRUE; - peer_data->ep_resolv.sockaddr = sockaddr; - } - - if (resolv_error || peer_data->ep_resolv.sockaddr.sa.sa_family == AF_UNSPEC) { - /* while it technically did not fail, something is probably odd. Retry frequently to - * resolve the name, like we would do for normal failures. */ - retry_in_msec = _peers_retry_in_msec(peer_data, TRUE); - _LOGT(LOGD_DEVICE, - "wireguard-peer[%s]: no %sresults for endpoint \"%s\" (retry %s)", - nm_wireguard_peer_get_public_key(peer_data->peer), - resolv_error ? "" : "suitable ", - nm_wireguard_peer_get_endpoint(peer_data->peer), - _retry_in_msec_to_string(retry_in_msec, s_retry)); - } else { - retry_in_msec = _peers_retry_in_msec(peer_data, FALSE); - _LOGT(LOGD_DEVICE, - "wireguard-peer[%s]: endpoint \"%s\" resolved to %s (retry %s)", - nm_wireguard_peer_get_public_key(peer_data->peer), - nm_wireguard_peer_get_endpoint(peer_data->peer), - nm_sock_addr_union_to_string(&peer_data->ep_resolv.sockaddr, - s_sockaddr, - sizeof(s_sockaddr)), - _retry_in_msec_to_string(retry_in_msec, s_retry)); - } - - _peers_resolve_retry_reschedule_for_peer(self, peer_data, retry_in_msec); - - if (changed) { - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - - /* schedule the job in the background, to give multiple resolve events time - * to complete. */ - nm_clear_g_source(&priv->link_config_delayed_id); - priv->link_config_delayed_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE + 1, - link_config_delayed_resolver_cb, - self, - NULL); - } -} - -static void -_peers_resolve_start(NMDeviceWireGuard *self, PeerData *peer_data) -{ - gs_unref_object GResolver *resolver = NULL; - const char * host; - - resolver = g_resolver_get_default(); - - nm_assert(!peer_data->ep_resolv.cancellable); - - peer_data->ep_resolv.cancellable = g_cancellable_new(); - - /* set a special next-try timestamp. It is positive, and indicates - * that we are in the process of trying. - * This timestamp however already lies in the past, but that is correct, - * because we are currently in the process of trying. We will determine - * a next-try timestamp once the try completes. */ - peer_data->ep_resolv.next_try_at_nsec = NEXT_TRY_AT_NSEC_PAST; - - host = nm_sock_addr_endpoint_get_host(_nm_wireguard_peer_get_endpoint(peer_data->peer)); - - g_resolver_lookup_by_name_async(resolver, - host, - peer_data->ep_resolv.cancellable, - _peers_resolve_cb, - peer_data); - - _LOGT(LOGD_DEVICE, - "wireguard-peer[%s]: resolving name \"%s\" for endpoint \"%s\"...", - nm_wireguard_peer_get_public_key(peer_data->peer), - host, - nm_wireguard_peer_get_endpoint(peer_data->peer)); -} - -static void -_peers_resolve_reresolve_all(NMDeviceWireGuard *self) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - PeerData * peer_data; - - c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) { - if (peer_data->ep_resolv.cancellable) { - /* remember to retry when the currently ongoing request completes. */ - peer_data->ep_resolv.next_try_at_nsec = NEXT_TRY_AT_NSEC_ASAP; - } else if (peer_data->ep_resolv.next_try_at_nsec <= 0) { - /* this peer does not require resolving the name. Skip it. */ - } else { - /* we have a next-try scheduled. Restart right away. */ - peer_data->ep_resolv.resolv_fail_count = 0; - _peers_resolve_start(self, peer_data); - } - } -} - -static gboolean -_peers_update(NMDeviceWireGuard *self, - PeerData * peer_data, - NMWireGuardPeer * peer, - gboolean force_update) -{ - nm_auto_unref_wgpeer NMWireGuardPeer *old_peer = NULL; - NMSockAddrEndpoint * old_endpoint; - NMSockAddrEndpoint * endpoint; - gboolean endpoint_changed = FALSE; - gboolean changed; - NMSockAddrUnion sockaddr; - gboolean sockaddr_fixed; - char sockaddr_sbuf[100]; - - nm_assert(peer); - nm_assert(nm_wireguard_peer_is_sealed(peer)); - - if (peer == peer_data->peer && !force_update) - return FALSE; - - changed = (nm_wireguard_peer_cmp(peer, peer_data->peer, NM_SETTING_COMPARE_FLAG_EXACT) != 0); - - old_peer = peer_data->peer; - peer_data->peer = nm_wireguard_peer_ref(peer); - - old_endpoint = old_peer ? _nm_wireguard_peer_get_endpoint(old_peer) : NULL; - endpoint = peer ? _nm_wireguard_peer_get_endpoint(peer) : NULL; - - endpoint_changed = (endpoint != old_endpoint - && (!old_endpoint || !endpoint - || !nm_streq(nm_sock_addr_endpoint_get_endpoint(old_endpoint), - nm_sock_addr_endpoint_get_endpoint(endpoint)))); - - if (!force_update && !endpoint_changed) { - /* nothing to do. */ - return changed; - } - - sockaddr = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC; - sockaddr_fixed = TRUE; - if (endpoint && nm_sock_addr_endpoint_get_host(endpoint)) { - if (!nm_sock_addr_endpoint_get_fixed_sockaddr(endpoint, &sockaddr)) { - /* we have an endpoint, but it's not a static IP address. We need to resolve - * the names. */ - sockaddr_fixed = FALSE; - } - } - - if (nm_sock_addr_union_cmp(&peer_data->ep_resolv.sockaddr, &sockaddr) != 0) - changed = TRUE; - - nm_clear_g_cancellable(&peer_data->ep_resolv.cancellable); - - peer_data->ep_resolv = (PeerEndpointResolveData){ - .sockaddr = sockaddr, - .resolv_fail_count = 0, - .cancellable = NULL, - .next_try_at_nsec = 0, - }; - - if (!endpoint) { - _LOGT(LOGD_DEVICE, - "wireguard-peer[%s]: no endpoint configured", - nm_wireguard_peer_get_public_key(peer_data->peer)); - } else if (!nm_sock_addr_endpoint_get_host(endpoint)) { - _LOGT(LOGD_DEVICE, - "wireguard-peer[%s]: invalid endpoint \"%s\"", - nm_wireguard_peer_get_public_key(peer_data->peer), - nm_sock_addr_endpoint_get_endpoint(endpoint)); - } else if (sockaddr_fixed) { - _LOGT(LOGD_DEVICE, - "wireguard-peer[%s]: fixed endpoint \"%s\" (%s)", - nm_wireguard_peer_get_public_key(peer_data->peer), - nm_sock_addr_endpoint_get_endpoint(endpoint), - nm_sock_addr_union_to_string(&peer_data->ep_resolv.sockaddr, - sockaddr_sbuf, - sizeof(sockaddr_sbuf))); - } else - _peers_resolve_start(self, peer_data); - - return changed; -} - -static void -_peers_remove_all(NMDeviceWireGuardPrivate *priv) -{ - PeerData *peer_data; - - while ((peer_data = c_list_first_entry(&priv->lst_peers_head, PeerData, lst_peers))) - _peers_remove(priv, peer_data); -} - -static void -_peers_update_all(NMDeviceWireGuard *self, NMSettingWireGuard *s_wg, gboolean *out_peers_removed) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - PeerData * peer_data_safe; - PeerData * peer_data; - guint i, n; - gboolean peers_removed = FALSE; - - c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) - peer_data->dirty_update_all = TRUE; - - n = nm_setting_wireguard_get_peers_len(s_wg); - for (i = 0; i < n; i++) { - NMWireGuardPeer *peer = nm_setting_wireguard_get_peer(s_wg, i); - gboolean added = FALSE; - - peer_data = _peers_find(priv, peer); - if (!peer_data) { - peer_data = _peers_add(self, peer); - added = TRUE; - } - _peers_update(self, peer_data, peer, added); - peer_data->dirty_update_all = FALSE; - } - - c_list_for_each_entry_safe (peer_data, peer_data_safe, &priv->lst_peers_head, lst_peers) { - if (peer_data->dirty_update_all) { - _peers_remove(priv, peer_data); - peers_removed = TRUE; - } - } - - NM_SET_OUT(out_peers_removed, peers_removed); -} - -static void -_peers_get_platform_list(NMDeviceWireGuardPrivate * priv, - LinkConfigMode config_mode, - NMPWireGuardPeer ** out_peers, - NMPlatformWireGuardChangePeerFlags **out_peer_flags, - guint * out_len, - GArray ** out_allowed_ips_data) -{ - gs_free NMPWireGuardPeer *plpeers = NULL; - gs_free NMPlatformWireGuardChangePeerFlags *plpeer_flags = NULL; - gs_unref_array GArray *allowed_ips = NULL; - PeerData * peer_data; - guint i_good; - guint n_aip; - guint i_aip; - guint len; - guint i; - - nm_assert(out_peers && !*out_peers); - nm_assert(out_peer_flags && !*out_peer_flags); - nm_assert(out_len && *out_len == 0); - nm_assert(out_allowed_ips_data && !*out_allowed_ips_data); - - len = g_hash_table_size(priv->peers); - - nm_assert(len == c_list_length(&priv->lst_peers_head)); - - if (len == 0) - return; - - plpeers = g_new0(NMPWireGuardPeer, len); - plpeer_flags = g_new0(NMPlatformWireGuardChangePeerFlags, len); - - i_good = 0; - c_list_for_each_entry (peer_data, &priv->lst_peers_head, lst_peers) { - NMPlatformWireGuardChangePeerFlags *plf = &plpeer_flags[i_good]; - NMPWireGuardPeer * plp = &plpeers[i_good]; - NMSettingSecretFlags psk_secret_flags; - - if (!nm_utils_base64secret_decode(nm_wireguard_peer_get_public_key(peer_data->peer), - sizeof(plp->public_key), - plp->public_key)) - continue; - - *plf = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE; - - plp->persistent_keepalive_interval = - nm_wireguard_peer_get_persistent_keepalive(peer_data->peer); - if (NM_IN_SET(config_mode, LINK_CONFIG_MODE_FULL, LINK_CONFIG_MODE_REAPPLY)) - *plf |= NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_KEEPALIVE_INTERVAL; - - /* if the peer has an endpoint but it is not yet resolved (not ready), - * we still configure it and leave the endpoint unspecified. Later, - * when we can resolve the endpoint, we will update. */ - plp->endpoint = peer_data->ep_resolv.sockaddr; - if (plp->endpoint.sa.sa_family == AF_UNSPEC) { - /* we don't actually ever clear endpoints, if we don't have better information. */ - } else - *plf |= NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ENDPOINT; - - if (NM_IN_SET(config_mode, LINK_CONFIG_MODE_FULL, LINK_CONFIG_MODE_REAPPLY)) { - psk_secret_flags = nm_wireguard_peer_get_preshared_key_flags(peer_data->peer); - if (!NM_FLAGS_HAS(psk_secret_flags, NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) { - if (!nm_utils_base64secret_decode( - nm_wireguard_peer_get_preshared_key(peer_data->peer), - sizeof(plp->preshared_key), - plp->preshared_key) - && config_mode == LINK_CONFIG_MODE_FULL) - goto skip; - } - *plf |= NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY; - } - - if (NM_IN_SET(config_mode, LINK_CONFIG_MODE_FULL, LINK_CONFIG_MODE_REAPPLY) - && ((n_aip = nm_wireguard_peer_get_allowed_ips_len(peer_data->peer)) > 0)) { - if (!allowed_ips) - allowed_ips = g_array_new(FALSE, FALSE, sizeof(NMPWireGuardAllowedIP)); - - *plf |= NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_ALLOWEDIPS - | NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS; - - plp->_construct_idx_start = allowed_ips->len; - for (i_aip = 0; i_aip < n_aip; i_aip++) { - const char *aip; - NMIPAddr addrbin = {}; - int addr_family; - gboolean valid; - int prefix; - - aip = nm_wireguard_peer_get_allowed_ip(peer_data->peer, i_aip, &valid); - if (!valid - || !nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, - aip, - &addr_family, - &addrbin, - &prefix)) { - /* the address is really not expected to be invalid, because then - * the connection would not verify. Anyway, silently skip it. */ - continue; - } - - if (prefix == -1) - prefix = addr_family == AF_INET ? 32 : 128; - - g_array_append_val(allowed_ips, - ((NMPWireGuardAllowedIP){ - .family = addr_family, - .mask = prefix, - .addr = addrbin, - })); - } - plp->_construct_idx_end = allowed_ips->len; - } - - i_good++; - continue; - -skip: - memset(plp, 0, sizeof(*plp)); - } - - if (i_good == 0) - return; - - for (i = 0; i < i_good; i++) { - NMPWireGuardPeer *plp = &plpeers[i]; - guint l; - - if (plp->_construct_idx_end == 0) { - nm_assert(plp->_construct_idx_start == 0); - plp->allowed_ips = NULL; - plp->allowed_ips_len = 0; - } else { - nm_assert(plp->_construct_idx_start < plp->_construct_idx_end); - l = plp->_construct_idx_end - plp->_construct_idx_start; - plp->allowed_ips = - &g_array_index(allowed_ips, NMPWireGuardAllowedIP, plp->_construct_idx_start); - plp->allowed_ips_len = l; - } - } - *out_peers = g_steal_pointer(&plpeers); - *out_peer_flags = g_steal_pointer(&plpeer_flags); - *out_len = i_good; - *out_allowed_ips_data = g_steal_pointer(&allowed_ips); -} - -/*****************************************************************************/ - -static void -update_properties(NMDevice *device) -{ - NMDeviceWireGuard * self; - NMDeviceWireGuardPrivate * priv; - const NMPlatformLink * plink; - const NMPlatformLnkWireGuard *props = NULL; - int ifindex; - - g_return_if_fail(NM_IS_DEVICE_WIREGUARD(device)); - self = NM_DEVICE_WIREGUARD(device); - priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - - ifindex = nm_device_get_ifindex(device); - props = nm_platform_link_get_lnk_wireguard(nm_device_get_platform(device), ifindex, &plink); - if (!props) { - _LOGW(LOGD_PLATFORM, "could not get wireguard properties"); - return; - } - - g_object_freeze_notify(G_OBJECT(device)); - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START \ - { \ - if (priv->lnk_curr.field != props->field) { \ - priv->lnk_curr.field = props->field; \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - -#define CHECK_PROPERTY_CHANGED_ARRAY(field, prop) \ - G_STMT_START \ - { \ - if (memcmp(&priv->lnk_curr.field, &props->field, sizeof(priv->lnk_curr.field)) != 0) { \ - memcpy(&priv->lnk_curr.field, &props->field, sizeof(priv->lnk_curr.field)); \ - _notify(self, prop); \ - } \ - } \ - G_STMT_END - - CHECK_PROPERTY_CHANGED_ARRAY(public_key, PROP_PUBLIC_KEY); - CHECK_PROPERTY_CHANGED(listen_port, PROP_LISTEN_PORT); - CHECK_PROPERTY_CHANGED(fwmark, PROP_FWMARK); - - g_object_thaw_notify(G_OBJECT(device)); -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NM_DEVICE_CLASS(nm_device_wireguard_parent_class)->link_changed(device, pllink); - update_properties(device); -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -/*****************************************************************************/ - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char *iface = nm_device_get_iface(device); - int r; - - g_return_val_if_fail(iface, FALSE); - - r = nm_platform_link_wireguard_add(nm_device_get_platform(device), iface, out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create WireGuard interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -_secrets_cancel(NMDeviceWireGuard *self) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - - if (priv->secrets_call_id) - nm_act_request_cancel_secrets(NULL, priv->secrets_call_id); - nm_assert(!priv->secrets_call_id); -} - -static void -_secrets_cb(NMActRequest * req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * connection, - GError * error, - gpointer user_data) -{ - NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(user_data); - NMDevice * device = NM_DEVICE(self); - NMDeviceWireGuardPrivate *priv; - - g_return_if_fail(NM_IS_DEVICE_WIREGUARD(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - - g_return_if_fail(priv->secrets_call_id == call_id); - - priv->secrets_call_id = NULL; - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - g_return_if_fail(req == nm_device_get_act_request(device)); - g_return_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_NEED_AUTH); - g_return_if_fail(nm_act_request_get_settings_connection(req) == connection); - - if (error) { - _LOGW(LOGD_ETHER, "%s", error->message); - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -_secrets_get_secrets(NMDeviceWireGuard * self, - const char * setting_name, - NMSecretAgentGetSecretsFlags flags, - const char *const * hints) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - NMActRequest * req; - - _secrets_cancel(self); - - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv->secrets_call_id = - nm_act_request_get_secrets(req, TRUE, setting_name, flags, hints, _secrets_cb, self); - g_return_if_fail(priv->secrets_call_id); -} - -static NMActStageReturn -_secrets_handle_auth_or_fail(NMDeviceWireGuard *self, NMActRequest *req, gboolean new_secrets) -{ - NMConnection * applied_connection; - const char * setting_name; - gs_unref_ptrarray GPtrArray *hints = NULL; - - if (!nm_device_auth_retries_try_next(NM_DEVICE(self))) - return NM_ACT_STAGE_RETURN_FAILURE; - - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_NONE); - - nm_active_connection_clear_secrets(NM_ACTIVE_CONNECTION(req)); - - applied_connection = nm_act_request_get_applied_connection(req); - setting_name = nm_connection_need_secrets(applied_connection, &hints); - if (!setting_name) { - _LOGI(LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (hints) - g_ptr_array_add(hints, NULL); - - _secrets_get_secrets(self, - setting_name, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION - | (new_secrets ? NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW : 0), - (hints ? (const char *const *) hints->pdata : NULL)); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static void -_dns_config_changed(NMDnsManager *dns_manager, NMDeviceWireGuard *self) -{ - /* when the DNS configuration changes, we re-resolve the peer addresses. - * - * Possibly, we should also do that when the default-route changes, but it's - * hard to figure out when that happens. */ - _peers_resolve_reresolve_all(self); -} - -/*****************************************************************************/ - -static NMActStageReturn -link_config(NMDeviceWireGuard * self, - const char * reason, - LinkConfigMode config_mode, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceWireGuardPrivate * priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - nm_auto_bzero_secret_ptr NMSecretPtr wg_lnk_clear_private_key = NM_SECRET_PTR_INIT(); - NMSettingWireGuard * s_wg; - NMConnection * connection; - NMActStageReturn ret; - gs_unref_array GArray *allowed_ips_data = NULL; - NMPlatformLnkWireGuard wg_lnk; - gs_free NMPWireGuardPeer *plpeers = NULL; - gs_free NMPlatformWireGuardChangePeerFlags *plpeer_flags = NULL; - guint plpeers_len = 0; - const char * setting_name; - gboolean peers_removed; - NMPlatformWireGuardChangeFlags wg_change_flags; - int ifindex; - int r; - - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NONE); - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - s_wg = NM_SETTING_WIREGUARD(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIREGUARD)); - g_return_val_if_fail(s_wg, NM_ACT_STAGE_RETURN_FAILURE); - - priv->link_config_last_at = nm_utils_get_monotonic_timestamp_nsec(); - - _LOGT(LOGD_DEVICE, - "wireguard link config (%s, %s)...", - reason, - _link_config_mode_to_string(config_mode)); - - _auto_default_route_init(self); - - if (!priv->dns_manager) { - priv->dns_manager = g_object_ref(nm_dns_manager_get()); - g_signal_connect(priv->dns_manager, - NM_DNS_MANAGER_CONFIG_CHANGED, - G_CALLBACK(_dns_config_changed), - self); - } - - if (NM_IN_SET(config_mode, LINK_CONFIG_MODE_FULL) - && (setting_name = nm_connection_need_secrets(connection, NULL))) { - NMActRequest *req = nm_device_get_act_request(NM_DEVICE(self)); - - _LOGD(LOGD_DEVICE, - "Activation: connection '%s' has security, but secrets are required.", - nm_connection_get_id(connection)); - - ret = _secrets_handle_auth_or_fail(self, req, FALSE); - if (ret != NM_ACT_STAGE_RETURN_SUCCESS) { - if (ret != NM_ACT_STAGE_RETURN_POSTPONE) { - nm_assert(ret == NM_ACT_STAGE_RETURN_FAILURE); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - } - return ret; - } - } - - ifindex = nm_device_get_ip_ifindex(NM_DEVICE(self)); - if (ifindex <= 0) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - _peers_update_all(self, s_wg, &peers_removed); - - wg_lnk = (NMPlatformLnkWireGuard){}; - - wg_change_flags = NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE; - - if (NM_IN_SET(config_mode, LINK_CONFIG_MODE_FULL) - || (NM_IN_SET(config_mode, LINK_CONFIG_MODE_REAPPLY) && peers_removed)) - wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS; - - if (NM_IN_SET(config_mode, LINK_CONFIG_MODE_FULL, LINK_CONFIG_MODE_REAPPLY)) { - wg_lnk.listen_port = nm_setting_wireguard_get_listen_port(s_wg); - wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_LISTEN_PORT; - - wg_lnk.fwmark = priv->auto_default_route_fwmark; - wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK; - - if (nm_utils_base64secret_decode(nm_setting_wireguard_get_private_key(s_wg), - sizeof(wg_lnk.private_key), - wg_lnk.private_key)) { - wg_lnk_clear_private_key = NM_SECRET_PTR_ARRAY(wg_lnk.private_key); - wg_change_flags |= NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY; - } else { - if (NM_IN_SET(config_mode, LINK_CONFIG_MODE_FULL)) { - _LOGD(LOGD_DEVICE, "the provided private-key is invalid"); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - return NM_ACT_STAGE_RETURN_FAILURE; - } - } - } - - _peers_get_platform_list(priv, - config_mode, - &plpeers, - &plpeer_flags, - &plpeers_len, - &allowed_ips_data); - - r = nm_platform_link_wireguard_change(nm_device_get_platform(NM_DEVICE(self)), - ifindex, - &wg_lnk, - plpeers, - plpeer_flags, - plpeers_len, - wg_change_flags); - - nm_explicit_bzero(plpeers, sizeof(plpeers[0]) * plpeers_len); - - if (r < 0) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static void -link_config_delayed(NMDeviceWireGuard *self, const char *reason) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - gint64 now; - - priv->link_config_delayed_id = 0; - - if (priv->link_config_last_at != 0) { - now = nm_utils_get_monotonic_timestamp_nsec(); - if (now < priv->link_config_last_at + LINK_CONFIG_RATE_LIMIT_NSEC) { - /* we ratelimit calls to link_config(), because we call this whenever a resolver - * completes. */ - _LOGT(LOGD_DEVICE, "wireguard link config (%s) (postponed)", reason); - priv->link_config_delayed_id = - g_timeout_add(NM_MAX((priv->link_config_last_at + LINK_CONFIG_RATE_LIMIT_NSEC - now) - / NM_UTILS_NSEC_PER_MSEC, - (gint64) 1), - link_config_delayed_ratelimit_cb, - self); - return; - } - } - - link_config(self, reason, LINK_CONFIG_MODE_ENDPOINTS, NULL); -} - -static gboolean -link_config_delayed_ratelimit_cb(gpointer user_data) -{ - link_config_delayed(user_data, "after-ratelimiting"); - return G_SOURCE_REMOVE; -} - -static gboolean -link_config_delayed_resolver_cb(gpointer user_data) -{ - link_config_delayed(user_data, "resolver-update"); - return G_SOURCE_REMOVE; -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceSysIfaceState sys_iface_state; - NMDeviceStateReason failure_reason; - NMActStageReturn ret; - - sys_iface_state = nm_device_sys_iface_state_get(device); - - if (sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_EXTERNAL) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NONE); - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - ret = - link_config(NM_DEVICE_WIREGUARD(device), - "configure", - (sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_ASSUME) ? LINK_CONFIG_MODE_ASSUME - : LINK_CONFIG_MODE_FULL, - &failure_reason); - - if (sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_ASSUME) { - /* this never fails. */ - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, failure_reason); - NM_SET_OUT(out_failure_reason, failure_reason); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return ret; -} - -static NMIPConfig * -_get_dev2_ip_config(NMDeviceWireGuard *self, int addr_family) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - gs_unref_object NMIPConfig *ip_config = NULL; - NMConnection * connection; - NMSettingWireGuard * s_wg; - guint n_peers; - guint i; - int ip_ifindex; - guint32 route_metric; - guint32 route_table_coerced; - gboolean auto_default_route_enabled; - - _auto_default_route_init(self); - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - - s_wg = NM_SETTING_WIREGUARD(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIREGUARD)); - - /* Differences to `wg-quick`. - * - * `wg-quick` supports the "Table" setting with 3 modes: - * - * a1) "off": this is what we do with "peer-routes" disabled. - * - * a2) an explicit routing table. This is our behavior with "peer-routes" on. In this case - * we honor the "ipv4.route-table" and "ipv6.route-table" settings. One difference is that - * `wg-quick` would resolve table names from /etc/iproute2/rt_tables. Our connection profiles - * only contain table numbers, so that conversion from name to table must have happened - * before already. - * - * a3) "auto" (the default). In this case, `wg-quick` would only add the route to the - * main table, if the AllowedIP range is not yet reachable on the link. With "peer-routes" - * enabled, we don't check for that and always add the routes to the main-table - * (with 'ipv4.route-table' and 'ipv6.route-table' set to zero or RT_TABLE_MAIN (254)). - * - * Also, in "auto" mode, `wg-quick` would add special handling for /0 routes and pick - * an empty table to configure policy routing to avoid routing loops. This handling - * of routing-loops via policy routing is not yet done, and requires a separate solution - * from constructing the peer-routes here. - */ - if (!nm_setting_wireguard_get_peer_routes(s_wg)) - return NULL; - - ip_ifindex = nm_device_get_ip_ifindex(NM_DEVICE(self)); - - if (ip_ifindex <= 0) - return NULL; - - route_metric = nm_device_get_route_metric(NM_DEVICE(self), addr_family); - - route_table_coerced = - nm_platform_route_table_coerce(nm_device_get_route_table(NM_DEVICE(self), addr_family)); - - auto_default_route_enabled = (addr_family == AF_INET) ? priv->auto_default_route_enabled_4 - : priv->auto_default_route_enabled_6; - - n_peers = nm_setting_wireguard_get_peers_len(s_wg); - for (i = 0; i < n_peers; i++) { - NMWireGuardPeer *peer = nm_setting_wireguard_get_peer(s_wg, i); - guint n_aips; - guint j; - - n_aips = nm_wireguard_peer_get_allowed_ips_len(peer); - for (j = 0; j < n_aips; j++) { - NMPlatformIPXRoute rt; - NMIPAddr addrbin; - const char * aip; - gboolean valid; - int prefix; - guint32 rtable_coerced; - - aip = nm_wireguard_peer_get_allowed_ip(peer, j, &valid); - - if (!valid - || !nm_utils_parse_inaddr_prefix_bin(addr_family, aip, NULL, &addrbin, &prefix)) - continue; - - if (prefix < 0) - prefix = (addr_family == AF_INET) ? 32 : 128; - - if (prefix == 0) { - NMSettingIPConfig *s_ip; - - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - if (nm_setting_ip_config_get_never_default(s_ip)) - continue; - } - - if (!ip_config) { - ip_config = nm_device_ip_config_new(NM_DEVICE(self), addr_family); - nm_ip_config_set_config_flags(ip_config, - NM_IP_CONFIG_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES, - 0); - } - - nm_utils_ipx_address_clear_host_address(addr_family, &addrbin, NULL, prefix); - - rtable_coerced = route_table_coerced; - - if (prefix == 0 && auto_default_route_enabled) { - /* In auto-default-route mode, we place the default route in a table that - * has the same number as the fwmark. wg-quick does that too. If you don't - * like that, configure the rules and the default-route explicitly in the - * connection profile. */ - rtable_coerced = nm_platform_route_table_coerce(priv->auto_default_route_fwmark); - } - - if (addr_family == AF_INET) { - rt.r4 = (NMPlatformIP4Route){ - .network = addrbin.addr4, - .plen = prefix, - .ifindex = ip_ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .table_coerced = rtable_coerced, - .metric = route_metric, - }; - } else { - rt.r6 = (NMPlatformIP6Route){ - .network = addrbin.addr6, - .plen = prefix, - .ifindex = ip_ifindex, - .rt_source = NM_IP_CONFIG_SOURCE_USER, - .table_coerced = rtable_coerced, - .metric = route_metric, - }; - } - - nm_ip_config_add_route(ip_config, &rt.rx, NULL); - } - } - - return g_steal_pointer(&ip_config); -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - gs_unref_object NMIPConfig *ip_config = NULL; - - ip_config = _get_dev2_ip_config(NM_DEVICE_WIREGUARD(device), addr_family); - - nm_device_set_dev2_ip_config(device, addr_family, ip_config); - - return NM_DEVICE_CLASS(nm_device_wireguard_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static guint32 -get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - /* When "MTU" for `wg-quick up` is unset, it calls `ip route get` for - * each configured endpoint, to determine the suitable MTU how to reach - * each endpoint. - * For `wg-quick` this works very well, because whenever the script runs it - * determines the best setting at that point in time. It's simply not concerned - * with what happens later (and it's not around anyway). - * - * NetworkManager sticks around, so the right MTU would need to be re-determined - * whenever anything relevant changes. Which basically means, to re-evaluate whenever - * something related to addresses or routing changes (which happens all the time). - * - * The correct MTU indeed depends on the MTU setting of other interfaces (or routes). - * But it's still odd, that activating/deactivating a seemingly unrelated interface - * would trigger an MTU change. It's odd to explain/document and odd to implemented - * -- despite this being the reality. - * - * For now, only support configuring an explicit MTU, or leave the setting untouched. - * The same limitation also applies to other "ip-tunnel" types, where we could use - * similar smarts for autodetecting the MTU. - */ - return nm_device_get_configured_mtu_from_connection(device, - NM_TYPE_SETTING_WIREGUARD, - out_source); -} - -static void -_device_cleanup(NMDeviceWireGuard *self) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - - _peers_remove_all(priv); - - _secrets_cancel(self); - - priv->auto_default_route_initialized = FALSE; - priv->auto_default_route_priority_initialized = FALSE; -} - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - if (new_state <= NM_DEVICE_STATE_ACTIVATED) - return; - - _device_cleanup(NM_DEVICE_WIREGUARD(device)); -} - -/*****************************************************************************/ - -static gboolean -can_reapply_change(NMDevice * device, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error) -{ - if (nm_streq(setting_name, NM_SETTING_WIREGUARD_SETTING_NAME)) { - /* Most, but not all WireGuard settings can be reapplied. Whitelist. - * - * MTU cannot be reapplied. */ - return nm_device_hash_check_invalid_keys(diffs, - NM_SETTING_WIREGUARD_SETTING_NAME, - error, - NM_SETTING_WIREGUARD_FWMARK, - NM_SETTING_WIREGUARD_IP4_AUTO_DEFAULT_ROUTE, - NM_SETTING_WIREGUARD_IP6_AUTO_DEFAULT_ROUTE, - NM_SETTING_WIREGUARD_LISTEN_PORT, - NM_SETTING_WIREGUARD_PEERS, - NM_SETTING_WIREGUARD_PEER_ROUTES, - NM_SETTING_WIREGUARD_PRIVATE_KEY, - NM_SETTING_WIREGUARD_PRIVATE_KEY_FLAGS); - } - - return NM_DEVICE_CLASS(nm_device_wireguard_parent_class) - ->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); -} - -static void -reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_new) -{ - NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(device); - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - gs_unref_object NMIPConfig *ip4_config = NULL; - gs_unref_object NMIPConfig *ip6_config = NULL; - NMDeviceState state = nm_device_get_state(device); - - NM_DEVICE_CLASS(nm_device_wireguard_parent_class)->reapply_connection(device, con_old, con_new); - - if (state >= NM_DEVICE_STATE_CONFIG) { - priv->auto_default_route_refresh = TRUE; - link_config(NM_DEVICE_WIREGUARD(device), "reapply", LINK_CONFIG_MODE_REAPPLY, NULL); - } - - if (state >= NM_DEVICE_STATE_IP_CONFIG) { - ip4_config = _get_dev2_ip_config(self, AF_INET); - ip6_config = _get_dev2_ip_config(self, AF_INET6); - - nm_device_set_dev2_ip_config(device, AF_INET, ip4_config); - nm_device_set_dev2_ip_config(device, AF_INET6, ip6_config); - } -} - -/*****************************************************************************/ - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(device); - NMSettingWireGuard * s_wg = - NM_SETTING_WIREGUARD(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIREGUARD)); - const NMPObject * obj_wg; - const NMPObjectLnkWireGuard *olnk_wg; - guint i; - - if (!s_wg) { - s_wg = NM_SETTING_WIREGUARD(nm_setting_wireguard_new()); - nm_connection_add_setting(connection, NM_SETTING(s_wg)); - } - - g_object_set(s_wg, - NM_SETTING_WIREGUARD_FWMARK, - (guint) priv->lnk_curr.fwmark, - NM_SETTING_WIREGUARD_LISTEN_PORT, - (guint) priv->lnk_curr.listen_port, - NULL); - - obj_wg = NMP_OBJECT_UP_CAST(nm_platform_link_get_lnk_wireguard(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - NULL)); - if (!obj_wg) - return; - - olnk_wg = &obj_wg->_lnk_wireguard; - - for (i = 0; i < olnk_wg->peers_len; i++) { - nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; - const NMPWireGuardPeer * ppeer = &olnk_wg->peers[i]; - - peer = nm_wireguard_peer_new(); - - _nm_wireguard_peer_set_public_key_bin(peer, ppeer->public_key); - - nm_setting_wireguard_append_peer(s_wg, peer); - } -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(object); - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_PUBLIC_KEY: - g_value_take_variant(value, - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, - priv->lnk_curr.public_key, - sizeof(priv->lnk_curr.public_key), - 1)); - break; - case PROP_LISTEN_PORT: - g_value_set_uint(value, priv->lnk_curr.listen_port); - break; - case PROP_FWMARK: - g_value_set_uint(value, priv->lnk_curr.fwmark); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_wireguard_init(NMDeviceWireGuard *self) -{ - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - - c_list_init(&priv->lst_peers_head); - priv->peers = g_hash_table_new(_peer_data_hash, _peer_data_equal); -} - -static void -dispose(GObject *object) -{ - NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD(object); - - _device_cleanup(self); - - G_OBJECT_CLASS(nm_device_wireguard_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMDeviceWireGuard * self = NM_DEVICE_WIREGUARD(object); - NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); - - nm_explicit_bzero(priv->lnk_curr.private_key, sizeof(priv->lnk_curr.private_key)); - - if (priv->dns_manager) { - g_signal_handlers_disconnect_by_func(priv->dns_manager, _dns_config_changed, self); - g_object_unref(priv->dns_manager); - } - - g_hash_table_destroy(priv->peers); - - G_OBJECT_CLASS(nm_device_wireguard_parent_class)->finalize(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_wireguard = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_WIREGUARD, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("PublicKey", - "ay", - NM_DEVICE_WIREGUARD_PUBLIC_KEY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ListenPort", - "q", - NM_DEVICE_WIREGUARD_LISTEN_PORT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FwMark", - "u", - NM_DEVICE_WIREGUARD_FWMARK), ), ), -}; - -static void -nm_device_wireguard_class_init(NMDeviceWireGuardClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_wireguard); - - device_class->connection_type_supported = NM_SETTING_WIREGUARD_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_WIREGUARD_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_WIREGUARD); - - device_class->state_changed = device_state_changed; - device_class->create_and_realize = create_and_realize; - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage2_config_also_for_external_or_assume = TRUE; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->link_changed = link_changed; - device_class->update_connection = update_connection; - device_class->can_reapply_change = can_reapply_change; - device_class->reapply_connection = reapply_connection; - device_class->get_configured_mtu = get_configured_mtu; - device_class->get_extra_rules = get_extra_rules; - device_class->coerce_route_table = coerce_route_table; - - obj_properties[PROP_PUBLIC_KEY] = - g_param_spec_variant(NM_DEVICE_WIREGUARD_PUBLIC_KEY, - "", - "", - G_VARIANT_TYPE("ay"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LISTEN_PORT] = g_param_spec_uint(NM_DEVICE_WIREGUARD_LISTEN_PORT, - "", - "", - 0, - G_MAXUINT16, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_FWMARK] = g_param_spec_uint(NM_DEVICE_WIREGUARD_FWMARK, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*************************************************************/ - -#define NM_TYPE_WIREGUARD_DEVICE_FACTORY (nm_wireguard_device_factory_get_type()) -#define NM_WIREGUARD_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIREGUARD_DEVICE_FACTORY, NMWireGuardDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_WIREGUARD, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "WireGuard", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_WIREGUARD, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_WIREGUARD, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - WIREGUARD, - WireGuard, - wireguard, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_WIREGUARD) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_WIREGUARD_SETTING_NAME), - factory_class->create_device = create_device;) diff --git a/src/devices/nm-device-wireguard.h b/src/devices/nm-device-wireguard.h deleted file mode 100644 index f562f356..00000000 --- a/src/devices/nm-device-wireguard.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Javier Arteaga <jarteaga@jbeta.is> - */ - -#ifndef __NM_DEVICE_WIREGUARD_H__ -#define __NM_DEVICE_WIREGUARD_H__ - -#include "nm-device.h" - -#define NM_TYPE_DEVICE_WIREGUARD (nm_device_wireguard_get_type()) -#define NM_DEVICE_WIREGUARD(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuard)) -#define NM_DEVICE_WIREGUARD_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuardClass)) -#define NM_IS_DEVICE_WIREGUARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIREGUARD)) -#define NM_IS_DEVICE_WIREGUARD_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_WIREGUARD)) -#define NM_DEVICE_WIREGUARD_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_WIREGUARD, NMDeviceWireGuardClass)) - -#define NM_DEVICE_WIREGUARD_PUBLIC_KEY "public-key" -#define NM_DEVICE_WIREGUARD_LISTEN_PORT "listen-port" -#define NM_DEVICE_WIREGUARD_FWMARK "fwmark" - -typedef struct _NMDeviceWireGuard NMDeviceWireGuard; -typedef struct _NMDeviceWireGuardClass NMDeviceWireGuardClass; - -GType nm_device_wireguard_get_type(void); - -#endif /* __NM_DEVICE_WIREGUARD_H__ */ diff --git a/src/devices/nm-device-wpan.c b/src/devices/nm-device-wpan.c deleted file mode 100644 index 195603dc..00000000 --- a/src/devices/nm-device-wpan.c +++ /dev/null @@ -1,257 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk> - */ - -#include "nm-default.h" - -#include "nm-manager.h" -#include "nm-device-wpan.h" - -#include <stdlib.h> -#include <sys/types.h> -#include <linux/if.h> - -#include "nm-act-request.h" -#include "nm-device-private.h" -#include "nm-ip4-config.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-setting-wpan.h" -#include "nm-core-internal.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceWpan); - -/*****************************************************************************/ - -struct _NMDeviceWpan { - NMDevice parent; -}; - -struct _NMDeviceWpanClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceWpan, nm_device_wpan, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingWpan *s_wpan; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_WPAN_SETTING_NAME, - existing_connections, - NULL, - _("WPAN connection"), - NULL, - NULL, - TRUE); - - s_wpan = NM_SETTING_WPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_WPAN)); - if (!s_wpan) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wpan' setting is required."); - return FALSE; - } - - return TRUE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMSettingWpan *s_wpan = - NM_SETTING_WPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_WPAN)); - - if (!s_wpan) { - s_wpan = (NMSettingWpan *) nm_setting_wpan_new(); - nm_connection_add_setting(connection, (NMSetting *) s_wpan); - } -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingWpan *s_wpan; - const char * mac, *hw_addr; - - if (!NM_DEVICE_CLASS(nm_device_wpan_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_wpan = NM_SETTING_WPAN(nm_connection_get_setting(connection, NM_TYPE_SETTING_WPAN)); - - mac = nm_setting_wpan_get_mac_address(s_wpan); - if (mac) { - hw_addr = nm_device_get_hw_address(device); - if (!nm_utils_hwaddr_matches(mac, -1, hw_addr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "MAC address mismatches"); - return FALSE; - } - } - - return TRUE; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceWpan * self = NM_DEVICE_WPAN(device); - NMSettingWpan * s_wpan; - NMPlatform * platform; - guint16 pan_id; - guint16 short_address; - gint16 page, channel; - int ifindex; - const guint8 * hwaddr; - gsize hwaddr_len = 0; - const NMPlatformLink *lowpan_plink; - NMDevice * lowpan_device = NULL; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - - platform = nm_device_get_platform(device); - nm_assert(NM_IS_PLATFORM(platform)); - - ifindex = nm_device_get_ifindex(device); - - g_return_val_if_fail(ifindex > 0, NM_ACT_STAGE_RETURN_FAILURE); - - s_wpan = nm_device_get_applied_setting(device, NM_TYPE_SETTING_WPAN); - - g_return_val_if_fail(s_wpan, NM_ACT_STAGE_RETURN_FAILURE); - - hwaddr = nm_platform_link_get_address(platform, ifindex, &hwaddr_len); - - if (!hwaddr) { - *out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - /* As of kernel 4.16, the 6LoWPAN devices layered on top of WPANs - * need to be DOWN as well as the WPAN device itself in order to - * modify the WPAN properties. */ - lowpan_plink = - nm_platform_link_get_by_address(platform, NM_LINK_TYPE_6LOWPAN, hwaddr, hwaddr_len); - if (lowpan_plink && NM_FLAGS_HAS(lowpan_plink->n_ifi_flags, IFF_UP)) { - lowpan_device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, lowpan_plink->ifindex); - } - - if (lowpan_device) - nm_device_take_down(lowpan_device, TRUE); - - nm_device_take_down(device, TRUE); - - pan_id = nm_setting_wpan_get_pan_id(s_wpan); - if (pan_id != G_MAXUINT16) { - if (!nm_platform_wpan_set_pan_id(platform, ifindex, pan_id)) { - _LOGW(LOGD_DEVICE, "unable to set the PAN ID"); - goto out; - } - } - - short_address = nm_setting_wpan_get_short_address(s_wpan); - if (short_address != G_MAXUINT16) { - if (!nm_platform_wpan_set_short_addr(platform, ifindex, short_address)) { - _LOGW(LOGD_DEVICE, "unable to set the short address"); - goto out; - } - } - - channel = nm_setting_wpan_get_channel(s_wpan); - if (channel != NM_SETTING_WPAN_CHANNEL_DEFAULT) { - page = nm_setting_wpan_get_page(s_wpan); - if (!nm_platform_wpan_set_channel(platform, ifindex, page, channel)) { - _LOGW(LOGD_DEVICE, "unable to set the channel"); - goto out; - } - } - - ret = NM_ACT_STAGE_RETURN_SUCCESS; - -out: - nm_device_bring_up(device, TRUE, NULL); - - if (lowpan_device) - nm_device_bring_up(lowpan_device, TRUE, NULL); - - return ret; -} - -/*****************************************************************************/ - -static void -nm_device_wpan_init(NMDeviceWpan *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_wpan = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_WPAN, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), -}; - -static void -nm_device_wpan_class_init(NMDeviceWpanClass *klass) -{ - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_wpan); - - device_class->connection_type_supported = NM_SETTING_WPAN_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_WPAN_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_WPAN); - - device_class->complete_connection = complete_connection; - device_class->check_connection_compatible = check_connection_compatible; - device_class->update_connection = update_connection; - device_class->act_stage1_prepare = act_stage1_prepare; -} - -/*****************************************************************************/ - -#define NM_TYPE_WPAN_DEVICE_FACTORY (nm_wpan_device_factory_get_type()) -#define NM_WPAN_DEVICE_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WPAN_DEVICE_FACTORY, NMWpanDeviceFactory)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_WPAN, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "WPAN", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_WPAN, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_WPAN, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL( - WPAN, - Wpan, - wpan, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_WPAN) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_WPAN_SETTING_NAME), - factory_class->create_device = create_device;); diff --git a/src/devices/nm-device-wpan.h b/src/devices/nm-device-wpan.h deleted file mode 100644 index 4bc4f243..00000000 --- a/src/devices/nm-device-wpan.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2018 Lubomir Rintel <lkundrak@v3.sk> - */ - -#ifndef __NETWORKMANAGER_DEVICE_WPAN_H__ -#define __NETWORKMANAGER_DEVICE_WPAN_H__ - -#define NM_TYPE_DEVICE_WPAN (nm_device_wpan_get_type()) -#define NM_DEVICE_WPAN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WPAN, NMDeviceWpan)) -#define NM_DEVICE_WPAN_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WPAN, NMDeviceWpanClass)) -#define NM_IS_DEVICE_WPAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WPAN)) -#define NM_IS_DEVICE_WPAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_WPAN)) -#define NM_DEVICE_WPAN_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_WPAN, NMDeviceWpanClass)) - -typedef struct _NMDeviceWpan NMDeviceWpan; -typedef struct _NMDeviceWpanClass NMDeviceWpanClass; - -GType nm_device_wpan_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_WPAN_H__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c deleted file mode 100644 index 0be05f23..00000000 --- a/src/devices/nm-device.c +++ /dev/null @@ -1,18778 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2018 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "nm-default.h" - -#include "nm-device.h" - -#include <netinet/in.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <signal.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <arpa/inet.h> -#include <fcntl.h> -#include <linux/if_addr.h> -#include <linux/if_arp.h> -#include <linux/rtnetlink.h> - -#include "nm-std-aux/unaligned.h" -#include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-glib-aux/nm-random-utils.h" -#include "systemd/nm-sd-utils-shared.h" - -#include "nm-libnm-core-intern/nm-ethtool-utils.h" -#include "nm-libnm-core-intern/nm-common-macros.h" -#include "nm-device-private.h" -#include "nm-l3cfg.h" -#include "nm-l3-config-data.h" -#include "NetworkManagerUtils.h" -#include "nm-manager.h" -#include "platform/nm-platform.h" -#include "platform/nm-platform-utils.h" -#include "platform/nmp-object.h" -#include "platform/nmp-rules-manager.h" -#include "ndisc/nm-ndisc.h" -#include "ndisc/nm-lndp-ndisc.h" -#include "dhcp/nm-dhcp-manager.h" -#include "dhcp/nm-dhcp-utils.h" -#include "nm-act-request.h" -#include "nm-proxy-config.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" -#include "nm-pacrunner-manager.h" -#include "dnsmasq/nm-dnsmasq-manager.h" -#include "nm-dhcp-config.h" -#include "nm-rfkill-manager.h" -#include "nm-firewall-manager.h" -#include "settings/nm-settings-connection.h" -#include "settings/nm-settings.h" -#include "nm-setting-ethtool.h" -#include "nm-setting-user.h" -#include "nm-auth-utils.h" -#include "nm-keep-alive.h" -#include "nm-netns.h" -#include "nm-dispatcher.h" -#include "nm-config.h" -#include "c-list/src/c-list.h" -#include "dns/nm-dns-manager.h" -#include "nm-acd-manager.h" -#include "nm-core-internal.h" -#include "systemd/nm-sd.h" -#include "nm-lldp-listener.h" -#include "nm-audit-manager.h" -#include "nm-connectivity.h" -#include "nm-dbus-interface.h" - -#include "nm-device-generic.h" -#include "nm-device-vlan.h" -#include "nm-device-vrf.h" -#include "nm-device-wireguard.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDevice); - -/*****************************************************************************/ - -#define DEFAULT_AUTOCONNECT TRUE - -static guint32 -dhcp_grace_period_from_timeout(guint32 timeout) -{ -#define DHCP_GRACE_PERIOD_MULTIPLIER 2U - - nm_assert(timeout > 0); - nm_assert(timeout < G_MAXINT32); - - if (timeout < G_MAXUINT32 / DHCP_GRACE_PERIOD_MULTIPLIER) - return timeout * DHCP_GRACE_PERIOD_MULTIPLIER; - - return G_MAXUINT32; -} - -#define CARRIER_WAIT_TIME_MS 6000 -#define CARRIER_WAIT_TIME_AFTER_MTU_MS 10000 - -#define NM_DEVICE_AUTH_RETRIES_UNSET -1 -#define NM_DEVICE_AUTH_RETRIES_INFINITY -2 -#define NM_DEVICE_AUTH_RETRIES_DEFAULT 3 - -/*****************************************************************************/ - -typedef void (*ActivationHandleFunc)(NMDevice *self); - -typedef enum { - CLEANUP_TYPE_KEEP, - CLEANUP_TYPE_REMOVED, - CLEANUP_TYPE_DECONFIGURE, -} CleanupType; - -typedef struct { - CList lst_slave; - NMDevice *slave; - gulong watch_id; - bool slave_is_enslaved; - bool configure; -} SlaveInfo; - -typedef struct { - NMDevice *device; - guint idle_add_id; - int ifindex; -} DeleteOnDeactivateData; - -typedef struct { - NMDevice * device; - GCancellable * cancellable; - NMPlatformAsyncCallback callback; - gpointer callback_data; - guint num_vfs; - NMTernary autoprobe; -} SriovOp; - -typedef void (*AcdCallback)(NMDevice *, NMIP4Config **, gboolean); - -typedef enum { - /* The various NML3ConfigData types that we track explicitly. Note that - * their relative order matters: higher numbers in this enum means more - * important (and during merge overwrites other settings). */ - L3_CONFIG_DATA_TYPE_LL_4, - L3_CONFIG_DATA_TYPE_AC_6, - L3_CONFIG_DATA_TYPE_DHCP_4, - L3_CONFIG_DATA_TYPE_DHCP_6, - L3_CONFIG_DATA_TYPE_DEV_4, - L3_CONFIG_DATA_TYPE_DEV_6, - L3_CONFIG_DATA_TYPE_SETTING, - _L3_CONFIG_DATA_TYPE_NUM, - _L3_CONFIG_DATA_TYPE_NONE, -} L3ConfigDataType; - -typedef struct { - AcdCallback callback; - NMDevice * device; - NMIP4Config **configs; -} AcdData; - -typedef enum { - HW_ADDR_TYPE_UNSET = 0, - HW_ADDR_TYPE_PERMANENT, - HW_ADDR_TYPE_EXPLICIT, - HW_ADDR_TYPE_GENERATED, -} HwAddrType; - -typedef enum { - FIREWALL_STATE_UNMANAGED = 0, - FIREWALL_STATE_INITIALIZED, - FIREWALL_STATE_WAIT_STAGE_3, - FIREWALL_STATE_WAIT_IP_CONFIG, -} FirewallState; - -typedef struct { - NMIPConfig *orig; /* the original configuration applied to the device */ - NMIPConfig *current; /* configuration after external changes. NULL means - * that the original configuration didn't change. */ -} AppliedConfig; - -typedef struct { - NMDhcpClient *client; - NMDhcpConfig *config; - gulong state_sigid; - guint grace_id; - bool grace_pending : 1; - bool was_active : 1; -} DhcpData; - -struct _NMDeviceConnectivityHandle { - CList concheck_lst; - NMDevice * self; - NMDeviceConnectivityCallback callback; - gpointer user_data; - NMConnectivityCheckHandle * c_handle; - guint64 seq; - bool is_periodic : 1; - bool is_periodic_bump : 1; - bool is_periodic_bump_on_complete : 1; - int addr_family; -}; - -typedef struct { - int ifindex; - NMEthtoolFeatureStates *features; - NMTernary requested[_NM_ETHTOOL_ID_FEATURE_NUM]; - NMEthtoolCoalesceState *coalesce; - NMEthtoolRingState * ring; -} EthtoolState; - -/*****************************************************************************/ - -enum { - STATE_CHANGED, - AUTOCONNECT_ALLOWED, - IP4_CONFIG_CHANGED, - IP6_CONFIG_CHANGED, - IP6_PREFIX_DELEGATED, - IP6_SUBNET_NEEDED, - REMOVED, - RECHECK_AUTO_ACTIVATE, - RECHECK_ASSUME, - LAST_SIGNAL, -}; -static guint signals[LAST_SIGNAL] = {0}; - -NM_GOBJECT_PROPERTIES_DEFINE(NMDevice, - PROP_UDI, - PROP_PATH, - PROP_IFACE, - PROP_IP_IFACE, - PROP_DRIVER, - PROP_DRIVER_VERSION, - PROP_FIRMWARE_VERSION, - PROP_CAPABILITIES, - PROP_CARRIER, - PROP_MTU, - PROP_IP4_ADDRESS, - PROP_IP4_CONFIG, - PROP_DHCP4_CONFIG, - PROP_IP6_CONFIG, - PROP_DHCP6_CONFIG, - PROP_STATE, - PROP_STATE_REASON, - PROP_ACTIVE_CONNECTION, - PROP_DEVICE_TYPE, - PROP_LINK_TYPE, - PROP_MANAGED, - PROP_AUTOCONNECT, - PROP_FIRMWARE_MISSING, - PROP_NM_PLUGIN_MISSING, - PROP_TYPE_DESC, - PROP_RFKILL_TYPE, - PROP_IFINDEX, - PROP_AVAILABLE_CONNECTIONS, - PROP_PHYSICAL_PORT_ID, - PROP_MASTER, - PROP_PARENT, - PROP_HW_ADDRESS, - PROP_PERM_HW_ADDRESS, - PROP_HAS_PENDING_ACTION, - PROP_METERED, - PROP_LLDP_NEIGHBORS, - PROP_REAL, - PROP_SLAVES, - PROP_STATISTICS_REFRESH_RATE_MS, - PROP_STATISTICS_TX_BYTES, - PROP_STATISTICS_RX_BYTES, - PROP_IP4_CONNECTIVITY, - PROP_IP6_CONNECTIVITY, - PROP_INTERFACE_FLAGS, ); - -typedef struct _NMDevicePrivate { - bool in_state_changed; - - guint device_link_changed_id; - guint device_ip_link_changed_id; - - NMDeviceState state; - NMDeviceStateReason state_reason; - struct { - guint id; - - /* The @state/@reason is only valid, when @id is set. */ - NMDeviceState state; - NMDeviceStateReason reason; - } queued_state; - - union { - struct { - guint queued_ip_config_id_6; - guint queued_ip_config_id_4; - }; - guint queued_ip_config_id_x[2]; - }; - - GSList *pending_actions; - GSList *dad6_failed_addrs; - - NMDBusTrackObjPath parent_device; - - char *udi; - char *path; - - union { - const char *const iface; - char * iface_; - }; - union { - const char *const ip_iface; - char * ip_iface_; - }; - - union { - const int ifindex; - int ifindex_; - }; - union { - const int ip_ifindex; - int ip_ifindex_; - }; - - NMNetnsSharedIPHandle *shared_ip_handle; - - int parent_ifindex; - - int auth_retries; - - union { - const guint8 hw_addr_len; /* read-only */ - guint8 hw_addr_len_; - }; - - HwAddrType hw_addr_type : 5; - - bool real : 1; - - bool update_ip_config_completed_v4 : 1; - bool update_ip_config_completed_v6 : 1; - - NMDeviceType type; - char * type_desc; - NMLinkType link_type; - NMDeviceCapabilities capabilities; - char * driver; - char * driver_version; - char * firmware_version; - RfKillType rfkill_type; - bool firmware_missing : 1; - bool nm_plugin_missing : 1; - bool - hw_addr_perm_fake : 1; /* whether the permanent HW address could not be read and is a fake */ - - NMUtilsStableType current_stable_id_type : 3; - - bool nm_owned : 1; /* whether the device is a device owned and created by NM */ - - bool assume_state_guess_assume : 1; - char *assume_state_connection_uuid; - - GHashTable *available_connections; - char * hw_addr; - char * hw_addr_perm; - char * hw_addr_initial; - char * physical_port_id; - guint dev_id; - - NMUnmanagedFlags unmanaged_mask; - NMUnmanagedFlags unmanaged_flags; - DeleteOnDeactivateData - *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */ - - GCancellable *deactivating_cancellable; - - NMActRequest * queued_act_request; - bool queued_act_request_is_waiting_for_carrier : 1; - NMDBusTrackObjPath act_request; - - union { - struct { - guint activation_source_id_6; - guint activation_source_id_4; /* for layer2 and IPv4. */ - }; - guint activation_source_id_x[2]; - }; - - union { - struct { - ActivationHandleFunc activation_source_func_6; - ActivationHandleFunc activation_source_func_4; /* for layer2 and IPv4. */ - }; - ActivationHandleFunc activation_source_func_x[2]; - }; - - guint recheck_assume_id; - - struct { - guint call_id; - NMDeviceStateReason available_reason; - NMDeviceStateReason unavailable_reason; - } recheck_available; - - struct { - NMDispatcherCallId *call_id; - NMDeviceState post_state; - NMDeviceStateReason post_state_reason; - } dispatcher; - - /* Link stuff */ - guint link_connected_id; - guint link_disconnected_id; - guint carrier_defer_id; - guint carrier_wait_id; - gulong config_changed_id; - guint32 mtu; - guint32 ip6_mtu; - guint32 mtu_initial; - guint32 ip6_mtu_initial; - NMDeviceMtuSource mtu_source; - - guint32 v4_route_table; - guint32 v6_route_table; - - /* when carrier goes away, we give a grace period of _get_carrier_wait_ms() - * until taking action. - * - * When changing MTU, the device might take longer then that. So, whenever - * NM changes the MTU it sets @carrier_wait_until_ms to CARRIER_WAIT_TIME_AFTER_MTU_MS - * in the future. This is used to extend the grace period in this particular case. */ - gint64 carrier_wait_until_ms; - - union { - const NMDeviceSysIfaceState sys_iface_state; - NMDeviceSysIfaceState sys_iface_state_; - }; - - bool carrier : 1; - bool ignore_carrier : 1; - - bool up : 1; /* IFF_UP */ - - bool v4_commit_first_time : 1; - bool v6_commit_first_time : 1; - - bool default_route_metric_penalty_ip4_has : 1; - bool default_route_metric_penalty_ip6_has : 1; - - bool v4_route_table_initialized : 1; - bool v6_route_table_initialized : 1; - - bool l3config_merge_flags_has : 1; - - bool v4_route_table_all_sync_before : 1; - bool v6_route_table_all_sync_before : 1; - - NMDeviceAutoconnectBlockedFlags autoconnect_blocked_flags : 5; - - bool is_enslaved : 1; - - bool ipv6ll_handle : 1; /* TRUE if NM handles the device's IPv6LL address */ - bool ipv6ll_has : 1; - bool ndisc_started : 1; - bool device_link_changed_down : 1; - - bool concheck_rp_filter_checked : 1; - - NMDeviceStageState stage1_sriov_state : 3; - - /* Generic DHCP stuff */ - char *dhcp_anycast_address; - - char *current_stable_id; - - /* Proxy Configuration */ - NMProxyConfig * proxy_config; - NMPacrunnerConfId *pacrunner_conf_id; - - /* IP configuration info. Combined config from VPN, settings, and device */ - union { - struct { - NMIP6Config *ip_config_6; - NMIP4Config *ip_config_4; - }; - NMIPConfig *ip_config_x[2]; - }; - - /* Config from DHCP, PPP, LLv4, etc */ - AppliedConfig dev_ip_config_4; - - /* config from the setting */ - union { - struct { - NMIP6Config *con_ip_config_6; - NMIP4Config *con_ip_config_4; - }; - NMIPConfig *con_ip_config_x[2]; - }; - - /* Stuff added outside NM */ - union { - struct { - NMIP6Config *ext_ip_config_6; - NMIP4Config *ext_ip_config_4; - }; - NMIPConfig *ext_ip_config_x[2]; - }; - - /* VPNs which use this device */ - union { - struct { - GSList *vpn_configs_6; - GSList *vpn_configs_4; - }; - GSList *vpn_configs_x[2]; - }; - - /* Extra device configuration, injected by the subclass of NMDevice. - * This is used for example by NMDeviceModem for WWAN configuration. */ - union { - struct { - AppliedConfig dev2_ip_config_6; - AppliedConfig dev2_ip_config_4; - }; - AppliedConfig dev2_ip_config_x[2]; - }; - - /* DHCPv4 tracking */ - struct { - char *pac_url; - } dhcp4; - - struct { - /* IP6 config from DHCP */ - AppliedConfig ip6_config; - /* Event ID of the current IP6 config from DHCP */ - char * event_id; - gulong prefix_sigid; - NMNDiscDHCPLevel mode; - guint needed_prefixes; - } dhcp6; - - union { - struct { - DhcpData dhcp_data_6; - DhcpData dhcp_data_4; - }; - DhcpData dhcp_data_x[2]; - }; - - struct { - NMLogDomain log_domain; - guint timeout; - guint watch; - GPid pid; - char * binary; - char * address; - guint deadline; - } gw_ping; - - /* dnsmasq stuff for shared connections */ - NMDnsMasqManager *dnsmasq_manager; - gulong dnsmasq_state_id; - - /* Firewall */ - FirewallState fw_state : 4; - NMFirewallManager * fw_mgr; - NMFirewallManagerCallId *fw_call; - - /* IPv4LL stuff */ - sd_ipv4ll *ipv4ll; - guint ipv4ll_timeout; - guint rt6_temporary_not_available_id; - - /* IPv4 DAD stuff */ - struct { - GSList * dad_list; - NMAcdManager *announcing; - } acd; - - union { - struct { - const NMDeviceIPState ip_state_6; - const NMDeviceIPState ip_state_4; - }; - union { - const NMDeviceIPState ip_state_x[2]; - NMDeviceIPState ip_state_x_[2]; - }; - }; - - AppliedConfig ac_ip6_config; /* config from IPv6 autoconfiguration */ - NMIP6Config * ext_ip6_config_captured; /* Configuration captured from platform. */ - NMIP6Config * dad6_ip6_config; - struct in6_addr ipv6ll_addr; - - GHashTable *rt6_temporary_not_available; - - NMNDisc * ndisc; - gulong ndisc_changed_id; - gulong ndisc_timeout_id; - NMSettingIP6ConfigPrivacy ndisc_use_tempaddr; - - guint linklocal6_timeout_id; - guint8 linklocal6_dad_counter; - - GHashTable *ip6_saved_properties; - - EthtoolState *ethtool_state; - - gboolean needs_ip6_subnet; - - /* master interface for bridge/bond/team slave */ - NMDevice *master; - gulong master_ready_id; - - /* slave management */ - CList slaves; /* list of SlaveInfo */ - - NMMetered metered; - - NMSettings *settings; - NMManager * manager; - - NMNetns *netns; - - NMLldpListener *lldp_listener; - - NMConnectivity *concheck_mgr; - CList concheck_lst_head; - struct { - /* if periodic checks are enabled, this is the source id for the next check. */ - guint p_cur_id; - - /* the currently configured max periodic interval. */ - guint p_max_interval; - - /* the current interval. If we are probing, the interval might be lower - * then the configured max interval. */ - guint p_cur_interval; - - /* the timestamp, when we last scheduled the timer p_cur_id with current interval - * p_cur_interval. */ - gint64 p_cur_basetime_ns; - - NMConnectivityState state; - } concheck_x[2]; - - guint check_delete_unrealized_id; - guint32 interface_flags; - - struct { - SriovOp *pending; /* SR-IOV operation currently running */ - SriovOp *next; /* next SR-IOV operation scheduled */ - } sriov; - guint sriov_reset_pending; - - struct { - guint timeout_id; - guint refresh_rate_ms; - guint64 tx_bytes; - guint64 rx_bytes; - } stats; - - bool mtu_force_set_done : 1; -} NMDevicePrivate; - -G_DEFINE_ABSTRACT_TYPE(NMDevice, nm_device, NM_TYPE_DBUS_OBJECT) - -#define NM_DEVICE_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMDevice, NM_IS_DEVICE) - -/*****************************************************************************/ - -static const NMDBusInterfaceInfoExtended interface_info_device; -static const GDBusSignalInfo signal_info_state_changed; - -static void nm_device_set_proxy_config(NMDevice *self, const char *pac_url); - -static gboolean update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs); - -static gboolean nm_device_set_ip_config(NMDevice * self, - int addr_family, - NMIPConfig *config, - gboolean commit, - GPtrArray * ip4_dev_route_blacklist); - -static gboolean ip_config_merge_and_apply(NMDevice *self, int addr_family, gboolean commit); - -static gboolean nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure); -static void nm_device_slave_notify_enslave(NMDevice *self, gboolean success); -static void nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason); - -static void addrconf6_start_with_link_ready(NMDevice *self); -static gboolean linklocal6_start(NMDevice *self); - -static guint32 default_route_metric_penalty_get(NMDevice *self, int addr_family); - -static guint _prop_get_ipv4_dad_timeout(NMDevice *self); - -static void _carrier_wait_check_queued_act_request(NMDevice *self); -static gint64 _get_carrier_wait_ms(NMDevice *self); - -static const char *_activation_func_to_string(ActivationHandleFunc func); - -static void -_set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting); -static void queued_state_clear(NMDevice *device); -static gboolean queued_ip4_config_change(gpointer user_data); -static gboolean queued_ip6_config_change(gpointer user_data); -static void ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data); -static gboolean ip_config_valid(NMDeviceState state); -static NMActStageReturn dhcp4_start(NMDevice *self); -static gboolean dhcp6_start(NMDevice *self, gboolean wait_for_ll); -static void nm_device_start_ip_check(NMDevice *self); -static void realize_start_setup(NMDevice * self, - const NMPlatformLink *plink, - gboolean assume_state_guess_assume, - const char * assume_state_connection_uuid, - gboolean set_nm_owned, - NMUnmanFlagOp unmanaged_user_explicit, - gboolean force_platform_init); -static void _set_mtu(NMDevice *self, guint32 mtu); -static void _commit_mtu(NMDevice *self, const NMIP4Config *config); -static void _cancel_activation(NMDevice *self); - -static void concheck_update_state(NMDevice * self, - int addr_family, - NMConnectivityState state, - gboolean is_periodic); - -static void activate_stage4_ip_config_timeout_4(NMDevice *self); -static void activate_stage4_ip_config_timeout_6(NMDevice *self); - -static void (*const activate_stage4_ip_config_timeout_x[2])(NMDevice *self) = { - activate_stage4_ip_config_timeout_6, - activate_stage4_ip_config_timeout_4, -}; - -static void sriov_op_cb(GError *error, gpointer user_data); - -static void activate_stage5_ip_config_result_4(NMDevice *self); -static void activate_stage5_ip_config_result_6(NMDevice *self); - -static void (*const activate_stage5_ip_config_result_x[2])(NMDevice *self) = { - activate_stage5_ip_config_result_6, - activate_stage5_ip_config_result_4, -}; - -/*****************************************************************************/ - -static NM_UTILS_LOOKUP_STR_DEFINE( - queued_state_to_string, - NMDeviceState, - NM_UTILS_LOOKUP_DEFAULT(NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "???"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNKNOWN, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNMANAGED, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unmanaged"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_UNAVAILABLE, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "unavailable"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_DISCONNECTED, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "disconnected"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_PREPARE, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "prepare"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_CONFIG, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "config"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_NEED_AUTH, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "need-auth"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_IP_CONFIG, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-config"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_IP_CHECK, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "ip-check"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_SECONDARIES, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "secondaries"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_ACTIVATED, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "activated"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_DEACTIVATING, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "deactivating"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_FAILED, - NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "failed"), ); - -const char * -nm_device_state_to_str(NMDeviceState state) -{ - return queued_state_to_string(state) + NM_STRLEN(NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE); -} - -NM_UTILS_LOOKUP_STR_DEFINE( - nm_device_state_reason_to_str, - NMDeviceStateReason, - NM_UTILS_LOOKUP_DEFAULT(NULL), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_UNKNOWN, "unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NOW_MANAGED, "managed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NOW_UNMANAGED, "unmanaged"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONFIG_FAILED, "config-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE, "ip-config-unavailable"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED, "ip-config-expired"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NO_SECRETS, "no-secrets"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT, "supplicant-disconnect"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED, - "supplicant-config-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED, "supplicant-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT, "supplicant-timeout"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_START_FAILED, "ppp-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_DISCONNECT, "ppp-disconnect"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PPP_FAILED, "ppp-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_START_FAILED, "dhcp-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_ERROR, "dhcp-error"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DHCP_FAILED, "dhcp-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SHARED_START_FAILED, "sharing-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SHARED_FAILED, "sharing-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED, "autoip-start-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_ERROR, "autoip-error"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_AUTOIP_FAILED, "autoip-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_BUSY, "modem-busy"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE, "modem-no-dialtone"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER, "modem-no-carrier"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT, "modem-dial-timeout"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_DIAL_FAILED, "modem-dial-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED, "modem-init-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_APN_FAILED, "gsm-apn-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING, - "gsm-registration-idle"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED, - "gsm-registration-denied"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT, - "gsm-registration-timeout"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_REGISTRATION_FAILED, - "gsm-registration-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_PIN_CHECK_FAILED, "gsm-pin-check-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_FIRMWARE_MISSING, "firmware-missing"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_REMOVED, "removed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SLEEPING, "sleeping"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, "connection-removed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_USER_REQUESTED, "user-requested"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CARRIER, "carrier-changed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED, "connection-assumed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, "supplicant-available"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_NOT_FOUND, "modem-not-found"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_BT_FAILED, "bluetooth-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED, "gsm-sim-not-inserted"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED, "gsm-sim-pin-required"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED, "gsm-sim-puk-required"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_GSM_SIM_WRONG, "gsm-sim-wrong"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_INFINIBAND_MODE, "infiniband-mode"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED, "dependency-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_BR2684_FAILED, "br2684-bridge-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE, - "modem-manager-unavailable"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SSID_NOT_FOUND, "ssid-not-found"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED, - "secondary-connection-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_DCB_FCOE_FAILED, "dcb-fcoe-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED, "teamd-control-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_FAILED, "modem-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, "modem-available"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT, "sim-pin-incorrect"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_NEW_ACTIVATION, "new-activation"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PARENT_CHANGED, "parent-changed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED, - "parent-managed-changed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_OVSDB_FAILED, "ovsdb-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE, "ip-address-duplicate"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED, "ip-method-unsupported"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED, - "sriov-configuration-failed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_STATE_REASON_PEER_NOT_FOUND, "peer-not-found"), ); - -#define reason_to_string_a(reason) NM_UTILS_LOOKUP_STR_A(nm_device_state_reason_to_str, reason) - -static NM_UTILS_LOOKUP_STR_DEFINE(mtu_source_to_str, - NMDeviceMtuSource, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_PARENT, "parent"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_IP_CONFIG, - "ip-config"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_MTU_SOURCE_CONNECTION, - "connection"), ); - -/*****************************************************************************/ - -static NMSettingIP6ConfigPrivacy -_ip6_privacy_clamp(NMSettingIP6ConfigPrivacy use_tempaddr) -{ - switch (use_tempaddr) { - case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - return use_tempaddr; - default: - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - } -} - -/*****************************************************************************/ - -static const char * -_prop_get_connection_stable_id(NMDevice * self, - NMConnection * connection, - NMUtilsStableType *out_stable_type) -{ - NMDevicePrivate *priv; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(NM_IS_CONNECTION(connection)); - nm_assert(out_stable_type); - - priv = NM_DEVICE_GET_PRIVATE(self); - - /* we cache the generated stable ID for the time of an activation. - * - * The reason is, that we don't want the stable-id to change as long - * as the device is active. - * - * Especially with ${RANDOM} stable-id we want to generate *one* configuration - * for each activation. */ - if (G_UNLIKELY(!priv->current_stable_id)) { - gs_free char * default_id = NULL; - gs_free char * generated = NULL; - NMUtilsStableType stable_type; - NMSettingConnection *s_con; - gboolean hwaddr_is_fake; - const char * hwaddr; - const char * stable_id; - const char * uuid; - - s_con = nm_connection_get_setting_connection(connection); - - stable_id = nm_setting_connection_get_stable_id(s_con); - - if (!stable_id) { - default_id = - nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("connection.stable-id"), - self); - stable_id = default_id; - } - - uuid = nm_connection_get_uuid(connection); - - /* the cloned-mac-address may be generated based on the stable-id. - * Thus, at this point, we can only use the permanent MAC address - * as seed. */ - hwaddr = nm_device_get_permanent_hw_address_full(self, TRUE, &hwaddr_is_fake); - - stable_type = nm_utils_stable_id_parse(stable_id, - nm_device_get_ip_iface(self), - !hwaddr_is_fake ? hwaddr : NULL, - nm_utils_boot_id_str(), - uuid, - &generated); - - /* current_stable_id_type is a bitfield! */ - priv->current_stable_id_type = stable_type; - nm_assert(stable_type <= (NMUtilsStableType) 0x3); - nm_assert(stable_type + (NMUtilsStableType) 1 > (NMUtilsStableType) 0); - nm_assert(priv->current_stable_id_type == stable_type); - - if (stable_type == NM_UTILS_STABLE_TYPE_UUID) - priv->current_stable_id = g_strdup(uuid); - else if (stable_type == NM_UTILS_STABLE_TYPE_STABLE_ID) - priv->current_stable_id = g_strdup(stable_id); - else if (stable_type == NM_UTILS_STABLE_TYPE_GENERATED) - priv->current_stable_id = - nm_str_realloc(nm_utils_stable_id_generated_complete(generated)); - else { - nm_assert(stable_type == NM_UTILS_STABLE_TYPE_RANDOM); - priv->current_stable_id = nm_str_realloc(nm_utils_stable_id_random()); - } - _LOGT(LOGD_DEVICE, - "stable-id: type=%d, \"%s\"" - "%s%s%s", - (int) priv->current_stable_id_type, - priv->current_stable_id, - NM_PRINT_FMT_QUOTED(stable_type == NM_UTILS_STABLE_TYPE_GENERATED, - " from \"", - generated, - "\"", - "")); - } - - nm_assert(priv->current_stable_id); - *out_stable_type = priv->current_stable_id_type; - return priv->current_stable_id; -} - -static GBytes * -_prop_get_ipv6_dhcp_duid(NMDevice * self, - NMConnection *connection, - GBytes * hwaddr, - gboolean * out_enforce) -{ - NMSettingIPConfig *s_ip6; - const char * duid; - gs_free char * duid_default = NULL; - const char * duid_error; - GBytes * duid_out; - gboolean duid_enforce = TRUE; - gs_free char * logstr1 = NULL; - const guint8 * hwaddr_bin; - gsize hwaddr_len; - int arp_type; - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - duid = nm_setting_ip6_config_get_dhcp_duid(NM_SETTING_IP6_CONFIG(s_ip6)); - - if (!duid) { - duid_default = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ipv6.dhcp-duid"), - self); - duid = duid_default; - if (!duid) - duid = "lease"; - } - - if (nm_streq(duid, "lease")) { - duid_enforce = FALSE; - duid_out = nm_utils_generate_duid_from_machine_id(); - goto out_good; - } - - if (!_nm_utils_dhcp_duid_valid(duid, &duid_out)) { - duid_error = "invalid duid"; - goto out_fail; - } - - if (duid_out) - goto out_good; - - if (NM_IN_STRSET(duid, "ll", "llt")) { - if (!hwaddr) { - duid_error = "missing link-layer address"; - goto out_fail; - } - - hwaddr_bin = g_bytes_get_data(hwaddr, &hwaddr_len); - arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len); - if (arp_type < 0) { - duid_error = "unsupported link-layer address"; - goto out_fail; - } - - if (nm_streq(duid, "ll")) - duid_out = nm_utils_generate_duid_ll(arp_type, hwaddr_bin, hwaddr_len); - else { - duid_out = nm_utils_generate_duid_llt(arp_type, - hwaddr_bin, - hwaddr_len, - nm_utils_host_id_get_timestamp_ns() - / NM_UTILS_NSEC_PER_SEC); - } - - goto out_good; - } - - if (NM_IN_STRSET(duid, "stable-ll", "stable-llt", "stable-uuid")) { - /* preferably, we would salt the checksum differently for each @duid type. We missed - * to do that initially, so most types use the DEFAULT_SALT. - * - * Implementations that are added later, should use a distinct salt instead, - * like "stable-ll"/"stable-llt" with ARPHRD_INFINIBAND below. */ - const guint32 DEFAULT_SALT = 670531087u; - nm_auto_free_checksum GChecksum *sum = NULL; - NMUtilsStableType stable_type; - const char * stable_id = NULL; - guint32 salted_header; - const guint8 * host_id; - gsize host_id_len; - union { - guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256]; - guint8 hwaddr_eth[ETH_ALEN]; - guint8 hwaddr_infiniband[INFINIBAND_ALEN]; - NMUuid uuid; - struct _nm_packed { - guint8 hwaddr[ETH_ALEN]; - guint32 timestamp; - } llt_eth; - struct _nm_packed { - guint8 hwaddr[INFINIBAND_ALEN]; - guint32 timestamp; - } llt_infiniband; - } digest; - - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); - - if (NM_IN_STRSET(duid, "stable-ll", "stable-llt")) { - /* for stable LL/LLT DUIDs, we still need a hardware address to detect - * the arp-type. Alternatively, we would be able to detect it based on - * other means (e.g. NMDevice type), but instead require the hardware - * address to be present. This is at least consistent with the "ll"/"llt" - * modes above. */ - if (!hwaddr) { - duid_error = "missing link-layer address"; - goto out_fail; - } - if ((arp_type = nm_utils_arp_type_detect_from_hwaddrlen(g_bytes_get_size(hwaddr))) - < 0) { - duid_error = "unsupported link-layer address"; - goto out_fail; - } - - if (arp_type == ARPHRD_ETHER) - salted_header = DEFAULT_SALT; - else { - nm_assert(arp_type == ARPHRD_INFINIBAND); - salted_header = 0x42492CEFu + ((guint32) arp_type); - } - } else { - salted_header = DEFAULT_SALT; - arp_type = -1; - } - - salted_header = htonl(salted_header + ((guint32) stable_type)); - - nm_utils_host_id_get(&host_id, &host_id_len); - - sum = g_checksum_new(G_CHECKSUM_SHA256); - g_checksum_update(sum, (const guchar *) &salted_header, sizeof(salted_header)); - g_checksum_update(sum, (const guchar *) stable_id, -1); - g_checksum_update(sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest(sum, digest.sha256); - - G_STATIC_ASSERT_EXPR(sizeof(digest) == sizeof(digest.sha256)); - - if (nm_streq(duid, "stable-ll")) { - switch (arp_type) { - case ARPHRD_ETHER: - duid_out = nm_utils_generate_duid_ll(arp_type, - digest.hwaddr_eth, - sizeof(digest.hwaddr_eth)); - break; - case ARPHRD_INFINIBAND: - duid_out = nm_utils_generate_duid_ll(arp_type, - digest.hwaddr_infiniband, - sizeof(digest.hwaddr_infiniband)); - break; - default: - g_return_val_if_reached(NULL); - } - } else if (nm_streq(duid, "stable-llt")) { - gint64 time; - guint32 timestamp; - -#define EPOCH_DATETIME_THREE_YEARS (356 * 24 * 3600 * 3) - - /* We want a variable time between the host_id timestamp and three years - * before. Let's compute the time (in seconds) from 0 to 3 years; then we'll - * subtract it from the host_id timestamp. - */ - time = nm_utils_host_id_get_timestamp_ns() / NM_UTILS_NSEC_PER_SEC; - - /* don't use too old timestamps. They cannot be expressed in DUID-LLT and - * would all be truncated to zero. */ - time = NM_MAX(time, NM_UTILS_EPOCH_DATETIME_200001010000 + EPOCH_DATETIME_THREE_YEARS); - - switch (arp_type) { - case ARPHRD_ETHER: - timestamp = unaligned_read_be32(&digest.llt_eth.timestamp); - time -= timestamp % EPOCH_DATETIME_THREE_YEARS; - duid_out = nm_utils_generate_duid_llt(arp_type, - digest.llt_eth.hwaddr, - sizeof(digest.llt_eth.hwaddr), - time); - break; - case ARPHRD_INFINIBAND: - timestamp = unaligned_read_be32(&digest.llt_infiniband.timestamp); - time -= timestamp % EPOCH_DATETIME_THREE_YEARS; - duid_out = nm_utils_generate_duid_llt(arp_type, - digest.llt_infiniband.hwaddr, - sizeof(digest.llt_infiniband.hwaddr), - time); - break; - default: - g_return_val_if_reached(NULL); - } - } else { - nm_assert(nm_streq(duid, "stable-uuid")); - duid_out = nm_utils_generate_duid_uuid(&digest.uuid); - } - - goto out_good; - } - - g_return_val_if_reached(NULL); - -out_fail: - nm_assert(!duid_out && duid_error); - { - NMUuid uuid; - - _LOGW(LOGD_IP6 | LOGD_DHCP6, - "ipv6.dhcp-duid: failure to generate %s DUID: %s. Fallback to random DUID-UUID.", - duid, - duid_error); - - nm_utils_random_bytes(&uuid, sizeof(uuid)); - duid_out = nm_utils_generate_duid_uuid(&uuid); - } - -out_good: - nm_assert(duid_out); - _LOGD(LOGD_IP6 | LOGD_DHCP6, - "ipv6.dhcp-duid: generate %s DUID '%s' (%s)", - duid, - (logstr1 = nm_dhcp_utils_duid_to_string(duid_out)), - duid_enforce ? "enforcing" : "prefer lease"); - - NM_SET_OUT(out_enforce, duid_enforce); - return duid_out; -} - -static guint32 -_prop_get_ipv6_ra_timeout(NMDevice *self) -{ - NMConnection *connection; - gint32 timeout; - - G_STATIC_ASSERT_EXPR(NM_RA_TIMEOUT_DEFAULT == 0); - G_STATIC_ASSERT_EXPR(NM_RA_TIMEOUT_INFINITY == G_MAXINT32); - - connection = nm_device_get_applied_connection(self); - - timeout = nm_setting_ip6_config_get_ra_timeout( - NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection))); - if (timeout > 0) - return timeout; - nm_assert(timeout == 0); - - return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ipv6.ra-timeout"), - self, - 0, - G_MAXINT32, - 0); -} - -static NMSettingConnectionMdns -_prop_get_connection_mdns(NMDevice *self) -{ - NMConnection * connection; - NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; - - g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_MDNS_DEFAULT); - - connection = nm_device_get_applied_connection(self); - if (connection) - mdns = nm_setting_connection_get_mdns(nm_connection_get_setting_connection(connection)); - if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) - return mdns; - - return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("connection.mdns"), - self, - NM_SETTING_CONNECTION_MDNS_NO, - NM_SETTING_CONNECTION_MDNS_YES, - NM_SETTING_CONNECTION_MDNS_DEFAULT); -} - -static NMSettingConnectionLlmnr -_prop_get_connection_llmnr(NMDevice *self) -{ - NMConnection * connection; - NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; - - g_return_val_if_fail(NM_IS_DEVICE(self), NM_SETTING_CONNECTION_LLMNR_DEFAULT); - - connection = nm_device_get_applied_connection(self); - if (connection) - llmnr = nm_setting_connection_get_llmnr(nm_connection_get_setting_connection(connection)); - if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) - return llmnr; - - return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("connection.llmnr"), - self, - NM_SETTING_CONNECTION_LLMNR_NO, - NM_SETTING_CONNECTION_LLMNR_YES, - NM_SETTING_CONNECTION_LLMNR_DEFAULT); -} - -static guint32 -_prop_get_ipvx_route_table(NMDevice *self, int addr_family) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceClass * klass; - NMConnection * connection; - NMSettingIPConfig * s_ip; - guint32 route_table = 0; - gboolean is_user_config = TRUE; - NMSettingConnection *s_con; - NMSettingVrf * s_vrf; - - nm_assert_addr_family(addr_family); - - /* the route table setting affects how we sync routes. We shall - * not change it while the device is active, hence, cache it. */ - if (addr_family == AF_INET) { - if (priv->v4_route_table_initialized) - return priv->v4_route_table; - } else { - if (priv->v6_route_table_initialized) - return priv->v6_route_table; - } - - connection = nm_device_get_applied_connection(self); - if (connection) { - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - if (s_ip) - route_table = nm_setting_ip_config_get_route_table(s_ip); - } - if (route_table == 0u) { - gint64 v; - - v = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT("ipv4.route-table") - : NM_CON_DEFAULT("ipv6.route-table"), - self, - 0, - G_MAXUINT32, - -1); - if (v != -1) { - route_table = v; - is_user_config = FALSE; - } - } - - if (route_table == 0u && connection - && (s_con = nm_connection_get_setting_connection(connection)) - && (nm_streq0(nm_setting_connection_get_slave_type(s_con), NM_SETTING_VRF_SETTING_NAME) - && priv->master && nm_device_get_device_type(priv->master) == NM_DEVICE_TYPE_VRF)) { - const NMPlatformLnkVrf *lnk; - - lnk = nm_platform_link_get_lnk_vrf(nm_device_get_platform(self), - nm_device_get_ifindex(priv->master), - NULL); - - if (lnk) - route_table = lnk->table; - } - - if (route_table == 0u && connection - && (s_vrf = (NMSettingVrf *) nm_connection_get_setting(connection, NM_TYPE_SETTING_VRF))) { - route_table = nm_setting_vrf_get_table(s_vrf); - } - - klass = NM_DEVICE_GET_CLASS(self); - if (klass->coerce_route_table) - route_table = klass->coerce_route_table(self, addr_family, route_table, is_user_config); - - if (addr_family == AF_INET) { - priv->v4_route_table_initialized = TRUE; - priv->v4_route_table = route_table; - } else { - priv->v6_route_table_initialized = TRUE; - priv->v6_route_table = route_table; - } - - _LOGT(LOGD_DEVICE, - "ipv%c.route-table = %u%s", - addr_family == AF_INET ? '4' : '6', - (guint)(route_table ?: RT_TABLE_MAIN), - route_table != 0u ? "" : " (policy routing not enabled)"); - - return route_table; -} - -static gboolean -_prop_get_connection_lldp(NMDevice *self) -{ - NMConnection * connection; - NMSettingConnection * s_con; - NMSettingConnectionLldp lldp = NM_SETTING_CONNECTION_LLDP_DEFAULT; - - connection = nm_device_get_applied_connection(self); - g_return_val_if_fail(connection, FALSE); - - s_con = nm_connection_get_setting_connection(connection); - g_return_val_if_fail(s_con, FALSE); - - lldp = nm_setting_connection_get_lldp(s_con); - if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) { - lldp = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("connection.lldp"), - self, - NM_SETTING_CONNECTION_LLDP_DEFAULT, - NM_SETTING_CONNECTION_LLDP_ENABLE_RX, - NM_SETTING_CONNECTION_LLDP_DEFAULT); - if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) - lldp = NM_SETTING_CONNECTION_LLDP_DISABLE; - } - return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX; -} - -static guint -_prop_get_ipv4_dad_timeout(NMDevice *self) -{ - NMConnection * connection; - NMSettingIPConfig *s_ip4 = NULL; - int timeout = -1; - - connection = nm_device_get_applied_connection(self); - if (connection) - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (s_ip4) - timeout = nm_setting_ip_config_get_dad_timeout(s_ip4); - if (timeout >= 0) - return timeout; - - return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ipv4.dad-timeout"), - self, - 0, - NM_SETTING_IP_CONFIG_DAD_TIMEOUT_MAX, - 0); -} - -static guint32 -_prop_get_ipvx_dhcp_timeout(NMDevice *self, int addr_family) -{ - NMDeviceClass *klass; - NMConnection * connection; - int timeout_i; - guint32 timeout; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert_addr_family(addr_family); - - connection = nm_device_get_applied_connection(self); - - timeout_i = nm_setting_ip_config_get_dhcp_timeout( - nm_connection_get_setting_ip_config(connection, addr_family)); - nm_assert(timeout_i >= 0 && timeout_i <= G_MAXINT32); - - timeout = (guint32) timeout_i; - if (timeout) - goto out; - - timeout = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - addr_family == AF_INET - ? NM_CON_DEFAULT("ipv4.dhcp-timeout") - : NM_CON_DEFAULT("ipv6.dhcp-timeout"), - self, - 0, - G_MAXINT32, - 0); - if (timeout) - goto out; - - klass = NM_DEVICE_GET_CLASS(self); - if (klass->get_dhcp_timeout_for_device) { - timeout = klass->get_dhcp_timeout_for_device(self, addr_family); - if (timeout) - goto out; - } - - timeout = NM_DHCP_TIMEOUT_DEFAULT; - -out: - G_STATIC_ASSERT_EXPR(G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); - nm_assert(timeout > 0); - nm_assert(timeout <= G_MAXINT32); - return timeout; -} - -/** - * _prop_get_ipvx_dhcp_iaid: - * @self: the #NMDevice - * @addr_family: the address family - * @connection: the connection - * @out_is_explicit: on return, %TRUE if the user set a valid IAID in - * the connection or in global configuration; %FALSE if the connection - * property was empty and no valid global configuration was provided. - * - * Returns: a IAID value for this device and the given connection. - */ -static guint32 -_prop_get_ipvx_dhcp_iaid(NMDevice * self, - int addr_family, - NMConnection *connection, - gboolean * out_is_explicit) -{ - NMSettingIPConfig *s_ip; - const char * iaid_str; - gs_free char * iaid_str_free = NULL; - guint32 iaid; - const char * iface; - const char * fail_reason; - gboolean is_explicit = TRUE; - - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - iaid_str = nm_setting_ip_config_get_dhcp_iaid(s_ip); - if (!iaid_str) { - iaid_str_free = nm_config_data_get_connection_default( - NM_CONFIG_GET_DATA, - addr_family == AF_INET ? NM_CON_DEFAULT("ipv4.dhcp-iaid") - : NM_CON_DEFAULT("ipv6.dhcp-iaid"), - self); - iaid_str = iaid_str_free; - if (!iaid_str) { - iaid_str = NM_IAID_IFNAME; - is_explicit = FALSE; - } else if (!_nm_utils_iaid_verify(iaid_str, NULL)) { - _LOGW(LOGD_DEVICE, - "invalid global default '%s' for ipv%c.dhcp-iaid", - iaid_str, - nm_utils_addr_family_to_char(addr_family)); - iaid_str = NM_IAID_IFNAME; - is_explicit = FALSE; - } - } - - if (nm_streq0(iaid_str, NM_IAID_MAC)) { - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); - if (!pllink || pllink->l_address.len < 4) { - fail_reason = "invalid link-layer address"; - goto out_fail; - } - - /* @iaid is in native endianness. Use unaligned_read_be32() - * so that the IAID for a given MAC address is the same on - * BE and LE machines. */ - iaid = unaligned_read_be32(&pllink->l_address.data[pllink->l_address.len - 4]); - goto out_good; - } else if (nm_streq0(iaid_str, NM_IAID_PERM_MAC)) { - guint8 hwaddr_buf[NM_UTILS_HWADDR_LEN_MAX]; - const char *hwaddr_str; - gsize hwaddr_len; - - hwaddr_str = nm_device_get_permanent_hw_address(self); - if (!hwaddr_str) { - fail_reason = "no permanent link-layer address"; - goto out_fail; - } - - if (!_nm_utils_hwaddr_aton(hwaddr_str, hwaddr_buf, sizeof(hwaddr_buf), &hwaddr_len)) - g_return_val_if_reached(0); - - if (hwaddr_len < 4) { - fail_reason = "invalid link-layer address"; - goto out_fail; - } - - iaid = unaligned_read_be32(&hwaddr_buf[hwaddr_len - 4]); - goto out_good; - } else if (nm_streq(iaid_str, "stable")) { - nm_auto_free_checksum GChecksum *sum = NULL; - guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - NMUtilsStableType stable_type; - const char * stable_id; - guint32 salted_header; - const guint8 * host_id; - gsize host_id_len; - - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); - salted_header = htonl(53390459 + stable_type); - nm_utils_host_id_get(&host_id, &host_id_len); - iface = nm_device_get_ip_iface(self); - - sum = g_checksum_new(G_CHECKSUM_SHA1); - g_checksum_update(sum, (const guchar *) &salted_header, sizeof(salted_header)); - g_checksum_update(sum, (const guchar *) stable_id, strlen(stable_id) + 1); - g_checksum_update(sum, (const guchar *) iface, strlen(iface) + 1); - g_checksum_update(sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest(sum, digest); - - iaid = unaligned_read_be32(digest); - goto out_good; - } else if ((iaid = _nm_utils_ascii_str_to_int64(iaid_str, 10, 0, G_MAXUINT32, -1)) != -1) { - goto out_good; - } else { - iface = nm_device_get_ip_iface(self); - iaid = nm_utils_create_dhcp_iaid(TRUE, (const guint8 *) iface, strlen(iface)); - goto out_good; - } - -out_fail: - nm_assert(fail_reason); - _LOGW(addr_family == AF_INET ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) - : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), - "ipv%c.dhcp-iaid: failure to generate IAID: %s. Using interface-name based IAID", - nm_utils_addr_family_to_char(addr_family), - fail_reason); - is_explicit = FALSE; - iface = nm_device_get_ip_iface(self); - iaid = nm_utils_create_dhcp_iaid(TRUE, (const guint8 *) iface, strlen(iface)); -out_good: - _LOGD(addr_family == AF_INET ? (LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4) - : (LOGD_DEVICE | LOGD_DHCP6 | LOGD_IP6), - "ipv%c.dhcp-iaid: using %u (0x%08x) IAID (str: '%s', explicit %d)", - nm_utils_addr_family_to_char(addr_family), - iaid, - iaid, - iaid_str, - is_explicit); - NM_SET_OUT(out_is_explicit, is_explicit); - return iaid; -} - -static NMDhcpHostnameFlags -_prop_get_ipvx_dhcp_hostname_flags(NMDevice *self, int addr_family) -{ - NMConnection * connection; - NMSettingIPConfig * s_ip; - NMDhcpHostnameFlags flags; - gs_free_error GError *error = NULL; - - g_return_val_if_fail(NM_IS_DEVICE(self), NM_DHCP_HOSTNAME_FLAG_NONE); - - connection = nm_device_get_applied_connection(self); - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - g_return_val_if_fail(s_ip, NM_DHCP_HOSTNAME_FLAG_NONE); - - if (!nm_setting_ip_config_get_dhcp_send_hostname(s_ip)) - return NM_DHCP_HOSTNAME_FLAG_NONE; - - flags = nm_setting_ip_config_get_dhcp_hostname_flags(s_ip); - if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) - return flags; - - flags = nm_config_data_get_connection_default_int64( - NM_CONFIG_GET_DATA, - addr_family == AF_INET ? NM_CON_DEFAULT("ipv4.dhcp-hostname-flags") - : NM_CON_DEFAULT("ipv6.dhcp-hostname-flags"), - self, - 0, - NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS, - 0); - - if (!_nm_utils_validate_dhcp_hostname_flags(flags, addr_family, &error)) { - _LOGW(LOGD_DEVICE, - "invalid global default value 0x%x for ipv%d.%s: %s", - (guint) flags, - addr_family == AF_INET ? 4 : 6, - NM_SETTING_IP_CONFIG_DHCP_HOSTNAME_FLAGS, - error->message); - flags = NM_DHCP_HOSTNAME_FLAG_NONE; - } - - if (flags != NM_DHCP_HOSTNAME_FLAG_NONE) - return flags; - - if (addr_family == AF_INET) - return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP4; - else - return NM_DHCP_HOSTNAME_FLAGS_FQDN_DEFAULT_IP6; -} - -static const char * -_prop_get_connection_mud_url(NMDevice *self, NMSettingConnection *s_con, char **out_mud_url) -{ - const char * mud_url; - gs_free char *s = NULL; - - nm_assert(out_mud_url && !*out_mud_url); - - mud_url = nm_setting_connection_get_mud_url(s_con); - - if (mud_url) { - if (nm_streq(mud_url, NM_CONNECTION_MUD_URL_NONE)) - return NULL; - return mud_url; - } - - s = nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("connection.mud-url"), - self); - if (s) { - if (nm_streq(s, NM_CONNECTION_MUD_URL_NONE)) - return NULL; - if (nm_sd_http_url_is_valid_https(s)) - return (*out_mud_url = g_steal_pointer(&s)); - } - - return NULL; -} - -static GBytes * -_prop_get_ipv4_dhcp_client_id(NMDevice *self, NMConnection *connection, GBytes *hwaddr) -{ - NMSettingIPConfig *s_ip4; - const char * client_id; - gs_free char * client_id_default = NULL; - guint8 * client_id_buf; - const char * fail_reason; - guint8 hwaddr_bin_buf[NM_UTILS_HWADDR_LEN_MAX]; - const guint8 * hwaddr_bin; - int arp_type; - gsize hwaddr_len; - GBytes * result; - gs_free char * logstr1 = NULL; - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - client_id = nm_setting_ip4_config_get_dhcp_client_id(NM_SETTING_IP4_CONFIG(s_ip4)); - - if (!client_id) { - client_id_default = - nm_config_data_get_connection_default(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ipv4.dhcp-client-id"), - self); - if (client_id_default && client_id_default[0]) { - /* a non-empty client-id is always valid, see nm_dhcp_utils_client_id_string_to_bytes(). */ - client_id = client_id_default; - } - } - - if (!client_id) { - _LOGD(LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: no explicit client-id configured"); - return NULL; - } - - if (nm_streq(client_id, "mac")) { - if (!hwaddr) { - fail_reason = "missing link-layer address"; - goto out_fail; - } - - hwaddr_bin = g_bytes_get_data(hwaddr, &hwaddr_len); - arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len); - if (arp_type < 0) { - fail_reason = "unsupported link-layer address"; - goto out_fail; - } - - result = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_bin, hwaddr_len); - goto out_good; - } - - if (nm_streq(client_id, "perm-mac")) { - const char *hwaddr_str; - - hwaddr_str = nm_device_get_permanent_hw_address(self); - if (!hwaddr_str) { - fail_reason = "missing permanent link-layer address"; - goto out_fail; - } - - if (!_nm_utils_hwaddr_aton(hwaddr_str, hwaddr_bin_buf, sizeof(hwaddr_bin_buf), &hwaddr_len)) - g_return_val_if_reached(NULL); - - arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len); - if (arp_type < 0) { - fail_reason = "unsupported permanent link-layer address"; - goto out_fail; - } - - result = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_bin_buf, hwaddr_len); - goto out_good; - } - - if (nm_streq(client_id, "duid")) { - guint32 iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET, connection, NULL); - - result = nm_utils_dhcp_client_id_systemd_node_specific(iaid); - goto out_good; - } - - if (nm_streq(client_id, "stable")) { - nm_auto_free_checksum GChecksum *sum = NULL; - guint8 digest[NM_UTILS_CHECKSUM_LENGTH_SHA1]; - NMUtilsStableType stable_type; - const char * stable_id; - guint32 salted_header; - const guint8 * host_id; - gsize host_id_len; - - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); - salted_header = htonl(2011610591 + stable_type); - nm_utils_host_id_get(&host_id, &host_id_len); - - sum = g_checksum_new(G_CHECKSUM_SHA1); - g_checksum_update(sum, (const guchar *) &salted_header, sizeof(salted_header)); - g_checksum_update(sum, (const guchar *) stable_id, strlen(stable_id) + 1); - g_checksum_update(sum, (const guchar *) host_id, host_id_len); - nm_utils_checksum_get_digest(sum, digest); - - client_id_buf = g_malloc(1 + 15); - client_id_buf[0] = 0; - memcpy(&client_id_buf[1], digest, 15); - result = g_bytes_new_take(client_id_buf, 1 + 15); - goto out_good; - } - - result = nm_dhcp_utils_client_id_string_to_bytes(client_id); - goto out_good; - -out_fail: - nm_assert(fail_reason); - _LOGW(LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: failure to generate client id (%s). Use random client id", - fail_reason); - client_id_buf = g_malloc(1 + 15); - client_id_buf[0] = 0; - nm_utils_random_bytes(&client_id_buf[1], 15); - result = g_bytes_new_take(client_id_buf, 1 + 15); - -out_good: - nm_assert(result); - _LOGD(LOGD_DEVICE | LOGD_DHCP4 | LOGD_IP4, - "ipv4.dhcp-client-id: use \"%s\" client ID: %s", - client_id, - (logstr1 = nm_dhcp_utils_duid_to_string(result))); - return result; -} - -static GBytes * -_prop_get_ipv4_dhcp_vendor_class_identifier(NMDevice *self, NMSettingIP4Config *s_ip4) -{ - gs_free char *config_data_prop = NULL; - gs_free char *to_free = NULL; - const char * conn_prop; - GBytes * bytes = NULL; - const char * bin; - gsize len; - - conn_prop = nm_setting_ip4_config_get_dhcp_vendor_class_identifier(s_ip4); - - if (!conn_prop) { - /* set in NetworkManager.conf ? */ - config_data_prop = nm_config_data_get_connection_default( - NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ipv4.dhcp-vendor-class-identifier"), - self); - - if (config_data_prop && nm_utils_validate_dhcp4_vendor_class_id(config_data_prop, NULL)) - conn_prop = config_data_prop; - } - - if (conn_prop) { - bin = nm_utils_buf_utf8safe_unescape(conn_prop, - NM_UTILS_STR_UTF8_SAFE_FLAG_NONE, - &len, - (gpointer *) &to_free); - if (to_free) - bytes = g_bytes_new_take(g_steal_pointer(&to_free), len); - else - bytes = g_bytes_new(bin, len); - } - - return bytes; -} - -static NMSettingIP6ConfigPrivacy -_prop_get_ipv6_ip6_privacy(NMDevice *self) -{ - NMSettingIP6ConfigPrivacy ip6_privacy; - NMConnection * connection; - - g_return_val_if_fail(self, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - - /* 1.) First look at the per-connection setting. If it is not -1 (unknown), - * use it. */ - connection = nm_device_get_applied_connection(self); - if (connection) { - NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config(connection); - - if (s_ip6) { - ip6_privacy = nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip6)); - ip6_privacy = _ip6_privacy_clamp(ip6_privacy); - if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) - return ip6_privacy; - } - } - - /* 2.) use the default value from the configuration. */ - ip6_privacy = - nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("ipv6.ip6-privacy"), - self, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - if (ip6_privacy != NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN) - return ip6_privacy; - - if (!nm_device_get_ip_ifindex(self)) - return NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - - /* 3.) No valid default-value configured. Fallback to reading sysctl. - * - * Instead of reading static config files in /etc, just read the current sysctl value. - * This works as NM only writes to "/proc/sys/net/ipv6/conf/IFNAME/use_tempaddr", but leaves - * the "default" entry untouched. */ - ip6_privacy = nm_platform_sysctl_get_int32( - nm_device_get_platform(self), - NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv6/conf/default/use_tempaddr"), - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - return _ip6_privacy_clamp(ip6_privacy); -} - -static const char * -_prop_get_x_cloned_mac_address(NMDevice * self, - NMConnection *connection, - gboolean is_wifi, - char ** out_addr) -{ - NMSetting * setting; - const char *addr = NULL; - - nm_assert(out_addr && !*out_addr); - - setting = nm_connection_get_setting(connection, - is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); - if (setting) { - addr = is_wifi ? nm_setting_wireless_get_cloned_mac_address((NMSettingWireless *) setting) - : nm_setting_wired_get_cloned_mac_address((NMSettingWired *) setting); - } - - if (!addr) { - gs_free char *a = NULL; - - a = nm_config_data_get_connection_default( - NM_CONFIG_GET_DATA, - is_wifi ? NM_CON_DEFAULT("wifi.cloned-mac-address") - : NM_CON_DEFAULT("ethernet.cloned-mac-address"), - self); - - addr = NM_CLONED_MAC_PRESERVE; - - if (!a) { - if (is_wifi) { - NMSettingMacRandomization v; - - /* for backward compatibility, read the deprecated wifi.mac-address-randomization setting. */ - a = nm_config_data_get_connection_default( - NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("wifi.mac-address-randomization"), - self); - v = _nm_utils_ascii_str_to_int64(a, - 10, - NM_SETTING_MAC_RANDOMIZATION_DEFAULT, - NM_SETTING_MAC_RANDOMIZATION_ALWAYS, - NM_SETTING_MAC_RANDOMIZATION_DEFAULT); - if (v == NM_SETTING_MAC_RANDOMIZATION_ALWAYS) - addr = NM_CLONED_MAC_RANDOM; - } - } else if (NM_CLONED_MAC_IS_SPECIAL(a) || nm_utils_hwaddr_valid(a, ETH_ALEN)) - addr = *out_addr = g_steal_pointer(&a); - } - - return addr; -} - -static const char * -_prop_get_x_generate_mac_address_mask(NMDevice * self, - NMConnection *connection, - gboolean is_wifi, - char ** out_value) -{ - NMSetting * setting; - const char *value = NULL; - char * a; - - nm_assert(out_value && !*out_value); - - setting = nm_connection_get_setting(connection, - is_wifi ? NM_TYPE_SETTING_WIRELESS : NM_TYPE_SETTING_WIRED); - if (setting) { - value = - is_wifi - ? nm_setting_wireless_get_generate_mac_address_mask((NMSettingWireless *) setting) - : nm_setting_wired_get_generate_mac_address_mask((NMSettingWired *) setting); - if (value) - return value; - } - - a = nm_config_data_get_connection_default( - NM_CONFIG_GET_DATA, - is_wifi ? NM_CON_DEFAULT("wifi.generate-mac-address-mask") - : NM_CON_DEFAULT("ethernet.generate-mac-address-mask"), - self); - if (!a) - return NULL; - *out_value = a; - return a; -} - -/*****************************************************************************/ - -static void -_ethtool_features_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) -{ - gs_free NMEthtoolFeatureStates *features; - - features = g_steal_pointer(ðtool_state->features); - - if (!nm_platform_ethtool_set_features(platform, - ethtool_state->ifindex, - features, - ethtool_state->requested, - FALSE)) - _LOGW(LOGD_DEVICE, "ethtool: failure resetting one or more offload features"); - else - _LOGD(LOGD_DEVICE, "ethtool: offload features successfully reset"); -} - -static void -_ethtool_features_set(NMDevice * self, - NMPlatform * platform, - EthtoolState * ethtool_state, - NMSettingEthtool *s_ethtool) -{ - gs_free NMEthtoolFeatureStates *features = NULL; - - if (ethtool_state->features) - _ethtool_features_reset(self, platform, ethtool_state); - - if (nm_setting_ethtool_init_features(s_ethtool, ethtool_state->requested) == 0) - return; - - features = nm_platform_ethtool_get_link_features(platform, ethtool_state->ifindex); - if (!features) { - _LOGW(LOGD_DEVICE, "ethtool: failure setting offload features (cannot read features)"); - return; - } - - if (!nm_platform_ethtool_set_features(platform, - ethtool_state->ifindex, - features, - ethtool_state->requested, - TRUE)) - _LOGW(LOGD_DEVICE, "ethtool: failure setting one or more offload features"); - else - _LOGD(LOGD_DEVICE, "ethtool: offload features successfully set"); - - ethtool_state->features = g_steal_pointer(&features); -} - -static void -_ethtool_coalesce_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) -{ - gs_free NMEthtoolCoalesceState *coalesce = NULL; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(NM_IS_PLATFORM(platform)); - nm_assert(ethtool_state); - - coalesce = g_steal_pointer(ðtool_state->coalesce); - if (!coalesce) - return; - - if (!nm_platform_ethtool_set_coalesce(platform, ethtool_state->ifindex, coalesce)) - _LOGW(LOGD_DEVICE, "ethtool: failure resetting one or more coalesce settings"); - else - _LOGD(LOGD_DEVICE, "ethtool: coalesce settings successfully reset"); -} - -static void -_ethtool_coalesce_set(NMDevice * self, - NMPlatform * platform, - EthtoolState * ethtool_state, - NMSettingEthtool *s_ethtool) -{ - NMEthtoolCoalesceState coalesce_old; - NMEthtoolCoalesceState coalesce_new; - gboolean has_old = FALSE; - GHashTable * hash; - GHashTableIter iter; - const char * name; - GVariant * variant; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(NM_IS_PLATFORM(platform)); - nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool)); - nm_assert(ethtool_state); - nm_assert(!ethtool_state->coalesce); - - hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE); - if (!hash) - return; - - g_hash_table_iter_init(&iter, hash); - while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { - NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); - - if (!nm_ethtool_id_is_coalesce(ethtool_id)) - continue; - - if (!has_old) { - if (!nm_platform_ethtool_get_link_coalesce(platform, - ethtool_state->ifindex, - &coalesce_old)) { - _LOGW(LOGD_DEVICE, "ethtool: failure getting coalesce settings (cannot read)"); - return; - } - has_old = TRUE; - coalesce_new = coalesce_old; - } - - nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); - coalesce_new.s[_NM_ETHTOOL_ID_COALESCE_AS_IDX(ethtool_id)] = g_variant_get_uint32(variant); - } - - if (!has_old) - return; - - ethtool_state->coalesce = nm_memdup(&coalesce_old, sizeof(coalesce_old)); - - if (!nm_platform_ethtool_set_coalesce(platform, ethtool_state->ifindex, &coalesce_new)) { - _LOGW(LOGD_DEVICE, "ethtool: failure setting coalesce settings"); - return; - } - - _LOGD(LOGD_DEVICE, "ethtool: coalesce settings successfully set"); -} - -static void -_ethtool_ring_reset(NMDevice *self, NMPlatform *platform, EthtoolState *ethtool_state) -{ - gs_free NMEthtoolRingState *ring = NULL; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(NM_IS_PLATFORM(platform)); - nm_assert(ethtool_state); - - ring = g_steal_pointer(ðtool_state->ring); - if (!ring) - return; - - if (!nm_platform_ethtool_set_ring(platform, ethtool_state->ifindex, ring)) - _LOGW(LOGD_DEVICE, "ethtool: failure resetting one or more ring settings"); - else - _LOGD(LOGD_DEVICE, "ethtool: ring settings successfully reset"); -} - -static void -_ethtool_ring_set(NMDevice * self, - NMPlatform * platform, - EthtoolState * ethtool_state, - NMSettingEthtool *s_ethtool) -{ - NMEthtoolRingState ring_old; - NMEthtoolRingState ring_new; - GHashTable * hash; - GHashTableIter iter; - const char * name; - GVariant * variant; - gboolean has_old = FALSE; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(NM_IS_PLATFORM(platform)); - nm_assert(NM_IS_SETTING_ETHTOOL(s_ethtool)); - nm_assert(ethtool_state); - nm_assert(!ethtool_state->ring); - - hash = _nm_setting_option_hash(NM_SETTING(s_ethtool), FALSE); - if (!hash) - return; - - g_hash_table_iter_init(&iter, hash); - while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { - NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); - guint32 u32; - - if (!nm_ethtool_id_is_ring(ethtool_id)) - continue; - - nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); - - if (!has_old) { - if (!nm_platform_ethtool_get_link_ring(platform, ethtool_state->ifindex, &ring_old)) { - _LOGW(LOGD_DEVICE, - "ethtool: failure setting ring options (cannot read existing setting)"); - return; - } - has_old = TRUE; - ring_new = ring_old; - } - - u32 = g_variant_get_uint32(variant); - - switch (ethtool_id) { - case NM_ETHTOOL_ID_RING_RX: - ring_new.rx_pending = u32; - break; - case NM_ETHTOOL_ID_RING_RX_JUMBO: - ring_new.rx_jumbo_pending = u32; - break; - case NM_ETHTOOL_ID_RING_RX_MINI: - ring_new.rx_mini_pending = u32; - break; - case NM_ETHTOOL_ID_RING_TX: - ring_new.tx_pending = u32; - break; - default: - nm_assert_not_reached(); - } - } - - if (!has_old) - return; - - ethtool_state->ring = nm_memdup(&ring_old, sizeof(ring_old)); - - if (!nm_platform_ethtool_set_ring(platform, ethtool_state->ifindex, &ring_new)) { - _LOGW(LOGD_DEVICE, "ethtool: failure setting ring settings"); - return; - } - - _LOGD(LOGD_DEVICE, "ethtool: ring settings successfully set"); -} - -static void -_ethtool_state_reset(NMDevice *self) -{ - NMPlatform * platform = nm_device_get_platform(self); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free EthtoolState *ethtool_state = g_steal_pointer(&priv->ethtool_state); - - if (!ethtool_state) - return; - - if (ethtool_state->features) - _ethtool_features_reset(self, platform, ethtool_state); - if (ethtool_state->coalesce) - _ethtool_coalesce_reset(self, platform, ethtool_state); - if (ethtool_state->ring) - _ethtool_ring_reset(self, platform, ethtool_state); -} - -static void -_ethtool_state_set(NMDevice *self) -{ - int ifindex; - NMPlatform * platform; - NMConnection * connection; - NMSettingEthtool *s_ethtool; - gs_free EthtoolState *ethtool_state = NULL; - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - - ifindex = nm_device_get_ip_ifindex(self); - if (ifindex <= 0) - return; - - platform = nm_device_get_platform(self); - nm_assert(platform); - - connection = nm_device_get_applied_connection(self); - if (!connection) - return; - - s_ethtool = NM_SETTING_ETHTOOL(nm_connection_get_setting(connection, NM_TYPE_SETTING_ETHTOOL)); - if (!s_ethtool) - return; - - ethtool_state = g_new0(EthtoolState, 1); - ethtool_state->ifindex = ifindex; - - _ethtool_features_set(self, platform, ethtool_state, s_ethtool); - _ethtool_coalesce_set(self, platform, ethtool_state, s_ethtool); - _ethtool_ring_set(self, platform, ethtool_state, s_ethtool); - - if (ethtool_state->features || ethtool_state->coalesce || ethtool_state->ring) - priv->ethtool_state = g_steal_pointer(ðtool_state); -} - -/*****************************************************************************/ - -static gboolean -is_loopback(NMDevice *self) -{ - return NM_IS_DEVICE_GENERIC(self) && NM_DEVICE_GET_PRIVATE(self)->ifindex == 1; -} - -gboolean -nm_device_is_vpn(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - /* NetworkManager currently treats VPN connections (loaded from NetworkManager VPN plugins) - * differently. Those are considered VPNs. - * However, some native device types may also be considered VPNs... - * - * We should avoid distinguishing between is-vpn and "regular" devices. Is an (unencrypted) - * IP tunnel a VPN? Is MACSec on top of an IP tunnel a VPN? - * Sometimes we differentiate, but avoid unless reasonable. */ - - return NM_IS_DEVICE_WIREGUARD(self); -} - -NMSettings * -nm_device_get_settings(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->settings; -} - -NMManager * -nm_device_get_manager(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->manager; -} - -NMNetns * -nm_device_get_netns(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->netns; -} - -NMDedupMultiIndex * -nm_device_get_multi_index(NMDevice *self) -{ - return nm_netns_get_multi_idx(nm_device_get_netns(self)); -} - -NMPlatform * -nm_device_get_platform(NMDevice *self) -{ - return nm_netns_get_platform(nm_device_get_netns(self)); -} - -static NMConnectivity * -concheck_get_mgr(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (G_UNLIKELY(!priv->concheck_mgr)) - priv->concheck_mgr = g_object_ref(nm_connectivity_get()); - return priv->concheck_mgr; -} - -NMIP4Config * -nm_device_ip4_config_new(NMDevice *self) -{ - return nm_ip4_config_new(nm_device_get_multi_index(self), nm_device_get_ip_ifindex(self)); -} - -NMIP6Config * -nm_device_ip6_config_new(NMDevice *self) -{ - return nm_ip6_config_new(nm_device_get_multi_index(self), nm_device_get_ip_ifindex(self)); -} - -NMIPConfig * -nm_device_ip_config_new(NMDevice *self, int addr_family) -{ - nm_assert_addr_family(addr_family); - - return addr_family == AF_INET ? (gpointer) nm_device_ip4_config_new(self) - : (gpointer) nm_device_ip6_config_new(self); -} - -NML3ConfigData * -nm_device_create_l3_config_data(NMDevice *self) -{ - int ifindex; - - nm_assert(NM_IS_DEVICE(self)); - - ifindex = nm_device_get_ip_ifindex(self); - if (ifindex <= 0) - g_return_val_if_reached(NULL); - - return nm_l3_config_data_new(nm_device_get_multi_index(self), ifindex); -} - -static void -applied_config_clear(AppliedConfig *config) -{ - g_clear_object(&config->current); - g_clear_object(&config->orig); -} - -static void -applied_config_init(AppliedConfig *config, gpointer ip_config) -{ - nm_assert(!ip_config || (!config->orig && !config->current) - || nm_ip_config_get_addr_family(ip_config) - == nm_ip_config_get_addr_family(config->orig ?: config->current)); - nm_assert(!ip_config || NM_IS_IP_CONFIG(ip_config)); - - nm_g_object_ref(ip_config); - applied_config_clear(config); - config->orig = ip_config; -} - -static void -applied_config_init_new(AppliedConfig *config, NMDevice *self, int addr_family) -{ - gs_unref_object NMIPConfig *c = nm_device_ip_config_new(self, addr_family); - - applied_config_init(config, c); -} - -static NMIPConfig * -applied_config_get_current(AppliedConfig *config) -{ - return config->current ?: config->orig; -} - -static void -applied_config_add_address(AppliedConfig *config, const NMPlatformIPAddress *address) -{ - if (config->orig) - nm_ip_config_add_address(config->orig, address); - else - nm_assert(!config->current); - - if (config->current) - nm_ip_config_add_address(config->current, address); -} - -static void -applied_config_add_nameserver(AppliedConfig *config, const NMIPAddr *ns) -{ - if (config->orig) - nm_ip_config_add_nameserver(config->orig, ns); - else - nm_assert(!config->current); - - if (config->current) - nm_ip_config_add_nameserver(config->current, ns); -} - -static void -applied_config_add_search(AppliedConfig *config, const char *new) -{ - if (config->orig) - nm_ip_config_add_search(config->orig, new); - else - nm_assert(!config->current); - - if (config->current) - nm_ip_config_add_search(config->current, new); -} - -static void -applied_config_reset_searches(AppliedConfig *config) -{ - if (config->orig) - nm_ip_config_reset_searches(config->orig); - else - nm_assert(!config->current); - - if (config->current) - nm_ip_config_reset_searches(config->current); -} - -static void -applied_config_reset_nameservers(AppliedConfig *config) -{ - if (config->orig) - nm_ip_config_reset_nameservers(config->orig); - else - nm_assert(!config->current); - - if (config->current) - nm_ip_config_reset_nameservers(config->current); -} - -/*****************************************************************************/ - -static NM_UTILS_LOOKUP_STR_DEFINE( - _sys_iface_state_to_str, - NMDeviceSysIfaceState, - NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, "external"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_ASSUME, "assume"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_MANAGED, "managed"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_SYS_IFACE_STATE_REMOVED, "removed"), ); - -NMDeviceSysIfaceState -nm_device_sys_iface_state_get(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); - - return NM_DEVICE_GET_PRIVATE(self)->sys_iface_state; -} - -gboolean -nm_device_sys_iface_state_is_external(NMDevice *self) -{ - return NM_IN_SET(nm_device_sys_iface_state_get(self), NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); -} - -gboolean -nm_device_sys_iface_state_is_external_or_assume(NMDevice *self) -{ - return NM_IN_SET(nm_device_sys_iface_state_get(self), - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME); -} - -void -nm_device_sys_iface_state_set(NMDevice *self, NMDeviceSysIfaceState sys_iface_state) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IN_SET(sys_iface_state, - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME, - NM_DEVICE_SYS_IFACE_STATE_MANAGED, - NM_DEVICE_SYS_IFACE_STATE_REMOVED)); - - priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->sys_iface_state != sys_iface_state) { - _LOGT(LOGD_DEVICE, - "sys-iface-state: %s -> %s", - _sys_iface_state_to_str(priv->sys_iface_state), - _sys_iface_state_to_str(sys_iface_state)); - priv->sys_iface_state_ = sys_iface_state; - } - - /* this function only sets a flag, no immediate actions are initiated. - * - * If you change this, make sure that all callers are fine with such actions. */ - - nm_assert(priv->sys_iface_state == sys_iface_state); -} - -static void -_active_connection_set_state_flags_full(NMDevice * self, - NMActivationStateFlags flags, - NMActivationStateFlags mask) -{ - NMActiveConnection *ac; - - ac = NM_ACTIVE_CONNECTION(nm_device_get_act_request(self)); - if (ac) - nm_active_connection_set_state_flags_full(ac, flags, mask); -} - -static void -_active_connection_set_state_flags(NMDevice *self, NMActivationStateFlags flags) -{ - _active_connection_set_state_flags_full(self, flags, flags); -} - -/*****************************************************************************/ - -void -nm_device_assume_state_get(NMDevice * self, - gboolean * out_assume_state_guess_assume, - const char **out_assume_state_connection_uuid) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - NM_SET_OUT(out_assume_state_guess_assume, priv->assume_state_guess_assume); - NM_SET_OUT(out_assume_state_connection_uuid, priv->assume_state_connection_uuid); -} - -static void -_assume_state_set(NMDevice * self, - gboolean assume_state_guess_assume, - const char *assume_state_connection_uuid) -{ - NMDevicePrivate *priv; - - nm_assert(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->assume_state_guess_assume == !!assume_state_guess_assume - && nm_streq0(priv->assume_state_connection_uuid, assume_state_connection_uuid)) - return; - - _LOGD(LOGD_DEVICE, - "assume-state: set guess-assume=%c, connection=%s%s%s", - assume_state_guess_assume ? '1' : '0', - NM_PRINT_FMT_QUOTE_STRING(assume_state_connection_uuid)); - priv->assume_state_guess_assume = assume_state_guess_assume; - g_free(priv->assume_state_connection_uuid); - priv->assume_state_connection_uuid = g_strdup(assume_state_connection_uuid); -} - -void -nm_device_assume_state_reset(NMDevice *self) -{ - g_return_if_fail(NM_IS_DEVICE(self)); - - _assume_state_set(self, FALSE, NULL); -} - -/*****************************************************************************/ - -static void -init_ip_config_dns_priority(NMDevice *self, NMIPConfig *config) -{ - const char *property; - int priority; - - property = (nm_ip_config_get_addr_family(config) == AF_INET) - ? NM_CON_DEFAULT("ipv4.dns-priority") - : NM_CON_DEFAULT("ipv6.dns-priority"); - - priority = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - property, - self, - G_MININT, - G_MAXINT, - 0); - - if (priority == 0) { - priority = - nm_device_is_vpn(self) ? NM_DNS_PRIORITY_DEFAULT_VPN : NM_DNS_PRIORITY_DEFAULT_NORMAL; - } - - nm_ip_config_set_dns_priority(config, priority); -} - -/*****************************************************************************/ - -static char * -nm_device_sysctl_ip_conf_get(NMDevice *self, int addr_family, const char *property) -{ - const char *ifname; - - nm_assert_addr_family(addr_family); - - ifname = nm_device_get_ip_iface_from_platform(self); - if (!ifname) - return NULL; - return nm_platform_sysctl_ip_conf_get(nm_device_get_platform(self), - addr_family, - ifname, - property); -} - -static gint64 -nm_device_sysctl_ip_conf_get_int_checked(NMDevice * self, - int addr_family, - const char *property, - guint base, - gint64 min, - gint64 max, - gint64 fallback) -{ - const char *ifname; - - nm_assert_addr_family(addr_family); - - ifname = nm_device_get_ip_iface_from_platform(self); - if (!ifname) { - errno = EINVAL; - return fallback; - } - return nm_platform_sysctl_ip_conf_get_int_checked(nm_device_get_platform(self), - addr_family, - ifname, - property, - base, - min, - max, - fallback); -} - -static void -set_ipv6_token(NMDevice *self, NMUtilsIPv6IfaceId iid, const char *token_str) -{ - NMPlatform * platform; - int ifindex; - const NMPlatformLink *link; - char buf[32]; - gint64 val; - - /* Setting the kernel token is not strictly necessary as the - * IPv6 address is generated in userspace. However it is - * convenient so that users can see the token with iproute - * ('ip token'). */ - platform = nm_device_get_platform(self); - ifindex = nm_device_get_ip_ifindex(self); - link = nm_platform_link_get(platform, ifindex); - - if (link && link->inet6_token.id == iid.id) { - _LOGT(LOGD_DEVICE | LOGD_IP6, "token %s already set", token_str); - return; - } - - /* The kernel allows setting a token only when 'accept_ra' - * is 1: temporarily flip it if necessary; unfortunately - * this will also generate an additional Router Solicitation - * from kernel. */ - val = nm_device_sysctl_ip_conf_get_int_checked(self, - AF_INET6, - "accept_ra", - 10, - G_MININT32, - G_MAXINT32, - 1); - if (val != 1) - nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", "1"); - - nm_platform_link_set_ipv6_token(platform, ifindex, iid); - - if (val != 1) { - nm_sprintf_buf(buf, "%d", (int) val); - nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", buf); - } -} - -gboolean -nm_device_sysctl_ip_conf_set(NMDevice * self, - int addr_family, - const char *property, - const char *value) -{ - NMPlatform * platform = nm_device_get_platform(self); - gs_free char *value_to_free = NULL; - const char * ifname; - - nm_assert_addr_family(addr_family); - - ifname = nm_device_get_ip_iface_from_platform(self); - if (!ifname) - return FALSE; - - if (!value) { - /* Set to a default value when we've got a NULL @value. */ - value_to_free = nm_platform_sysctl_ip_conf_get(platform, addr_family, "default", property); - value = value_to_free; - if (!value) - return FALSE; - } - - return nm_platform_sysctl_ip_conf_set(platform, addr_family, ifname, property, value); -} - -/*****************************************************************************/ - -gboolean -nm_device_has_capability(NMDevice *self, NMDeviceCapabilities caps) -{ - return NM_FLAGS_ANY(NM_DEVICE_GET_PRIVATE(self)->capabilities, caps); -} - -static void -_add_capabilities(NMDevice *self, NMDeviceCapabilities capabilities) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!NM_FLAGS_ALL(priv->capabilities, capabilities)) { - priv->capabilities |= capabilities; - _notify(self, PROP_CAPABILITIES); - } -} - -/*****************************************************************************/ - -static NM_UTILS_LOOKUP_STR_DEFINE(_ip_state_to_string, - NMDeviceIPState, - NM_UTILS_LOOKUP_DEFAULT_WARN("unknown"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_NONE, "none"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_WAIT, "wait"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_CONF, "conf"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_DONE, "done"), - NM_UTILS_LOOKUP_STR_ITEM(NM_DEVICE_IP_STATE_FAIL, "fail"), ); - -static void -_set_ip_state(NMDevice *self, int addr_family, NMDeviceIPState new_state) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - nm_assert_addr_family(addr_family); - - if (priv->ip_state_x[IS_IPv4] == new_state) - return; - - _LOGT(LOGD_DEVICE, - "ip%c-state: set to %d (%s)", - nm_utils_addr_family_to_char(addr_family), - (int) new_state, - _ip_state_to_string(new_state)); - - priv->ip_state_x_[IS_IPv4] = new_state; - - if (new_state == NM_DEVICE_IP_STATE_DONE) { - /* we only set the IPx_READY flag once we reach NM_DEVICE_IP_STATE_DONE state. We don't - * ever clear it, even if we later enter NM_DEVICE_IP_STATE_FAIL state. - * - * This is not documented/guaranteed behavior, but seems to make sense for now. */ - _active_connection_set_state_flags(self, - addr_family == AF_INET - ? NM_ACTIVATION_STATE_FLAG_IP4_READY - : NM_ACTIVATION_STATE_FLAG_IP6_READY); - } -} - -/*****************************************************************************/ - -const char * -nm_device_get_udi(NMDevice *self) -{ - g_return_val_if_fail(self != NULL, NULL); - - return NM_DEVICE_GET_PRIVATE(self)->udi; -} - -const char * -nm_device_get_iface(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->iface; -} - -static gboolean -_set_ifindex(NMDevice *self, int ifindex, gboolean is_ip_ifindex) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - int * p_ifindex; - - if (ifindex < 0) - ifindex = 0; - - p_ifindex = is_ip_ifindex ? &priv->ip_ifindex_ : &priv->ifindex_; - - if (*p_ifindex == ifindex) - return FALSE; - - *p_ifindex = ifindex; - - _LOGD(LOGD_DEVICE, "ifindex: set %sifindex %d", is_ip_ifindex ? "ip-" : "", ifindex); - - if (!is_ip_ifindex) - _notify(self, PROP_IFINDEX); - - return TRUE; -} - -/** - * nm_device_take_over_link: - * @self: the #NMDevice - * @ifindex: a ifindex - * @old_name: (transfer full): on return, the name of the old link, if - * the link was renamed - * @error: location to store error, or %NULL - * - * Given an existing link, move it under the control of a device. In - * particular, the link will be renamed to match the device name. If the - * link was renamed, the old name is returned in @old_name. - * - * Returns: %TRUE if the device took control of the link, %FALSE otherwise - */ -gboolean -nm_device_take_over_link(NMDevice *self, int ifindex, char **old_name, GError **error) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const NMPlatformLink *plink; - NMPlatform * platform; - - nm_assert(ifindex > 0); - NM_SET_OUT(old_name, NULL); - - if (priv->ifindex > 0 && priv->ifindex != ifindex) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "the device already has ifindex %d", - priv->ifindex); - return FALSE; - } - - platform = nm_device_get_platform(self); - plink = nm_platform_link_get(platform, ifindex); - if (!plink) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "link %d not found", ifindex); - return FALSE; - } - - if (!nm_streq(plink->name, nm_device_get_iface(self))) { - gboolean up; - gboolean success; - gs_free char *name = NULL; - - up = NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP); - name = g_strdup(plink->name); - - /* Rename the link to the device ifname */ - if (up) - nm_platform_link_set_down(platform, ifindex); - success = nm_platform_link_set_name(platform, ifindex, nm_device_get_iface(self)); - if (up) - nm_platform_link_set_up(platform, ifindex, NULL); - - if (!success) { - nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "failure renaming link %d", ifindex); - return FALSE; - } - - NM_SET_OUT(old_name, g_steal_pointer(&name)); - } - - _set_ifindex(self, ifindex, FALSE); - - return TRUE; -} - -int -nm_device_get_ifindex(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), 0); - - return NM_DEVICE_GET_PRIVATE(self)->ifindex; -} - -/** - * nm_device_is_software: - * @self: the #NMDevice - * - * Indicates if the device is a software-based virtual device without - * backing hardware, which can be added and removed programmatically. - * - * Returns: %TRUE if the device is a software-based device - */ -gboolean -nm_device_is_software(NMDevice *self) -{ - return NM_FLAGS_HAS(NM_DEVICE_GET_PRIVATE(self)->capabilities, NM_DEVICE_CAP_IS_SOFTWARE); -} - -/** - * nm_device_is_real: - * @self: the #NMDevice - * - * Returns: %TRUE if the device exists, %FALSE if the device is a placeholder - */ -gboolean -nm_device_is_real(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - return NM_DEVICE_GET_PRIVATE(self)->real; -} - -const char * -nm_device_get_ip_iface(NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(self != NULL, NULL); - - priv = NM_DEVICE_GET_PRIVATE(self); - /* If it's not set, default to iface */ - return priv->ip_iface ?: priv->iface; -} - -const char * -nm_device_get_ip_iface_from_platform(NMDevice *self) -{ - int ifindex; - - ifindex = nm_device_get_ip_ifindex(self); - if (ifindex <= 0) - return NULL; - - return nm_platform_link_get_name(nm_device_get_platform(self), ifindex); -} - -int -nm_device_get_ip_ifindex(const NMDevice *self) -{ - const NMDevicePrivate *priv; - - g_return_val_if_fail(self != NULL, 0); - - priv = NM_DEVICE_GET_PRIVATE(self); - /* If it's not set, default to ifindex */ - return priv->ip_iface ? priv->ip_ifindex : priv->ifindex; -} - -static void -_set_ip_ifindex(NMDevice *self, int ifindex, const char *ifname) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMPlatform * platform; - gboolean eq_name; - - /* normalize arguments */ - if (ifindex <= 0) { - ifindex = 0; - ifname = NULL; - } - - eq_name = nm_streq0(priv->ip_iface, ifname); - - if (eq_name && priv->ip_ifindex == ifindex) - return; - - _LOGD(LOGD_DEVICE, - "ip-ifindex: update ip-interface to %s%s%s, ifindex %d", - NM_PRINT_FMT_QUOTE_STRING(ifname), - ifindex); - - _set_ifindex(self, ifindex, TRUE); - - if (!eq_name) { - g_free(priv->ip_iface_); - priv->ip_iface_ = g_strdup(ifname); - _notify(self, PROP_IP_IFACE); - } - - if (priv->ip_ifindex > 0) { - platform = nm_device_get_platform(self); - - nm_platform_process_events_ensure_link(platform, priv->ip_ifindex, priv->ip_iface); - - if (nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) - nm_platform_link_set_user_ipv6ll_enabled(platform, priv->ip_ifindex, TRUE); - - if (!nm_platform_link_is_up(platform, priv->ip_ifindex)) - nm_platform_link_set_up(platform, priv->ip_ifindex, NULL); - } - - /* We don't care about any saved values from the old iface */ - g_hash_table_remove_all(priv->ip6_saved_properties); -} - -gboolean -nm_device_set_ip_ifindex(NMDevice *self, int ifindex) -{ - char ifname_buf[IFNAMSIZ]; - const char *ifname = NULL; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(nm_device_is_activating(self), FALSE); - - if (ifindex > 0) { - ifname = nm_platform_if_indextoname(nm_device_get_platform(self), ifindex, ifname_buf); - if (!ifname) - _LOGW(LOGD_DEVICE, "ip-ifindex: ifindex %d not found", ifindex); - } - - _set_ip_ifindex(self, ifindex, ifname); - return ifindex > 0; -} - -/** - * nm_device_set_ip_iface: - * @self: the #NMDevice - * @ifname: the new IP interface name - * - * Updates the IP interface name and possibly the ifindex. - * - * Returns: %TRUE if an interface with name @ifname exists, - * and %FALSE, if @ifname is %NULL or no such interface exists. - */ -gboolean -nm_device_set_ip_iface(NMDevice *self, const char *ifname) -{ - int ifindex = 0; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(nm_device_is_activating(self), FALSE); - - if (ifname) { - ifindex = nm_platform_if_nametoindex(nm_device_get_platform(self), ifname); - if (ifindex <= 0) - _LOGW(LOGD_DEVICE, "ip-ifindex: ifname %s not found", ifname); - } - - _set_ip_ifindex(self, ifindex, ifname); - return ifindex > 0; -} - -/*****************************************************************************/ - -int -nm_device_parent_get_ifindex(NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), 0); - - priv = NM_DEVICE_GET_PRIVATE(self); - return priv->parent_ifindex; -} - -NMDevice * -nm_device_parent_get_device(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->parent_device.obj; -} - -static void -parent_changed_notify(NMDevice *self, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent) -{ - /* empty handler to allow subclasses to always chain up the virtual function. */ -} - -static gboolean -_parent_set_ifindex(NMDevice *self, int parent_ifindex, gboolean force_check) -{ - NMDevicePrivate *priv; - NMDevice * parent_device; - gboolean changed = FALSE; - int old_ifindex; - gs_unref_object NMDevice *old_device = NULL; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (parent_ifindex <= 0) - parent_ifindex = 0; - - old_ifindex = priv->parent_ifindex; - - if (priv->parent_ifindex == parent_ifindex) { - if (parent_ifindex > 0) { - if (!force_check && priv->parent_device.obj - && nm_device_get_ifindex(priv->parent_device.obj) == parent_ifindex) - return FALSE; - } else { - if (!priv->parent_device.obj) - return FALSE; - } - } else { - priv->parent_ifindex = parent_ifindex; - changed = TRUE; - } - - if (parent_ifindex > 0) { - parent_device = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, parent_ifindex); - if (parent_device == self) - parent_device = NULL; - } else - parent_device = NULL; - - if (parent_device != priv->parent_device.obj) { - old_device = nm_g_object_ref(priv->parent_device.obj); - nm_dbus_track_obj_path_set(&priv->parent_device, parent_device, TRUE); - changed = TRUE; - } - - if (changed) { - if (priv->parent_ifindex <= 0) - _LOGD(LOGD_DEVICE, "parent: clear"); - else if (!priv->parent_device.obj) - _LOGD(LOGD_DEVICE, "parent: ifindex %d, no device", priv->parent_ifindex); - else { - _LOGD(LOGD_DEVICE, - "parent: ifindex %d, device %p, %s", - priv->parent_ifindex, - priv->parent_device.obj, - nm_device_get_iface(priv->parent_device.obj)); - } - - NM_DEVICE_GET_CLASS(self)->parent_changed_notify(self, - old_ifindex, - old_device, - priv->parent_ifindex, - priv->parent_device.obj); - } - return changed; -} - -void -nm_device_parent_set_ifindex(NMDevice *self, int parent_ifindex) -{ - _parent_set_ifindex(self, parent_ifindex, FALSE); -} - -gboolean -nm_device_parent_notify_changed(NMDevice *self, NMDevice *change_candidate, gboolean device_removed) -{ - NMDevicePrivate *priv; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(NM_IS_DEVICE(change_candidate)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->parent_ifindex > 0) { - if (priv->parent_device.obj == change_candidate - || priv->parent_ifindex == nm_device_get_ifindex(change_candidate)) - return _parent_set_ifindex(self, priv->parent_ifindex, device_removed); - } - return FALSE; -} - -/*****************************************************************************/ - -const char * -nm_device_parent_find_for_connection(NMDevice *self, const char *current_setting_parent) -{ - const char *new_parent; - NMDevice * parent_device; - - parent_device = nm_device_parent_get_device(self); - if (!parent_device) - return NULL; - - new_parent = nm_device_get_iface(parent_device); - if (!new_parent) - return NULL; - - if (current_setting_parent && !nm_streq(current_setting_parent, new_parent) - && nm_utils_is_uuid(current_setting_parent)) { - NMSettingsConnection *parent_connection; - - /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = nm_settings_get_connection_by_uuid(nm_device_get_settings(self), - current_setting_parent); - if (parent_connection - && nm_device_check_connection_compatible( - parent_device, - nm_settings_connection_get_connection(parent_connection), - NULL)) - return current_setting_parent; - } - - return new_parent; -} - -/*****************************************************************************/ - -static void -_stats_update_counters(NMDevice *self, guint64 tx_bytes, guint64 rx_bytes) -{ - NMDevicePrivate *priv; - gboolean tx_changed = FALSE; - gboolean rx_changed = FALSE; - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->stats.tx_bytes != tx_bytes) { - priv->stats.tx_bytes = tx_bytes; - tx_changed = TRUE; - } - if (priv->stats.rx_bytes != rx_bytes) { - priv->stats.rx_bytes = rx_bytes; - rx_changed = TRUE; - } - - nm_gobject_notify_together(self, - tx_changed ? PROP_STATISTICS_TX_BYTES : PROP_0, - rx_changed ? PROP_STATISTICS_RX_BYTES : PROP_0); -} - -static void -_stats_update_counters_from_pllink(NMDevice *self, const NMPlatformLink *pllink) -{ - _stats_update_counters(self, pllink->tx_bytes, pllink->rx_bytes); -} - -static gboolean -_stats_timeout_cb(gpointer user_data) -{ - NMDevice *self = user_data; - int ifindex; - - ifindex = nm_device_get_ip_ifindex(self); - - _LOGT(LOGD_DEVICE, "stats: refresh %d", ifindex); - - if (ifindex > 0) - nm_platform_link_refresh(nm_device_get_platform(self), ifindex); - - return G_SOURCE_CONTINUE; -} - -static guint -_stats_refresh_rate_real(guint refresh_rate_ms) -{ - const guint STATS_REFRESH_RATE_MS_MIN = 200; - - if (refresh_rate_ms == 0) - return 0; - - if (refresh_rate_ms < STATS_REFRESH_RATE_MS_MIN) { - /* you cannot set the refresh-rate arbitrarily small. E.g. - * setting to 1ms is just killing. Have a lowest number. */ - return STATS_REFRESH_RATE_MS_MIN; - } - - return refresh_rate_ms; -} - -static void -_stats_set_refresh_rate(NMDevice *self, guint refresh_rate_ms) -{ - NMDevicePrivate *priv; - int ifindex; - guint old_rate; - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->stats.refresh_rate_ms == refresh_rate_ms) - return; - - old_rate = priv->stats.refresh_rate_ms; - priv->stats.refresh_rate_ms = refresh_rate_ms; - _notify(self, PROP_STATISTICS_REFRESH_RATE_MS); - - _LOGD(LOGD_DEVICE, "stats: set refresh to %u ms", priv->stats.refresh_rate_ms); - - if (!nm_device_is_real(self)) - return; - - refresh_rate_ms = _stats_refresh_rate_real(refresh_rate_ms); - if (_stats_refresh_rate_real(old_rate) == refresh_rate_ms) - return; - - nm_clear_g_source(&priv->stats.timeout_id); - - if (!refresh_rate_ms) - return; - - /* trigger an initial refresh of the data whenever the refresh-rate changes. - * As we process the result in an idle handler with device_link_changed(), - * we don't get the result right away. */ - ifindex = nm_device_get_ip_ifindex(self); - if (ifindex > 0) - nm_platform_link_refresh(nm_device_get_platform(self), ifindex); - - priv->stats.timeout_id = g_timeout_add(refresh_rate_ms, _stats_timeout_cb, self); -} - -/*****************************************************************************/ - -static gboolean -get_ip_iface_identifier(NMDevice *self, NMUtilsIPv6IfaceId *out_iid) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMPlatform * platform = nm_device_get_platform(self); - const NMPlatformLink *pllink; - const guint8 * hwaddr; - guint8 pseudo_hwaddr[ETH_ALEN]; - gsize hwaddr_len; - int ifindex; - gboolean success; - - /* If we get here, we *must* have a kernel netdev, which implies an ifindex */ - ifindex = nm_device_get_ip_ifindex(self); - g_return_val_if_fail(ifindex > 0, FALSE); - - pllink = nm_platform_link_get(platform, ifindex); - if (!pllink || NM_IN_SET(pllink->type, NM_LINK_TYPE_NONE, NM_LINK_TYPE_UNKNOWN)) - return FALSE; - - hwaddr = nmp_link_address_get(&pllink->l_address, &hwaddr_len); - if (hwaddr_len <= 0) - return FALSE; - - if (pllink->type == NM_LINK_TYPE_6LOWPAN) { - /* If the underlying IEEE 802.15.4 device has a short address we generate - * a "pseudo 48-bit address" that's to be used in the same fashion as a - * wired Ethernet address. The mechanism is specified in Section 6. of - * RFC 4944 */ - guint16 pan_id; - guint16 short_addr; - - short_addr = nm_platform_wpan_get_short_addr(platform, pllink->parent); - if (short_addr != G_MAXUINT16) { - pan_id = nm_platform_wpan_get_pan_id(platform, pllink->parent); - pseudo_hwaddr[0] = short_addr & 0xff; - pseudo_hwaddr[1] = (short_addr >> 8) & 0xff; - pseudo_hwaddr[2] = 0; - pseudo_hwaddr[3] = 0; - pseudo_hwaddr[4] = pan_id & 0xff; - pseudo_hwaddr[5] = (pan_id >> 8) & 0xff; - - hwaddr = pseudo_hwaddr; - hwaddr_len = G_N_ELEMENTS(pseudo_hwaddr); - } - } - - success = nm_utils_get_ipv6_interface_identifier(pllink->type, - hwaddr, - hwaddr_len, - priv->dev_id, - out_iid); - if (!success) { - _LOGW(LOGD_PLATFORM, - "failed to generate interface identifier " - "for link type %u hwaddr_len %zu", - pllink->type, - hwaddr_len); - } - return success; -} - -/** - * nm_device_get_ip_iface_identifier: - * @self: an #NMDevice - * @iid: where to place the interface identifier - * @ignore_token: force creation of a non-tokenized address - * - * Return the interface's identifier for the EUI64 address generation mode. - * It's either a manually set token or and identifier generated in a - * hardware-specific way. - * - * Unless @ignore_token is set the token is preferred. That is the case - * for link-local addresses (to mimic kernel behavior). - * - * Returns: #TRUE if the @iid could be set - */ -static gboolean -nm_device_get_ip_iface_identifier(NMDevice *self, NMUtilsIPv6IfaceId *iid, gboolean ignore_token) -{ - NMSettingIP6Config *s_ip6; - const char * token = NULL; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - if (!ignore_token) { - s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); - - g_return_val_if_fail(s_ip6, FALSE); - - token = nm_setting_ip6_config_get_token(s_ip6); - } - if (token) - return nm_utils_ipv6_interface_identifier_get_from_token(iid, token); - else - return NM_DEVICE_GET_CLASS(self)->get_ip_iface_identifier(self, iid); -} - -const char * -nm_device_get_driver(NMDevice *self) -{ - g_return_val_if_fail(self != NULL, NULL); - - return NM_DEVICE_GET_PRIVATE(self)->driver; -} - -const char * -nm_device_get_driver_version(NMDevice *self) -{ - g_return_val_if_fail(self != NULL, NULL); - - return NM_DEVICE_GET_PRIVATE(self)->driver_version; -} - -NMDeviceType -nm_device_get_device_type(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_TYPE_UNKNOWN); - - return NM_DEVICE_GET_PRIVATE(self)->type; -} - -NMLinkType -nm_device_get_link_type(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NM_LINK_TYPE_UNKNOWN); - - return NM_DEVICE_GET_PRIVATE(self)->link_type; -} - -/** - * nm_device_get_metered: - * @setting: the #NMDevice - * - * Returns: the #NMDevice:metered property of the device. - * - * Since: 1.2 - **/ -NMMetered -nm_device_get_metered(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NM_METERED_UNKNOWN); - - return NM_DEVICE_GET_PRIVATE(self)->metered; -} - -guint32 -nm_device_get_route_metric_default(NMDeviceType device_type) -{ - /* Device 'priority' is used for the default route-metric and is based on - * the device type. The settings ipv4.route-metric and ipv6.route-metric - * can overwrite this default. - * - * For both IPv4 and IPv6 we use the same default values. - * - * The route-metric is used for the metric of the routes of device. - * This also applies to the default route. Therefore it affects also - * which device is the "best". - * - * For comparison, note that iproute2 by default adds IPv4 routes with - * metric 0, and IPv6 routes with metric 1024. The latter is the IPv6 - * "user default" in the kernel (NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6). - * In kernel, the full uint32_t range is available for route - * metrics (except for IPv6, where 0 means 1024). - */ - - switch (device_type) { - /* 50 is also used for VPN plugins (NM_VPN_ROUTE_METRIC_DEFAULT). - * - * Note that returning 50 from this function means that this device-type is - * in some aspects a VPN. */ - case NM_DEVICE_TYPE_WIREGUARD: - return NM_VPN_ROUTE_METRIC_DEFAULT; - - case NM_DEVICE_TYPE_ETHERNET: - case NM_DEVICE_TYPE_VETH: - return 100; - case NM_DEVICE_TYPE_MACSEC: - return 125; - case NM_DEVICE_TYPE_INFINIBAND: - return 150; - case NM_DEVICE_TYPE_ADSL: - return 200; - case NM_DEVICE_TYPE_WIMAX: - return 250; - case NM_DEVICE_TYPE_BOND: - return 300; - case NM_DEVICE_TYPE_TEAM: - return 350; - case NM_DEVICE_TYPE_VLAN: - return 400; - case NM_DEVICE_TYPE_MACVLAN: - return 410; - case NM_DEVICE_TYPE_BRIDGE: - return 425; - case NM_DEVICE_TYPE_TUN: - return 450; - case NM_DEVICE_TYPE_PPP: - return 460; - case NM_DEVICE_TYPE_VRF: - return 470; - case NM_DEVICE_TYPE_VXLAN: - return 500; - case NM_DEVICE_TYPE_DUMMY: - return 550; - case NM_DEVICE_TYPE_WIFI: - return 600; - case NM_DEVICE_TYPE_OLPC_MESH: - return 650; - case NM_DEVICE_TYPE_IP_TUNNEL: - return 675; - case NM_DEVICE_TYPE_MODEM: - return 700; - case NM_DEVICE_TYPE_BT: - return 750; - case NM_DEVICE_TYPE_6LOWPAN: - return 775; - case NM_DEVICE_TYPE_OVS_BRIDGE: - case NM_DEVICE_TYPE_OVS_INTERFACE: - case NM_DEVICE_TYPE_OVS_PORT: - return 800; - case NM_DEVICE_TYPE_WPAN: - return 850; - case NM_DEVICE_TYPE_WIFI_P2P: - case NM_DEVICE_TYPE_GENERIC: - return 950; - case NM_DEVICE_TYPE_UNKNOWN: - return 10000; - case NM_DEVICE_TYPE_UNUSED1: - case NM_DEVICE_TYPE_UNUSED2: - /* omit default: to get compiler warning about missing switch cases */ - break; - } - return 11000; -} - -static gboolean -default_route_metric_penalty_detect(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - /* currently we don't differentiate between IPv4 and IPv6 when detecting - * connectivity. */ - if (priv->concheck_x[IS_IPv4].state != NM_CONNECTIVITY_FULL - && nm_connectivity_check_enabled(concheck_get_mgr(self))) - return TRUE; - - return FALSE; -} - -static guint32 -default_route_metric_penalty_get(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert_addr_family(addr_family); - - if (addr_family == AF_INET ? priv->default_route_metric_penalty_ip4_has - : priv->default_route_metric_penalty_ip6_has) - return 20000; - return 0; -} - -guint32 -nm_device_get_route_metric(NMDevice *self, int addr_family) -{ - gint64 route_metric; - NMSettingIPConfig *s_ip; - NMConnection * connection; - const char * property; - - g_return_val_if_fail(NM_IS_DEVICE(self), G_MAXUINT32); - g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), G_MAXUINT32); - - connection = nm_device_get_applied_connection(self); - if (connection) { - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - - /* Slave interfaces don't have IP settings, but we may get here when - * external changes are made or when noticing IP changes when starting - * the slave connection. - */ - if (s_ip) { - route_metric = nm_setting_ip_config_get_route_metric(s_ip); - if (route_metric >= 0) - goto out; - } - } - - /* use the current NMConfigData, which makes this configuration reloadable. - * Note that that means that the route-metric might change between SIGHUP. - * You must cache the returned value if that is a problem. */ - property = addr_family == AF_INET ? NM_CON_DEFAULT("ipv4.route-metric") - : NM_CON_DEFAULT("ipv6.route-metric"); - route_metric = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - property, - self, - 0, - G_MAXUINT32, - -1); - if (route_metric >= 0) - goto out; - - route_metric = nm_manager_device_route_metric_reserve(NM_MANAGER_GET, - nm_device_get_ip_ifindex(self), - nm_device_get_device_type(self)); -out: - return nm_utils_ip_route_metric_normalize(addr_family, route_metric); -} - -guint32 -nm_device_get_route_table(NMDevice *self, int addr_family) -{ - guint32 route_table; - - g_return_val_if_fail(NM_IS_DEVICE(self), RT_TABLE_MAIN); - - route_table = _prop_get_ipvx_route_table(self, addr_family); - return route_table ?: (guint32) RT_TABLE_MAIN; -} - -static NMIPRouteTableSyncMode -_get_route_table_sync_mode_stateful(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMDedupMultiIter ipconf_iter; - gboolean all_sync_now; - gboolean all_sync_eff; - - all_sync_now = _prop_get_ipvx_route_table(self, addr_family) != 0u; - - if (!all_sync_now) { - /* If there's a local route switch to all-sync in order - * to properly manage the local table */ - if (addr_family == AF_INET) { - const NMPlatformIP4Route *route; - - nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->con_ip_config_4, &route) { - if (nm_platform_route_type_uncoerce(route->type_coerced) == RTN_LOCAL) { - all_sync_now = TRUE; - break; - } - } - } else { - const NMPlatformIP6Route *route; - - nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->con_ip_config_6, &route) { - if (nm_platform_route_type_uncoerce(route->type_coerced) == RTN_LOCAL) { - all_sync_now = TRUE; - break; - } - } - } - } - - if (all_sync_now) - all_sync_eff = TRUE; - else { - /* When we change from all-sync to no all-sync, we do a last all-sync one - * more time. For that, we determine the effective all-state based on the - * cached/previous all-sync flag. - * - * The purpose of this is to support reapply of route-table (and thus the - * all-sync mode). If reapply toggles from all-sync to no-all-sync, we must - * sync one last time. */ - if (addr_family == AF_INET) - all_sync_eff = priv->v4_route_table_all_sync_before; - else - all_sync_eff = priv->v6_route_table_all_sync_before; - } - - if (addr_family == AF_INET) - priv->v4_route_table_all_sync_before = all_sync_now; - else - priv->v6_route_table_all_sync_before = all_sync_now; - - return all_sync_eff ? NM_IP_ROUTE_TABLE_SYNC_MODE_ALL : NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN; -} - -const NMPObject * -nm_device_get_best_default_route(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - switch (addr_family) { - case AF_INET: - return priv->ip_config_4 ? nm_ip4_config_best_default_route_get(priv->ip_config_4) : NULL; - case AF_INET6: - return priv->ip_config_6 ? nm_ip6_config_best_default_route_get(priv->ip_config_6) : NULL; - case AF_UNSPEC: - return (priv->ip_config_4 ? nm_ip4_config_best_default_route_get(priv->ip_config_4) : NULL) - ?: (priv->ip_config_6 ? nm_ip6_config_best_default_route_get(priv->ip_config_6) - : NULL); - default: - g_return_val_if_reached(NULL); - } -} - -const char * -nm_device_get_type_desc(NMDevice *self) -{ - g_return_val_if_fail(self != NULL, NULL); - - return NM_DEVICE_GET_PRIVATE(self)->type_desc; -} - -const char * -nm_device_get_type_description(NMDevice *self) -{ - g_return_val_if_fail(self != NULL, NULL); - - /* Beware: this function should return the same - * value as nm_device_get_type_description() in libnm. */ - - return NM_DEVICE_GET_CLASS(self)->get_type_description(self); -} - -static const char * -get_type_description(NMDevice *self) -{ - NMDeviceClass *klass; - - nm_assert(NM_IS_DEVICE(self)); - - /* the default implementation for the description just returns the (modified) - * class name and depends entirely on the type of self. Note that we cache the - * description in the klass itself. - * - * Also note, that as the GObject class gets inited, it inherrits the fields - * of the parent class. That means, if NMDeviceVethClass was initialized after - * NMDeviceEthernetClass already has the description cached in the class - * (because we already fetched the description for an ethernet device), - * then default_type_description will wrongly contain "ethernet". - * To avoid that, and catch the situation, also cache the klass for - * which the description was cached. If that doesn't match, it was - * inherited and we need to reset it. */ - klass = NM_DEVICE_GET_CLASS(self); - if (G_UNLIKELY(klass->default_type_description_klass != klass)) { - const char *typename; - gs_free char *s = NULL; - - typename = G_OBJECT_TYPE_NAME(self); - if (g_str_has_prefix(typename, "NMDevice")) - typename += 8; - s = g_ascii_strdown(typename, -1); - klass->default_type_description = g_intern_string(s); - klass->default_type_description_klass = klass; - } - - nm_assert(klass->default_type_description); - return klass->default_type_description; -} - -gboolean -nm_device_has_carrier(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->carrier; -} - -NMActRequest * -nm_device_get_act_request(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->act_request.obj; -} - -NMActivationStateFlags -nm_device_get_activation_state_flags(NMDevice *self) -{ - NMActRequest *ac; - - g_return_val_if_fail(NM_IS_DEVICE(self), NM_ACTIVATION_STATE_FLAG_NONE); - - ac = NM_DEVICE_GET_PRIVATE(self)->act_request.obj; - if (!ac) - return NM_ACTIVATION_STATE_FLAG_NONE; - return nm_active_connection_get_state_flags(NM_ACTIVE_CONNECTION(ac)); -} - -NMSettingsConnection * -nm_device_get_settings_connection(NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - priv = NM_DEVICE_GET_PRIVATE(self); - - return priv->act_request.obj ? nm_act_request_get_settings_connection(priv->act_request.obj) - : NULL; -} - -NMConnection * -nm_device_get_settings_connection_get_connection(NMDevice *self) -{ - NMSettingsConnection *sett_con; - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->act_request.obj) - return NULL; - - sett_con = nm_act_request_get_settings_connection(priv->act_request.obj); - if (!sett_con) - return NULL; - - return nm_settings_connection_get_connection(sett_con); -} - -NMConnection * -nm_device_get_applied_connection(NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - priv = NM_DEVICE_GET_PRIVATE(self); - - return priv->act_request.obj ? nm_act_request_get_applied_connection(priv->act_request.obj) - : NULL; -} - -gboolean -nm_device_has_unmodified_applied_connection(NMDevice *self, NMSettingCompareFlags compare_flags) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->act_request.obj) - return FALSE; - - return nm_active_connection_has_unmodified_applied_connection( - (NMActiveConnection *) priv->act_request.obj, - compare_flags); -} - -gpointer -nm_device_get_applied_setting(NMDevice *self, GType setting_type) -{ - NMConnection *connection; - - connection = nm_device_get_applied_connection(self); - return connection ? nm_connection_get_setting(connection, setting_type) : NULL; -} - -RfKillType -nm_device_get_rfkill_type(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - return NM_DEVICE_GET_PRIVATE(self)->rfkill_type; -} - -static const char * -nm_device_get_physical_port_id(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->physical_port_id; -} - -/*****************************************************************************/ - -typedef enum { - CONCHECK_SCHEDULE_UPDATE_INTERVAL, - CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART, - CONCHECK_SCHEDULE_CHECK_EXTERNAL, - CONCHECK_SCHEDULE_CHECK_PERIODIC, - CONCHECK_SCHEDULE_RETURNED_MIN, - CONCHECK_SCHEDULE_RETURNED_BUMP, - CONCHECK_SCHEDULE_RETURNED_MAX, -} ConcheckScheduleMode; - -static NMDeviceConnectivityHandle *concheck_start(NMDevice * self, - int addr_family, - NMDeviceConnectivityCallback callback, - gpointer user_data, - gboolean is_periodic); - -static void -concheck_periodic_schedule_set(NMDevice *self, int addr_family, ConcheckScheduleMode mode); - -static gboolean -_concheck_periodic_timeout_cb(NMDevice *self, int addr_family) -{ - _LOGt(LOGD_CONCHECK, - "connectivity: [IPv%c] periodic timeout", - nm_utils_addr_family_to_char(addr_family)); - concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_CHECK_PERIODIC); - return G_SOURCE_REMOVE; -} - -static gboolean -concheck_ip4_periodic_timeout_cb(gpointer user_data) -{ - return _concheck_periodic_timeout_cb(user_data, AF_INET); -} - -static gboolean -concheck_ip6_periodic_timeout_cb(gpointer user_data) -{ - return _concheck_periodic_timeout_cb(user_data, AF_INET6); -} - -static gboolean -concheck_is_possible(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!nm_device_is_real(self) || is_loopback(self)) - return FALSE; - - /* we enable periodic checks for every device state (except UNKNOWN). Especially with - * unmanaged devices, it is interesting to know whether we have connectivity on that device. */ - if (priv->state == NM_DEVICE_STATE_UNKNOWN) - return FALSE; - - return TRUE; -} - -static gboolean -concheck_periodic_schedule_do(NMDevice *self, int addr_family, gint64 now_ns) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean periodic_check_disabled = FALSE; - gint64 expiry, tdiff; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - /* we always cancel whatever was pending. */ - if (nm_clear_g_source(&priv->concheck_x[IS_IPv4].p_cur_id)) - periodic_check_disabled = TRUE; - - if (priv->concheck_x[IS_IPv4].p_max_interval == 0) { - /* periodic checks are disabled */ - goto out; - } - - if (!concheck_is_possible(self)) - goto out; - - nm_assert(now_ns > 0); - nm_assert(priv->concheck_x[IS_IPv4].p_cur_interval > 0); - - /* we schedule the timeout based on our current settings cur-interval and cur-basetime. - * Before calling concheck_periodic_schedule_do(), make sure that these properties are - * correct. */ - - expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns - + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - tdiff = expiry - now_ns; - - _LOGT(LOGD_CONCHECK, - "connectivity: [IPv%c] periodic-check: %sscheduled in %lld milliseconds (%u seconds " - "interval)", - nm_utils_addr_family_to_char(addr_family), - periodic_check_disabled ? "re-" : "", - (long long) (tdiff / NM_UTILS_NSEC_PER_MSEC), - priv->concheck_x[IS_IPv4].p_cur_interval); - - priv->concheck_x[IS_IPv4].p_cur_id = - g_timeout_add(NM_MAX((gint64) 0, tdiff) / NM_UTILS_NSEC_PER_MSEC, - IS_IPv4 ? concheck_ip4_periodic_timeout_cb : concheck_ip6_periodic_timeout_cb, - self); - return TRUE; -out: - if (periodic_check_disabled) { - _LOGT(LOGD_CONCHECK, - "connectivity: [IPv%c] periodic-check: unscheduled", - nm_utils_addr_family_to_char(addr_family)); - } - return FALSE; -} - -#define CONCHECK_P_PROBE_INTERVAL 1 - -static void -concheck_periodic_schedule_set(NMDevice *self, int addr_family, ConcheckScheduleMode mode) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gint64 new_expiry, exp_expiry, cur_expiry, tdiff; - gint64 now_ns = 0; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - if (priv->concheck_x[IS_IPv4].p_max_interval == 0) { - /* periodic check is disabled. Nothing to do. */ - return; - } - - if (!priv->concheck_x[IS_IPv4].p_cur_id) { - /* we currently don't have a timeout scheduled. No need to reschedule - * another one... */ - if (NM_IN_SET(mode, - CONCHECK_SCHEDULE_UPDATE_INTERVAL, - CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART)) { - /* ... unless, we are about to start periodic checks after update-interval. - * In this case, fall through and restart the periodic checks below. */ - mode = CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART; - } else - return; - } - - switch (mode) { - case CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART: - priv->concheck_x[IS_IPv4].p_cur_interval = - NM_MIN(priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL); - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = - nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns); - if (concheck_periodic_schedule_do(self, addr_family, now_ns)) - concheck_start(self, addr_family, NULL, NULL, TRUE); - return; - - case CONCHECK_SCHEDULE_UPDATE_INTERVAL: - /* called with "UPDATE_INTERVAL" and already have a p_cur_id scheduled. */ - - nm_assert(priv->concheck_x[IS_IPv4].p_max_interval > 0); - nm_assert(priv->concheck_x[IS_IPv4].p_cur_interval > 0); - - if (priv->concheck_x[IS_IPv4].p_cur_interval <= priv->concheck_x[IS_IPv4].p_max_interval) { - /* we currently have a shorter interval set, than what we now have. Either, - * because we are probing, or because the previous max interval was shorter. - * - * Either way, the current timer is set just fine. Nothing to do, we will - * probe our way up. */ - return; - } - - cur_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns - + (priv->concheck_x[IS_IPv4].p_max_interval * NM_UTILS_NSEC_PER_SEC); - nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns); - - priv->concheck_x[IS_IPv4].p_cur_interval = priv->concheck_x[IS_IPv4].p_max_interval; - if (cur_expiry <= now_ns) { - /* Since the last time we scheduled a periodic check, already more than the - * new max_interval passed. We need to start a check right away (and - * schedule a timeout in cur-interval in the future). */ - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = now_ns; - if (concheck_periodic_schedule_do(self, addr_family, now_ns)) - concheck_start(self, addr_family, NULL, NULL, TRUE); - } else { - /* we are reducing the max-interval to a shorter interval that we have currently - * scheduled (with cur_interval). - * - * However, since the last time we scheduled the check, not even the new max-interval - * expired. All we need to do, is reschedule the timer to expire sooner. The cur_basetime - * is unchanged. */ - concheck_periodic_schedule_do(self, addr_family, now_ns); - } - return; - - case CONCHECK_SCHEDULE_CHECK_EXTERNAL: - /* a external connectivity check delays our periodic check. We reset the counter. */ - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = - nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns); - concheck_periodic_schedule_do(self, addr_family, now_ns); - return; - - case CONCHECK_SCHEDULE_CHECK_PERIODIC: - { - gboolean any_periodic_pending; - NMDeviceConnectivityHandle *handle; - guint old_interval = priv->concheck_x[IS_IPv4].p_cur_interval; - - any_periodic_pending = FALSE; - c_list_for_each_entry (handle, &priv->concheck_lst_head, concheck_lst) { - if (handle->addr_family != addr_family) - continue; - if (handle->is_periodic_bump) { - handle->is_periodic_bump = FALSE; - handle->is_periodic_bump_on_complete = FALSE; - any_periodic_pending = TRUE; - } - } - if (any_periodic_pending) { - /* we reached a timeout to schedule a new periodic request, however we still - * have period requests pending that didn't complete yet. We need to bump the - * interval already. */ - priv->concheck_x[IS_IPv4].p_cur_interval = - NM_MIN(old_interval * 2, priv->concheck_x[IS_IPv4].p_max_interval); - } - - /* we just reached a timeout. The expected expiry (exp_expiry) should be - * pretty close to now_ns. - * - * We want to reschedule the timeout at exp_expiry (aka now) + cur_interval. */ - nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns); - exp_expiry = - priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (old_interval * NM_UTILS_NSEC_PER_SEC); - new_expiry = - exp_expiry + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - tdiff = NM_MAX(new_expiry - now_ns, 0); - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = - (now_ns + tdiff) - (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - if (concheck_periodic_schedule_do(self, addr_family, now_ns)) { - handle = concheck_start(self, addr_family, NULL, NULL, TRUE); - if (old_interval != priv->concheck_x[IS_IPv4].p_cur_interval) { - /* we just bumped the interval already when scheduling this check. - * When the handle returns, don't bump a second time. - * - * But if we reach the timeout again before the handle returns (this - * code here) we will still bump the interval. */ - handle->is_periodic_bump_on_complete = FALSE; - } - } - return; - } - - /* we just got an event that we lost connectivity (that is, concheck returned). We reset - * the interval to min/max or increase the probe interval (bump). */ - case CONCHECK_SCHEDULE_RETURNED_MIN: - priv->concheck_x[IS_IPv4].p_cur_interval = - NM_MIN(priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL); - break; - case CONCHECK_SCHEDULE_RETURNED_MAX: - priv->concheck_x[IS_IPv4].p_cur_interval = priv->concheck_x[IS_IPv4].p_max_interval; - break; - case CONCHECK_SCHEDULE_RETURNED_BUMP: - priv->concheck_x[IS_IPv4].p_cur_interval = - NM_MIN(priv->concheck_x[IS_IPv4].p_cur_interval * 2, - priv->concheck_x[IS_IPv4].p_max_interval); - break; - } - - /* we are here, because we returned from a connectivity check and adjust the current interval. - * - * But note that we calculate the new timeout based on the time when we scheduled the - * last check, instead of counting from now. The reason is that we want that the times - * when we schedule checks be at precise intervals, without including the time it took for - * the connectivity check. */ - new_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns - + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - tdiff = NM_MAX(new_expiry - nm_utils_get_monotonic_timestamp_nsec_cached(&now_ns), 0); - priv->concheck_x[IS_IPv4].p_cur_basetime_ns = - now_ns + tdiff - (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NSEC_PER_SEC); - concheck_periodic_schedule_do(self, addr_family, now_ns); -} - -static void -concheck_update_interval(NMDevice *self, int addr_family, gboolean check_now) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - guint new_interval; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - new_interval = nm_connectivity_get_interval(concheck_get_mgr(self)); - - new_interval = NM_MIN(new_interval, 7 * 24 * 3600); - - if (new_interval != priv->concheck_x[IS_IPv4].p_max_interval) { - _LOGT(LOGD_CONCHECK, - "connectivity: [IPv%c] periodic-check: set interval to %u seconds", - nm_utils_addr_family_to_char(addr_family), - new_interval); - priv->concheck_x[IS_IPv4].p_max_interval = new_interval; - } - - if (!new_interval) { - /* this will cancel any potentially pending timeout because max-interval is zero. - * But it logs a nice message... */ - concheck_periodic_schedule_do(self, addr_family, 0); - - /* also update the fake connectivity state. */ - concheck_update_state(self, addr_family, NM_CONNECTIVITY_FAKE, TRUE); - return; - } - - concheck_periodic_schedule_set(self, - addr_family, - check_now ? CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART - : CONCHECK_SCHEDULE_UPDATE_INTERVAL); -} - -void -nm_device_check_connectivity_update_interval(NMDevice *self) -{ - concheck_update_interval(self, AF_INET, TRUE); - concheck_update_interval(self, AF_INET6, TRUE); -} - -static void -concheck_update_state(NMDevice * self, - int addr_family, - NMConnectivityState state, - gboolean allow_periodic_bump) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - /* @state is a result of the connectivity check. We only expect a precise - * number of possible values. */ - nm_assert(NM_IN_SET(state, - NM_CONNECTIVITY_LIMITED, - NM_CONNECTIVITY_PORTAL, - NM_CONNECTIVITY_FULL, - NM_CONNECTIVITY_FAKE, - NM_CONNECTIVITY_NONE, - NM_CONNECTIVITY_ERROR)); - - if (state == NM_CONNECTIVITY_ERROR) { - /* on error, we don't change the current connectivity state, - * except making UNKNOWN to NONE. */ - state = priv->concheck_x[IS_IPv4].state; - if (state == NM_CONNECTIVITY_UNKNOWN) - state = NM_CONNECTIVITY_NONE; - } else if (state == NM_CONNECTIVITY_FAKE) { - /* If the connectivity check is disabled and we obtain a fake - * result, make an optimistic guess. */ - if (priv->state == NM_DEVICE_STATE_ACTIVATED) { - /* FIXME: the fake connectivity state depends on the availability of - * a default route. However, we have no mechanism that rechecks the - * value if a device route appears/disappears after the device - * was activated. */ - if (nm_device_get_best_default_route(self, AF_UNSPEC)) - state = NM_CONNECTIVITY_FULL; - else - state = NM_CONNECTIVITY_LIMITED; - } else - state = NM_CONNECTIVITY_NONE; - } - - if (priv->concheck_x[IS_IPv4].state == state) { - /* we got a connectivity update, but the state didn't change. If we were probing, - * we bump the probe frequency. */ - if (allow_periodic_bump) - concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_RETURNED_BUMP); - return; - } - /* we need to update the probe interval before emitting signals. Emitting - * a signal might call back into NMDevice and change the probe settings. - * So, do that first. */ - if (state == NM_CONNECTIVITY_FULL) { - /* we reached full connectivity state. Stop probing by setting the - * interval to the max. */ - concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_RETURNED_MAX); - } else if (priv->concheck_x[IS_IPv4].state == NM_CONNECTIVITY_FULL) { - /* we are about to loose connectivity. (re)start probing by setting - * the timeout interval to the min. */ - concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_RETURNED_MIN); - } else { - if (allow_periodic_bump) - concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_RETURNED_BUMP); - } - - _LOGD(LOGD_CONCHECK, - "connectivity state changed from %s to %s", - nm_connectivity_state_to_string(priv->concheck_x[IS_IPv4].state), - nm_connectivity_state_to_string(state)); - priv->concheck_x[IS_IPv4].state = state; - - _notify(self, IS_IPv4 ? PROP_IP4_CONNECTIVITY : PROP_IP6_CONNECTIVITY); - - if (priv->state == NM_DEVICE_STATE_ACTIVATED && !nm_device_sys_iface_state_is_external(self)) { - if (nm_device_get_best_default_route(self, AF_INET) - && !ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "Failed to update IPv4 route metric"); - if (nm_device_get_best_default_route(self, AF_INET6) - && !ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "Failed to update IPv6 route metric"); - } -} - -static const char * -nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family) -{ - NMDeviceClass *klass; - NMConnection * connection = nm_device_get_applied_connection(self); - const char * method; - - g_return_val_if_fail(NM_IS_CONNECTION(connection), "" /* bogus */); - nm_assert_addr_family(addr_family); - - method = nm_utils_get_ip_config_method(connection, addr_family); - - if ((addr_family == AF_INET && nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) - || (addr_family == AF_INET6 && nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO))) { - klass = NM_DEVICE_GET_CLASS(self); - if (klass->get_auto_ip_config_method) { - const char *auto_method; - - auto_method = klass->get_auto_ip_config_method(self, addr_family); - if (auto_method) - return auto_method; - } - } - - return method; -} - -static void -concheck_handle_complete(NMDeviceConnectivityHandle *handle, GError *error) -{ - const gboolean IS_IPv4 = (handle->addr_family == AF_INET); - - /* The moment we invoke the callback, we unlink it. It signals - * that @handle is handled -- as far as the callee of callback - * is concerned. */ - c_list_unlink(&handle->concheck_lst); - - if (handle->c_handle) - nm_connectivity_check_cancel(handle->c_handle); - - if (handle->callback) { - handle->callback(handle->self, - handle, - NM_DEVICE_GET_PRIVATE(handle->self)->concheck_x[IS_IPv4].state, - error, - handle->user_data); - } - - g_slice_free(NMDeviceConnectivityHandle, handle); -} - -static void -concheck_cb(NMConnectivity * connectivity, - NMConnectivityCheckHandle *c_handle, - NMConnectivityState state, - gpointer user_data) -{ - _nm_unused gs_unref_object NMDevice *self_keep_alive = NULL; - NMDevice * self; - NMDevicePrivate * priv; - NMDeviceConnectivityHandle * handle; - NMDeviceConnectivityHandle * other_handle; - gboolean handle_is_alive; - gboolean allow_periodic_bump; - gboolean any_periodic_before; - gboolean any_periodic_after; - guint64 seq; - - handle = user_data; - nm_assert(handle->c_handle == c_handle); - nm_assert(NM_IS_DEVICE(handle->self)); - - handle->c_handle = NULL; - self = handle->self; - - if (state == NM_CONNECTIVITY_CANCELLED) { - /* the only place where we nm_connectivity_check_cancel(@c_handle), is - * from inside concheck_handle_complete(). This is a recursive call, - * nothing to do. */ - _LOGT(LOGD_CONCHECK, - "connectivity: [IPv%c] complete check (seq:%llu, cancelled)", - nm_utils_addr_family_to_char(handle->addr_family), - (long long unsigned) handle->seq); - return; - } - - /* we keep NMConnectivity instance alive. It cannot be disposing. */ - nm_assert(state != NM_CONNECTIVITY_DISPOSING); - - self_keep_alive = g_object_ref(self); - - /* keep @self alive, while we invoke callbacks. */ - priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert(handle && c_list_contains(&priv->concheck_lst_head, &handle->concheck_lst)); - - seq = handle->seq; - - _LOGT(LOGD_CONCHECK, - "connectivity: [Ipv%c] complete check (seq:%llu, state:%s)", - nm_utils_addr_family_to_char(handle->addr_family), - (long long unsigned) handle->seq, - nm_connectivity_state_to_string(state)); - - /* find out, if there are any periodic checks pending (either whether they - * were scheduled before or after @handle. */ - any_periodic_before = FALSE; - any_periodic_after = FALSE; - c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { - if (other_handle->addr_family != handle->addr_family) - continue; - if (other_handle->is_periodic_bump_on_complete) { - if (other_handle->seq < seq) - any_periodic_before = TRUE; - else if (other_handle->seq > seq) - any_periodic_after = TRUE; - } - } - if (NM_IN_SET(state, NM_CONNECTIVITY_ERROR)) { - /* the request failed. We consider this periodic check only as completed if - * this was a periodic check, and there are not checks pending (either - * before or after this one). - * - * We allow_periodic_bump, if the request failed and there are - * still other requests periodic pending. */ - allow_periodic_bump = - handle->is_periodic_bump_on_complete && !any_periodic_before && !any_periodic_after; - } else { - /* the request succeeded. This marks the completion of a periodic check, - * if this handle was periodic, or any previously scheduled one (that - * we are going to complete below). */ - allow_periodic_bump = handle->is_periodic_bump_on_complete || any_periodic_before; - } - - /* first update the new state, and emit signals. */ - concheck_update_state(self, handle->addr_family, state, allow_periodic_bump); - - handle_is_alive = FALSE; - - /* we might have invoked callbacks during concheck_update_state(). The caller might have - * cancelled and thus destroyed @handle. We have to check whether handle is still alive, - * by searching it in the list of alive handles. - * - * Also, we might want to complete all pending callbacks that were started before - * @handle, as they are automatically obsoleted. */ -check_handles: - c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { - if (other_handle->addr_family != handle->addr_family) - continue; - if (other_handle->seq >= seq) { - /* it's not guaranteed that @handle is still in the list. It might already - * be canceled while invoking callbacks for a previous other_handle. - * If it is already cancelled, @handle is a dangling pointer. - * - * Since @seq is assigned uniquely and increasing, either @other_handle is - * @handle (and thus, handle is alive), or it isn't. */ - if (other_handle == handle) - handle_is_alive = TRUE; - break; - } - - nm_assert(other_handle != handle); - - if (!NM_IN_SET(state, NM_CONNECTIVITY_ERROR)) { - /* we also want to complete handles that were started before the current - * @handle. Their response is out-dated. */ - concheck_handle_complete(other_handle, NULL); - - /* we invoked callbacks, other handles might be cancelled and removed from the list. - * Need to iterate the list from the start. */ - goto check_handles; - } - } - - if (!handle_is_alive) { - /* We didn't find @handle in the list of alive handles. Thus, the handles - * was cancelled while we were invoking events. Nothing to do, and don't - * touch the dangling pointer. */ - return; - } - - concheck_handle_complete(handle, NULL); -} - -static NMDeviceConnectivityHandle * -concheck_start(NMDevice * self, - int addr_family, - NMDeviceConnectivityCallback callback, - gpointer user_data, - gboolean is_periodic) -{ - static guint64 seq_counter = 0; - NMDevicePrivate * priv; - NMDeviceConnectivityHandle *handle; - const char * ifname; - - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - priv = NM_DEVICE_GET_PRIVATE(self); - - handle = g_slice_new0(NMDeviceConnectivityHandle); - handle->seq = ++seq_counter; - handle->self = self; - handle->callback = callback; - handle->user_data = user_data; - handle->is_periodic = is_periodic; - handle->is_periodic_bump = is_periodic; - handle->is_periodic_bump_on_complete = is_periodic; - handle->addr_family = addr_family; - - c_list_link_tail(&priv->concheck_lst_head, &handle->concheck_lst); - - _LOGT(LOGD_CONCHECK, - "connectivity: [IPv%c] start check (seq:%llu%s)", - nm_utils_addr_family_to_char(addr_family), - (long long unsigned) handle->seq, - is_periodic ? ", periodic-check" : ""); - - if (addr_family == AF_INET && !priv->concheck_rp_filter_checked) { - if ((ifname = nm_device_get_ip_iface_from_platform(self))) { - gboolean due_to_all; - int val; - - val = nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(nm_device_get_platform(self), - ifname, - TRUE, - &due_to_all); - if (val == 1) { - _LOGW(LOGD_CONCHECK, - "connectivity: \"/proc/sys/net/ipv4/conf/%s/rp_filter\" is set to \"1\". " - "This might break connectivity checking for IPv4 on this device", - due_to_all ? "all" : ifname); - } - } - - /* we only check once per device. It's a warning after all. */ - priv->concheck_rp_filter_checked = TRUE; - } - - handle->c_handle = nm_connectivity_check_start(concheck_get_mgr(self), - handle->addr_family, - nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - nm_device_get_ip_iface(self), - concheck_cb, - handle); - return handle; -} - -NMDeviceConnectivityHandle * -nm_device_check_connectivity(NMDevice * self, - int addr_family, - NMDeviceConnectivityCallback callback, - gpointer user_data) -{ - if (!concheck_is_possible(self)) - return NULL; - - concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_CHECK_EXTERNAL); - return concheck_start(self, addr_family, callback, user_data, FALSE); -} - -void -nm_device_check_connectivity_cancel(NMDeviceConnectivityHandle *handle) -{ - gs_free_error GError *cancelled_error = NULL; - - g_return_if_fail(handle); - g_return_if_fail(NM_IS_DEVICE(handle->self)); - g_return_if_fail(!c_list_is_empty(&handle->concheck_lst)); - - /* nobody has access to periodic handles, and cannot cancel - * them externally. */ - nm_assert(!handle->is_periodic); - - nm_utils_error_set_cancelled(&cancelled_error, FALSE, "NMDevice"); - concheck_handle_complete(handle, cancelled_error); -} - -NMConnectivityState -nm_device_get_connectivity_state(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - g_return_val_if_fail(NM_IS_DEVICE(self), NM_CONNECTIVITY_UNKNOWN); - nm_assert_addr_family(addr_family); - - priv = NM_DEVICE_GET_PRIVATE(self); - - switch (addr_family) { - case AF_INET: - case AF_INET6: - return priv->concheck_x[IS_IPv4].state; - default: - nm_assert(addr_family == AF_UNSPEC); - return NM_MAX_WITH_CMP(nm_connectivity_state_cmp, - priv->concheck_x[0].state, - priv->concheck_x[1].state); - } -} - -/*****************************************************************************/ - -static SlaveInfo * -find_slave_info(NMDevice *self, NMDevice *slave) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - CList * iter; - SlaveInfo * info; - - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry(iter, SlaveInfo, lst_slave); - if (info->slave == slave) - return info; - } - return NULL; -} - -/** - * nm_device_master_enslave_slave: - * @self: the master device - * @slave: the slave device to enslave - * @connection: (allow-none): the slave device's connection - * - * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, - * etc) then this function enslaves @slave. - * - * Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave - * other devices. - */ -static gboolean -nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection) -{ - NMDevicePrivate *priv; - SlaveInfo * info; - gboolean success = FALSE; - gboolean configure; - - g_return_val_if_fail(self != NULL, FALSE); - g_return_val_if_fail(slave != NULL, FALSE); - g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - info = find_slave_info(self, slave); - if (!info) - return FALSE; - - if (info->slave_is_enslaved) - success = TRUE; - else { - configure = (info->configure && connection != NULL); - if (configure) - g_return_val_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); - - success = NM_DEVICE_GET_CLASS(self)->enslave_slave(self, slave, connection, configure); - info->slave_is_enslaved = success; - } - - nm_device_slave_notify_enslave(info->slave, success); - - /* Ensure the device's hardware address is up-to-date; it often changes - * when slaves change. - */ - nm_device_update_hw_address(self); - - /* Send ARP announcements if did not yet and have addresses. */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !priv->acd.announcing) - nm_device_arp_announce(self); - - /* Restart IP configuration if we're waiting for slaves. Do this - * after updating the hardware address as IP config may need the - * new address. - */ - if (success) { - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_WAIT) - nm_device_activate_stage3_ip4_start(self); - - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT) - nm_device_activate_stage3_ip6_start(self); - } - - /* Since slave devices don't have their own IP configuration, - * set the MTU here. - */ - _commit_mtu(slave, NM_DEVICE_GET_PRIVATE(slave)->ip_config_4); - - return success; -} - -/** - * nm_device_master_release_one_slave: - * @self: the master device - * @slave: the slave device to release - * @configure: whether @self needs to actually release @slave - * @force: force the release of @slave even if it wasn't added - * to @master by NetworkManager - * @reason: the state change reason for the @slave - * - * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, - * etc) then this function releases the previously enslaved @slave and/or - * updates the state of @self and @slave to reflect its release. - */ -static void -nm_device_master_release_one_slave(NMDevice * self, - NMDevice * slave, - gboolean configure, - gboolean force, - NMDeviceStateReason reason) -{ - NMDevicePrivate *priv; - NMDevicePrivate *slave_priv; - SlaveInfo * info; - gs_unref_object NMDevice *self_free = NULL; - - g_return_if_fail(NM_DEVICE(self)); - g_return_if_fail(NM_DEVICE(slave)); - g_return_if_fail(!force || configure); - g_return_if_fail(NM_DEVICE_GET_CLASS(self)->release_slave != NULL); - - info = find_slave_info(self, slave); - - _LOGT(LOGD_CORE, - "master: release one slave %p/%s %s%s", - slave, - nm_device_get_iface(slave), - !info ? "(not registered)" : (info->slave_is_enslaved ? "(enslaved)" : "(not enslaved)"), - force ? " (force-configure)" : (configure ? " (configure)" : "")); - - if (!info) - g_return_if_reached(); - - priv = NM_DEVICE_GET_PRIVATE(self); - slave_priv = NM_DEVICE_GET_PRIVATE(slave); - - g_return_if_fail(self == slave_priv->master); - nm_assert(slave == info->slave); - - /* first, let subclasses handle the release ... */ - if (info->slave_is_enslaved || force) - NM_DEVICE_GET_CLASS(self)->release_slave(self, slave, configure); - - /* raise notifications about the release, including clearing is_enslaved. */ - nm_device_slave_notify_release(slave, reason); - - /* keep both alive until the end of the function. - * Transfers ownership from slave_priv->master. */ - self_free = self; - - c_list_unlink(&info->lst_slave); - slave_priv->master = NULL; - - g_signal_handler_disconnect(slave, info->watch_id); - g_object_unref(slave); - g_slice_free(SlaveInfo, info); - - if (c_list_is_empty(&priv->slaves)) { - _active_connection_set_state_flags_full(self, - 0, - NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES); - } - - /* Ensure the device's hardware address is up-to-date; it often changes - * when slaves change. - */ - nm_device_update_hw_address(self); - nm_device_set_unmanaged_by_flags(slave, - NM_UNMANAGED_IS_SLAVE, - NM_UNMAN_FLAG_OP_FORGET, - NM_DEVICE_STATE_REASON_REMOVED); -} - -/** - * can_unmanaged_external_down: - * @self: the device - * - * Check whether the device should stay NM_UNMANAGED_EXTERNAL_DOWN unless - * IFF_UP-ed externally. - */ -static gboolean -can_unmanaged_external_down(NMDevice *self) -{ - return !NM_DEVICE_GET_PRIVATE(self)->nm_owned && nm_device_is_software(self); -} - -static NMUnmanFlagOp -is_unmanaged_external_down(NMDevice *self, gboolean consider_can) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (consider_can && !NM_DEVICE_GET_CLASS(self)->can_unmanaged_external_down(self)) - return NM_UNMAN_FLAG_OP_FORGET; - - /* Manage externally-created software interfaces only when they are IFF_UP */ - if (priv->ifindex <= 0 || !priv->up - || !(!c_list_is_empty(&priv->slaves) - || nm_platform_link_can_assume(nm_device_get_platform(self), priv->ifindex))) - return NM_UNMAN_FLAG_OP_SET_UNMANAGED; - - return NM_UNMAN_FLAG_OP_SET_MANAGED; -} - -static void -set_unmanaged_external_down(NMDevice *self, gboolean only_if_unmanaged) -{ - NMUnmanFlagOp ext_flags; - - if (!nm_device_get_unmanaged_mask(self, NM_UNMANAGED_EXTERNAL_DOWN)) - return; - - if (only_if_unmanaged) { - if (!nm_device_get_unmanaged_flags(self, NM_UNMANAGED_EXTERNAL_DOWN)) - return; - } - - ext_flags = is_unmanaged_external_down(self, FALSE); - if (ext_flags != NM_UNMAN_FLAG_OP_SET_UNMANAGED) { - /* Ensure the assume check is queued before any queued state changes - * from the transition to UNAVAILABLE. - */ - nm_device_queue_recheck_assume(self); - } - - nm_device_set_unmanaged_by_flags(self, - NM_UNMANAGED_EXTERNAL_DOWN, - ext_flags, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); -} - -void -nm_device_update_dynamic_ip_setup(NMDevice *self) -{ - NMDevicePrivate *priv; - GError * error = NULL; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->state < NM_DEVICE_STATE_IP_CONFIG || priv->state > NM_DEVICE_STATE_ACTIVATED) - return; - - g_hash_table_remove_all(priv->ip6_saved_properties); - - if (priv->dhcp_data_4.client) { - if (!nm_device_dhcp4_renew(self, FALSE)) { - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DHCP_FAILED); - return; - } - } - if (priv->dhcp_data_6.client) { - if (!nm_device_dhcp6_renew(self, FALSE)) { - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DHCP_FAILED); - return; - } - } - if (priv->ndisc) { - /* FIXME: todo */ - } - if (priv->dnsmasq_manager) { - /* FIXME: todo */ - } - - if (priv->lldp_listener && nm_lldp_listener_is_running(priv->lldp_listener)) { - nm_lldp_listener_stop(priv->lldp_listener); - if (!nm_lldp_listener_start(priv->lldp_listener, nm_device_get_ifindex(self), &error)) { - _LOGD(LOGD_DEVICE, - "LLDP listener %p could not be restarted: %s", - priv->lldp_listener, - error->message); - g_clear_error(&error); - } - } -} - -/*****************************************************************************/ - -static void -carrier_changed_notify(NMDevice *self, gboolean carrier) -{ - /* stub */ -} - -static void -carrier_changed(NMDevice *self, gboolean carrier) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->state <= NM_DEVICE_STATE_UNMANAGED) - return; - - nm_device_recheck_available_connections(self); - - /* ignore-carrier devices ignore all carrier-down events */ - if (priv->ignore_carrier && !carrier) - return; - - if (nm_device_is_master(self)) { - if (carrier) { - /* Force master to retry getting ip addresses when carrier - * is restored. */ - if (priv->state == NM_DEVICE_STATE_ACTIVATED) - nm_device_update_dynamic_ip_setup(self); - /* If needed, also resume IP configuration that is - * waiting for carrier. */ - if (nm_device_activate_ip4_state_in_wait(self)) - nm_device_activate_stage3_ip4_start(self); - if (nm_device_activate_ip6_state_in_wait(self)) - nm_device_activate_stage3_ip6_start(self); - return; - } - /* fall-through and change state of device */ - } else if (priv->is_enslaved && !carrier) { - /* Slaves don't deactivate when they lose carrier; for - * bonds/teams in particular that would be actively - * counterproductive. - */ - return; - } - - if (carrier) { - if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { - nm_device_queue_state(self, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_CARRIER); - } else if (priv->state == NM_DEVICE_STATE_DISCONNECTED) { - /* If the device is already in DISCONNECTED state without a carrier - * (probably because it is tagged for carrier ignore) ensure that - * when the carrier appears, auto connections are rechecked for - * the device. - */ - nm_device_emit_recheck_auto_activate(self); - } else if (priv->state == NM_DEVICE_STATE_ACTIVATED) { - /* If the device is active without a carrier (probably because it is - * tagged for carrier ignore) ensure that when the carrier appears we - * renew DHCP leases and such. - */ - nm_device_update_dynamic_ip_setup(self); - } - } else { - if (priv->state == NM_DEVICE_STATE_UNAVAILABLE) { - if (priv->queued_state.id && priv->queued_state.state >= NM_DEVICE_STATE_DISCONNECTED) - queued_state_clear(self); - } else { - nm_device_queue_state(self, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_CARRIER); - } - } -} - -static gboolean -carrier_disconnected_action_cb(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - _LOGD(LOGD_DEVICE, - "carrier: link disconnected (calling deferred action) (id=%u)", - priv->carrier_defer_id); - - priv->carrier_defer_id = 0; - carrier_changed(self, FALSE); - return FALSE; -} - -static void -carrier_disconnected_action_cancel(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - guint id = priv->carrier_defer_id; - - if (nm_clear_g_source(&priv->carrier_defer_id)) { - _LOGD(LOGD_DEVICE, "carrier: link disconnected (canceling deferred action) (id=%u)", id); - } -} - -void -nm_device_set_carrier(NMDevice *self, gboolean carrier) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceState state = nm_device_get_state(self); - gboolean notify_flags = FALSE; - - if (priv->carrier == carrier) - return; - - if (NM_FLAGS_ALL(priv->capabilities, - NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { - if (carrier) - priv->interface_flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; - else - priv->interface_flags &= ~NM_DEVICE_INTERFACE_FLAG_CARRIER; - notify_flags = TRUE; - } - - priv->carrier = carrier; - if (notify_flags) - nm_gobject_notify_together(self, PROP_CARRIER, PROP_INTERFACE_FLAGS); - else - _notify(self, PROP_CARRIER); - - if (priv->carrier) { - _LOGI(LOGD_DEVICE, "carrier: link connected"); - carrier_disconnected_action_cancel(self); - NM_DEVICE_GET_CLASS(self)->carrier_changed_notify(self, carrier); - carrier_changed(self, TRUE); - - if (priv->carrier_wait_id) { - nm_device_remove_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); - _carrier_wait_check_queued_act_request(self); - } - } else { - if (priv->carrier_wait_id) - nm_device_add_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); - NM_DEVICE_GET_CLASS(self)->carrier_changed_notify(self, carrier); - if (state <= NM_DEVICE_STATE_DISCONNECTED && !priv->queued_act_request) { - _LOGD(LOGD_DEVICE, "carrier: link disconnected"); - carrier_changed(self, FALSE); - } else { - gint64 now_ms, until_ms; - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - until_ms = NM_MAX(now_ms + _get_carrier_wait_ms(self), priv->carrier_wait_until_ms); - priv->carrier_defer_id = - g_timeout_add(until_ms - now_ms, carrier_disconnected_action_cb, self); - _LOGD(LOGD_DEVICE, - "carrier: link disconnected (deferring action for %ld milliseconds) (id=%u)", - (long) (until_ms - now_ms), - priv->carrier_defer_id); - } - } -} - -static void -nm_device_set_carrier_from_platform(NMDevice *self) -{ - int ifindex; - - if (nm_device_has_capability(self, NM_DEVICE_CAP_CARRIER_DETECT)) { - if (!nm_device_has_capability(self, NM_DEVICE_CAP_NONSTANDARD_CARRIER) - && (ifindex = nm_device_get_ip_ifindex(self)) > 0) { - nm_device_set_carrier( - self, - nm_platform_link_is_connected(nm_device_get_platform(self), ifindex)); - } - } else { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - /* Fake online link when carrier detection is not available. */ - if (!priv->carrier) { - priv->carrier = TRUE; - _notify(self, PROP_CARRIER); - } - } -} - -/*****************************************************************************/ - -static void -device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDevice * master; - nm_auto_nmpobj const NMPObject *plink_master_keep_alive = NULL; - const NMPlatformLink * plink_master; - - g_return_if_fail(plink); - - if (plink->master <= 0) - return; - - master = nm_manager_get_device_by_ifindex(NM_MANAGER_GET, plink->master); - plink_master = nm_platform_link_get(nm_device_get_platform(self), plink->master); - plink_master_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(plink_master)); - - if (master == NULL && plink_master && nm_streq0(plink_master->name, "ovs-system") - && plink_master->type == NM_LINK_TYPE_OPENVSWITCH) { - _LOGD(LOGD_DEVICE, "the device claimed by openvswitch"); - return; - } - - if (priv->master) { - if (plink->master > 0 && plink->master == nm_device_get_ifindex(priv->master)) { - /* call add-slave again. We expect @self already to be added to - * the master, but this also triggers a recheck-assume. */ - nm_device_master_add_slave(priv->master, self, FALSE); - return; - } - - nm_device_master_release_one_slave(priv->master, - self, - FALSE, - FALSE, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - } - - if (master && NM_DEVICE_GET_CLASS(master)->enslave_slave) - nm_device_master_add_slave(master, self, FALSE); - else if (master) { - _LOGI(LOGD_DEVICE, - "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface(master)); - } else { - _LOGW(LOGD_DEVICE, - "enslaved to unknown device %d (%s%s%s)", - plink->master, - NM_PRINT_FMT_QUOTED(plink_master, "\"", plink_master->name, "\"", "??")); - } -} - -static void -ndisc_set_router_config(NMNDisc *ndisc, NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - gint32 now; - GArray * addresses, *dns_servers, *dns_domains; - guint len, i; - const NMDedupMultiHeadEntry *head_entry; - NMDedupMultiIter ipconf_iter; - - if (nm_ndisc_get_node_type(ndisc) != NM_NDISC_NODE_TYPE_ROUTER) - return; - - now = nm_utils_get_monotonic_timestamp_sec(); - - head_entry = nm_ip6_config_lookup_addresses(priv->ip_config_6); - addresses = - g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscAddress), head_entry ? head_entry->len : 0); - nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) { - const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(ipconf_iter.current->obj); - NMNDiscAddress * ndisc_addr; - guint32 lifetime, preferred; - gint32 base; - - if (IN6_IS_ADDR_UNSPECIFIED(&addr->address) || IN6_IS_ADDR_LINKLOCAL(&addr->address)) - continue; - - if (addr->n_ifa_flags & IFA_F_TENTATIVE || addr->n_ifa_flags & IFA_F_DADFAILED) - continue; - - if (addr->plen != 64) - continue; - - /* resolve the timestamps relative to a new base. - * - * Note that for convenience, platform @addr might have timestamp and/or - * lifetime unset. We don't allow that flexibility for ndisc and require - * well defined timestamps. */ - if (addr->timestamp) { - nm_assert(addr->timestamp < G_MAXINT32); - base = addr->timestamp; - } else - base = now; - - lifetime = nm_utils_lifetime_get(addr->timestamp, - addr->lifetime, - addr->preferred, - base, - &preferred); - if (!lifetime) - continue; - - g_array_set_size(addresses, addresses->len + 1); - ndisc_addr = &g_array_index(addresses, NMNDiscAddress, addresses->len - 1); - ndisc_addr->address = addr->address; - ndisc_addr->timestamp = base; - ndisc_addr->lifetime = lifetime; - ndisc_addr->preferred = preferred; - } - - len = nm_ip6_config_get_num_nameservers(priv->ip_config_6); - dns_servers = g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscDNSServer), len); - g_array_set_size(dns_servers, len); - for (i = 0; i < len; i++) { - const struct in6_addr *nameserver = nm_ip6_config_get_nameserver(priv->ip_config_6, i); - NMNDiscDNSServer * ndisc_nameserver; - - ndisc_nameserver = &g_array_index(dns_servers, NMNDiscDNSServer, i); - ndisc_nameserver->address = *nameserver; - ndisc_nameserver->timestamp = now; - ndisc_nameserver->lifetime = NM_NDISC_ROUTER_LIFETIME; - } - - len = nm_ip6_config_get_num_searches(priv->ip_config_6); - dns_domains = g_array_sized_new(FALSE, TRUE, sizeof(NMNDiscDNSDomain), len); - g_array_set_size(dns_domains, len); - for (i = 0; i < len; i++) { - const char * search = nm_ip6_config_get_search(priv->ip_config_6, i); - NMNDiscDNSDomain *ndisc_search; - - ndisc_search = &g_array_index(dns_domains, NMNDiscDNSDomain, i); - ndisc_search->domain = (char *) search; - ndisc_search->timestamp = now; - ndisc_search->lifetime = NM_NDISC_ROUTER_LIFETIME; - } - - nm_ndisc_set_config(ndisc, addresses, dns_servers, dns_domains); - g_array_unref(addresses); - g_array_unref(dns_servers); - g_array_unref(dns_domains); -} - -static void -device_update_interface_flags(NMDevice *self, const NMPlatformLink *plink) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceInterfaceFlags flags = NM_DEVICE_INTERFACE_FLAG_NONE; - - if (plink && NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP)) - flags |= NM_DEVICE_INTERFACE_FLAG_UP; - if (plink && NM_FLAGS_HAS(plink->n_ifi_flags, IFF_LOWER_UP)) - flags |= NM_DEVICE_INTERFACE_FLAG_LOWER_UP; - - if (NM_FLAGS_ALL(priv->capabilities, - NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NONSTANDARD_CARRIER)) { - if (priv->carrier) - flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; - } else { - if (plink && NM_FLAGS_HAS(plink->n_ifi_flags, IFF_LOWER_UP)) - flags |= NM_DEVICE_INTERFACE_FLAG_CARRIER; - } - - if (flags != priv->interface_flags) { - priv->interface_flags = flags; - _notify(self, PROP_INTERFACE_FLAGS); - } -} - -static gboolean -device_link_changed(NMDevice *self) -{ - NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - gboolean ip_ifname_changed = FALSE; - nm_auto_nmpobj const NMPObject *pllink_keep_alive = NULL; - const NMPlatformLink * pllink; - const char * str; - int ifindex; - gboolean was_up; - gboolean update_unmanaged_specs = FALSE; - gboolean got_hw_addr = FALSE, had_hw_addr; - gboolean seen_down = priv->device_link_changed_down; - - priv->device_link_changed_id = 0; - priv->device_link_changed_down = FALSE; - - ifindex = nm_device_get_ifindex(self); - if (ifindex <= 0) - return G_SOURCE_REMOVE; - pllink = nm_platform_link_get(nm_device_get_platform(self), ifindex); - if (!pllink) - return G_SOURCE_REMOVE; - - pllink_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(pllink)); - - str = nm_platform_link_get_udi(nm_device_get_platform(self), pllink->ifindex); - if (!nm_streq0(str, priv->udi)) { - g_free(priv->udi); - priv->udi = g_strdup(str); - _notify(self, PROP_UDI); - } - - str = nm_platform_link_get_path(nm_device_get_platform(self), pllink->ifindex); - if (!nm_streq0(str, priv->path)) { - g_free(priv->path); - priv->path = g_strdup(str); - _notify(self, PROP_PATH); - } - - if (!nm_streq0(pllink->driver, priv->driver)) { - g_free(priv->driver); - priv->driver = g_strdup(pllink->driver); - _notify(self, PROP_DRIVER); - } - - _set_mtu(self, pllink->mtu); - - if (ifindex == nm_device_get_ip_ifindex(self)) - _stats_update_counters_from_pllink(self, pllink); - - had_hw_addr = (priv->hw_addr != NULL); - nm_device_update_hw_address(self); - got_hw_addr = (!had_hw_addr && priv->hw_addr); - nm_device_update_permanent_hw_address(self, FALSE); - - if (pllink->name[0] && !nm_streq(priv->iface, pllink->name)) { - _LOGI(LOGD_DEVICE, - "interface index %d renamed iface from '%s' to '%s'", - priv->ifindex, - priv->iface, - pllink->name); - g_free(priv->iface_); - priv->iface_ = g_strdup(pllink->name); - - /* If the device has no explicit ip_iface, then changing iface changes ip_iface too. */ - ip_ifname_changed = !priv->ip_iface; - - if (nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) - nm_device_set_unmanaged_by_user_settings(self); - else - update_unmanaged_specs = TRUE; - - _notify(self, PROP_IFACE); - if (ip_ifname_changed) - _notify(self, PROP_IP_IFACE); - - /* Re-match available connections against the new interface name */ - nm_device_recheck_available_connections(self); - - /* Let any connections that use the new interface name have a chance - * to auto-activate on the device. - */ - nm_device_emit_recheck_auto_activate(self); - } - - if (priv->ndisc && pllink->inet6_token.id) { - if (nm_ndisc_set_iid(priv->ndisc, pllink->inet6_token)) - _LOGD(LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); - } - - /* Update carrier from link event if applicable. */ - if (nm_device_has_capability(self, NM_DEVICE_CAP_CARRIER_DETECT) - && !nm_device_has_capability(self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) - nm_device_set_carrier(self, pllink->connected); - - device_update_interface_flags(self, pllink); - - klass->link_changed(self, pllink); - - /* Update DHCP, etc, if needed */ - if (ip_ifname_changed) - nm_device_update_dynamic_ip_setup(self); - - was_up = priv->up; - priv->up = NM_FLAGS_HAS(pllink->n_ifi_flags, IFF_UP); - - if (pllink->initialized && nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { - NMDeviceStateReason reason; - - nm_device_set_unmanaged_by_user_udev(self); - nm_device_set_unmanaged_by_user_conf(self); - - reason = NM_DEVICE_STATE_REASON_NOW_MANAGED; - - /* If the device is a external-down candidated but no longer has external - * down set, we must clear the platform-unmanaged flag with reason - * "assumed". */ - if (nm_device_get_unmanaged_mask(self, NM_UNMANAGED_EXTERNAL_DOWN) - && !nm_device_get_unmanaged_flags(self, NM_UNMANAGED_EXTERNAL_DOWN)) { - /* actually, user-udev overwrites external-down. So we only assume the device, - * when it is a external-down candidate, which is not managed via udev. */ - if (!nm_device_get_unmanaged_mask(self, NM_UNMANAGED_USER_UDEV)) { - /* Ensure the assume check is queued before any queued state changes - * from the transition to UNAVAILABLE. - */ - nm_device_queue_recheck_assume(self); - reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; - } - } - - nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_PLATFORM_INIT, FALSE, reason); - } - - set_unmanaged_external_down(self, FALSE); - - device_recheck_slave_status(self, pllink); - - if (priv->up && (!was_up || seen_down)) { - /* the link was down and just came up. That happens for example, while changing MTU. - * We must restore IP configuration. */ - if (NM_IN_SET(priv->ip_state_4, NM_DEVICE_IP_STATE_CONF, NM_DEVICE_IP_STATE_DONE)) { - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "failed applying IP4 config after link comes up again"); - } - - priv->linklocal6_dad_counter = 0; - if (NM_IN_SET(priv->ip_state_6, NM_DEVICE_IP_STATE_CONF, NM_DEVICE_IP_STATE_DONE)) { - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "failed applying IP6 config after link comes up again"); - } - } - - if (update_unmanaged_specs) - nm_device_set_unmanaged_by_user_settings(self); - - if (got_hw_addr && !priv->up && nm_device_get_state(self) == NM_DEVICE_STATE_UNAVAILABLE) { - /* - * If the device is UNAVAILABLE, any previous try to - * bring it up probably has failed because of the - * invalid hardware address; try again. - */ - nm_device_bring_up(self, TRUE, NULL); - nm_device_queue_recheck_available(self, - NM_DEVICE_STATE_REASON_NONE, - NM_DEVICE_STATE_REASON_NONE); - } - - return G_SOURCE_REMOVE; -} - -static gboolean -device_ip_link_changed(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const NMPlatformLink *pllink; - const char * ip_iface; - - priv->device_ip_link_changed_id = 0; - - if (priv->ip_ifindex <= 0) - return G_SOURCE_REMOVE; - - nm_assert(priv->ip_iface); - - pllink = nm_platform_link_get(nm_device_get_platform(self), priv->ip_ifindex); - if (!pllink) - return G_SOURCE_REMOVE; - - if (priv->ifindex <= 0 && pllink->mtu) - _set_mtu(self, pllink->mtu); - - _stats_update_counters_from_pllink(self, pllink); - - ip_iface = pllink->name; - - if (!ip_iface[0]) - return FALSE; - - if (!nm_streq(priv->ip_iface, ip_iface)) { - _LOGI(LOGD_DEVICE, - "ip-ifname: interface index %d renamed ip_iface (%d) from '%s' to '%s'", - priv->ifindex, - priv->ip_ifindex, - priv->ip_iface, - ip_iface); - g_free(priv->ip_iface_); - priv->ip_iface_ = g_strdup(ip_iface); - _notify(self, PROP_IP_IFACE); - - nm_device_update_dynamic_ip_setup(self); - } - - return G_SOURCE_REMOVE; -} - -static void -link_changed_cb(NMPlatform * platform, - int obj_type_i, - int ifindex, - NMPlatformLink *info, - int change_type_i, - NMDevice * self) -{ - const NMPlatformSignalChangeType change_type = change_type_i; - NMDevicePrivate * priv; - - if (change_type != NM_PLATFORM_SIGNAL_CHANGED) - return; - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (ifindex == nm_device_get_ifindex(self)) { - if (!(info->n_ifi_flags & IFF_UP)) - priv->device_link_changed_down = TRUE; - if (!priv->device_link_changed_id) { - priv->device_link_changed_id = g_idle_add((GSourceFunc) device_link_changed, self); - _LOGD(LOGD_DEVICE, "queued link change for ifindex %d", ifindex); - } - } else if (ifindex == nm_device_get_ip_ifindex(self)) { - if (!priv->device_ip_link_changed_id) { - priv->device_ip_link_changed_id = - g_idle_add((GSourceFunc) device_ip_link_changed, self); - _LOGD(LOGD_DEVICE, "queued link change for ip-ifindex %d", ifindex); - } - } -} - -/*****************************************************************************/ - -static void -link_changed(NMDevice *self, const NMPlatformLink *pllink) -{ - /* stub implementation of virtual function to allow subclasses to chain up. */ -} - -static gboolean -link_type_compatible(NMDevice *self, NMLinkType link_type, gboolean *out_compatible, GError **error) -{ - NMDeviceClass *klass; - NMLinkType device_type; - guint i = 0; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - klass = NM_DEVICE_GET_CLASS(self); - - if (!klass->link_types) { - NM_SET_OUT(out_compatible, FALSE); - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Device does not support platform links"); - return FALSE; - } - - device_type = self->_priv->link_type; - if (device_type > NM_LINK_TYPE_UNKNOWN && device_type != link_type) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Needed link type 0x%x does not match the platform link type 0x%X", - device_type, - link_type); - return FALSE; - } - - for (i = 0; klass->link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { - if (klass->link_types[i] == link_type) - return TRUE; - if (klass->link_types[i] == NM_LINK_TYPE_ANY) - return TRUE; - } - - NM_SET_OUT(out_compatible, FALSE); - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Device does not support platform link type 0x%X", - link_type); - return FALSE; -} - -/** - * nm_device_realize_start(): - * @self: the #NMDevice - * @plink: an existing platform link or %NULL - * @assume_state_guess_assume: set the guess_assume state. - * @assume_state_connection_uuid: set the connection uuid to assume. - * @set_nm_owned: for software device, if TRUE set nm-owned. - * @unmanaged_user_explicit: the user-explicit unmanaged flag to apply - * on the device initially. - * @out_compatible: %TRUE on return if @self is compatible with @plink - * @error: location to store error, or %NULL - * - * Initializes and sets up the device using existing backing resources. Before - * the device is ready for use nm_device_realize_finish() must be called. - * @out_compatible will only be set if @plink is not %NULL, and - * - * Important: if nm_device_realize_start() returns %TRUE, the caller MUST - * also call nm_device_realize_finish() to balance g_object_freeze_notify(). - * - * Returns: %TRUE on success, %FALSE on error - */ -gboolean -nm_device_realize_start(NMDevice * self, - const NMPlatformLink *plink, - gboolean assume_state_guess_assume, - const char * assume_state_connection_uuid, - gboolean set_nm_owned, - NMUnmanFlagOp unmanaged_user_explicit, - gboolean * out_compatible, - GError ** error) -{ - nm_auto_nmpobj const NMPObject *plink_keep_alive = NULL; - - nm_assert(!plink || NMP_OBJECT_GET_TYPE(NMP_OBJECT_UP_CAST(plink)) == NMP_OBJECT_TYPE_LINK); - - NM_SET_OUT(out_compatible, TRUE); - - if (plink) { - if (!nm_streq0(nm_device_get_iface(self), plink->name)) { - NM_SET_OUT(out_compatible, FALSE); - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Device interface name does not match platform link"); - return FALSE; - } - - if (!link_type_compatible(self, plink->type, out_compatible, error)) - return FALSE; - - plink_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(plink)); - } - - realize_start_setup(self, - plink, - assume_state_guess_assume, - assume_state_connection_uuid, - set_nm_owned, - unmanaged_user_explicit, - FALSE); - return TRUE; -} - -/** - * nm_device_create_and_realize(): - * @self: the #NMDevice - * @connection: the #NMConnection being activated - * @parent: the parent #NMDevice if any - * @error: location to store error, or %NULL - * - * Creates any backing resources needed to realize the device to proceed - * with activating @connection. - * - * Returns: %TRUE on success, %FALSE on error - */ -gboolean -nm_device_create_and_realize(NMDevice * self, - NMConnection *connection, - NMDevice * parent, - GError ** error) -{ - nm_auto_nmpobj const NMPObject *plink_keep_alive = NULL; - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const NMPlatformLink * plink; - gboolean nm_owned; - - /* Must be set before device is realized */ - plink = nm_platform_link_get_by_ifname(nm_device_get_platform(self), priv->iface); - nm_owned = !plink || !link_type_compatible(self, plink->type, NULL, NULL); - _LOGD(LOGD_DEVICE, "create (is %snm-owned)", nm_owned ? "" : "not "); - - plink = NULL; - /* Create any resources the device needs */ - if (NM_DEVICE_GET_CLASS(self)->create_and_realize) { - if (!NM_DEVICE_GET_CLASS(self)->create_and_realize(self, connection, parent, &plink, error)) - return FALSE; - if (plink) { - nm_assert(NMP_OBJECT_GET_TYPE(NMP_OBJECT_UP_CAST(plink)) == NMP_OBJECT_TYPE_LINK); - plink_keep_alive = nmp_object_ref(NMP_OBJECT_UP_CAST(plink)); - } - } - - priv->nm_owned = nm_owned; - - realize_start_setup(self, - plink, - FALSE, /* assume_state_guess_assume */ - NULL, /* assume_state_connection_uuid */ - FALSE, - NM_UNMAN_FLAG_OP_FORGET, - TRUE); - nm_device_realize_finish(self, plink); - - if (nm_device_get_managed(self, FALSE)) { - nm_device_state_changed(self, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_NOW_MANAGED); - } - return TRUE; -} - -static gboolean -can_update_from_platform_link(NMDevice *self, const NMPlatformLink *plink) -{ - return TRUE; -} - -void -nm_device_update_from_platform_link(NMDevice *self, const NMPlatformLink *plink) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const char * str; - gboolean ifindex_changed; - guint32 mtu; - - if (!NM_DEVICE_GET_CLASS(self)->can_update_from_platform_link(self, plink)) - return; - - g_return_if_fail(plink == NULL || link_type_compatible(self, plink->type, NULL, NULL)); - - str = plink ? nm_platform_link_get_udi(nm_device_get_platform(self), plink->ifindex) : NULL; - if (!nm_streq0(str, priv->udi)) { - g_free(priv->udi); - priv->udi = g_strdup(str); - _notify(self, PROP_UDI); - } - - str = plink ? nm_platform_link_get_path(nm_device_get_platform(self), plink->ifindex) : NULL; - if (!nm_streq0(str, priv->path)) { - g_free(priv->path); - priv->path = g_strdup(str); - _notify(self, PROP_PATH); - } - - if (plink && !nm_str_is_empty(plink->name) && nm_utils_strdup_reset(&priv->iface_, plink->name)) - _notify(self, PROP_IFACE); - - str = plink ? plink->driver : NULL; - if (!nm_streq0(str, priv->driver)) { - g_free(priv->driver); - priv->driver = g_strdup(str); - _notify(self, PROP_DRIVER); - } - - if (plink) { - priv->up = NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP); - if (plink->ifindex == nm_device_get_ip_ifindex(self)) - _stats_update_counters_from_pllink(self, plink); - } else { - priv->up = FALSE; - } - - mtu = plink ? plink->mtu : 0; - _set_mtu(self, mtu); - - ifindex_changed = _set_ifindex(self, plink ? plink->ifindex : 0, FALSE); - - if (ifindex_changed) - NM_DEVICE_GET_CLASS(self)->link_changed(self, plink); - - device_update_interface_flags(self, plink); -} - -/*****************************************************************************/ - -static void -sriov_op_start(NMDevice *self, SriovOp *op) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert(!priv->sriov.pending); - - op->cancellable = g_cancellable_new(); - op->device = g_object_ref(self); - priv->sriov.pending = op; - - nm_platform_link_set_sriov_params_async(nm_device_get_platform(self), - priv->ifindex, - op->num_vfs, - op->autoprobe, - sriov_op_cb, - op, - op->cancellable); -} - -static void -sriov_op_cb(GError *error, gpointer user_data) -{ - SriovOp * op = user_data; - gs_unref_object NMDevice *self = op->device; - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert(op == priv->sriov.pending); - - g_clear_object(&op->cancellable); - - if (op->callback) - op->callback(error, op->callback_data); - - priv->sriov.pending = NULL; - nm_g_slice_free(op); - - if (priv->sriov.next) { - sriov_op_start(self, g_steal_pointer(&priv->sriov.next)); - } -} - -static void -sriov_op_queue_op(NMDevice *self, SriovOp *op) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->sriov.next) { - SriovOp *op_next = g_steal_pointer(&priv->sriov.next); - - priv->sriov.next = op; - - /* Cancel the next operation immediately */ - if (op_next->callback) { - gs_free_error GError *error = NULL; - - nm_utils_error_set_cancelled(&error, FALSE, NULL); - op_next->callback(error, op_next->callback_data); - } - - nm_g_slice_free(op_next); - return; - } - - if (priv->sriov.pending) { - priv->sriov.next = op; - g_cancellable_cancel(priv->sriov.pending->cancellable); - return; - } - - if (op) - sriov_op_start(self, op); -} - -static void -sriov_op_queue(NMDevice * self, - guint num_vfs, - NMTernary autoprobe, - NMPlatformAsyncCallback callback, - gpointer callback_data) -{ - SriovOp *op; - - /* We usually never want to cancel an async write operation, unless it's superseded - * by a newer operation (that resets the state). That is, because we need to ensure - * that we never end up doing two concurrent writes (since we write on a background - * thread, that would be unordered/racy). - * Of course, since we queue requests only per-device, when devices get renamed we - * might end up writing the same sysctl concurrently still. But that's really - * unlikely, and don't rename after udev completes! - * - * The "next" operation is not yet even started. It can be replaced/canceled right away - * when a newer request comes. - * The "pending" operation is currently ongoing, and we may cancel it if - * we have a follow-up operation (queued in "next"). Unless we have a such - * a newer request, we cannot cancel it! - * - * FIXME(shutdown): However, during shutdown we don't have a follow-up write request to cancel - * this operation and we have to give it at least some time to complete. The solution is that - * we register a way to abort the last call during shutdown, and after NM_SHUTDOWN_TIMEOUT_MS - * grace period we pull the plug and cancel it. */ - - op = g_slice_new(SriovOp); - *op = (SriovOp){ - .num_vfs = num_vfs, - .autoprobe = autoprobe, - .callback = callback, - .callback_data = callback_data, - }; - sriov_op_queue_op(self, op); -} - -static void -device_init_static_sriov_num_vfs(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free char * value = NULL; - int num_vfs; - - if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV)) { - value = nm_config_data_get_device_config(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS, - self, - NULL); - num_vfs = _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXINT32, -1); - if (num_vfs >= 0) - sriov_op_queue(self, num_vfs, NM_TERNARY_DEFAULT, NULL, NULL); - } -} - -static void -config_changed(NMConfig * config, - NMConfigData * config_data, - NMConfigChangeFlags changes, - NMConfigData * old_data, - NMDevice * self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->state <= NM_DEVICE_STATE_DISCONNECTED || priv->state > NM_DEVICE_STATE_ACTIVATED) { - priv->ignore_carrier = nm_config_data_get_ignore_carrier(config_data, self); - if (NM_FLAGS_HAS(changes, NM_CONFIG_CHANGE_VALUES)) - device_init_static_sriov_num_vfs(self); - } -} - -static void -realize_start_notify(NMDevice *self, const NMPlatformLink *pllink) -{ - /* the default implementation of realize_start_notify() just calls - * link_changed() -- which by default does nothing. */ - NM_DEVICE_GET_CLASS(self)->link_changed(self, pllink); -} - -/** - * realize_start_setup(): - * @self: the #NMDevice - * @plink: the #NMPlatformLink if backed by a kernel netdevice - * @assume_state_guess_assume: set the guess_assume state. - * @assume_state_connection_uuid: set the connection uuid to assume. - * @set_nm_owned: if TRUE and device is a software-device, set nm-owned. - * TRUE. - * @unmanaged_user_explicit: the user-explict unmanaged flag to set. - * @force_platform_init: if TRUE the platform-init unmanaged flag is - * forcefully cleared. - * - * Update the device from backing resource properties (like hardware - * addresses, carrier states, driver/firmware info, etc). This function - * should only change properties for this device, and should not perform - * any tasks that affect other interfaces (like master/slave or parent/child - * stuff). - */ -static void -realize_start_setup(NMDevice * self, - const NMPlatformLink *plink, - gboolean assume_state_guess_assume, - const char * assume_state_connection_uuid, - gboolean set_nm_owned, - NMUnmanFlagOp unmanaged_user_explicit, - gboolean force_platform_init) -{ - NMDevicePrivate * priv; - NMDeviceClass * klass; - NMPlatform * platform; - static guint32 id = 0; - NMDeviceCapabilities capabilities = 0; - NMConfig * config; - guint real_rate; - gboolean unmanaged; - - /* plink is a NMPlatformLink type, however, we require it to come from the platform - * cache (where else would it come from?). */ - nm_assert(!plink || NMP_OBJECT_GET_TYPE(NMP_OBJECT_UP_CAST(plink)) == NMP_OBJECT_TYPE_LINK); - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - /* The device should not be realized */ - g_return_if_fail(!priv->real); - g_return_if_fail(nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)); - g_return_if_fail(priv->ip_ifindex <= 0); - g_return_if_fail(priv->ip_iface == NULL); - g_return_if_fail(!priv->queued_ip_config_id_4); - g_return_if_fail(!priv->queued_ip_config_id_6); - - _LOGD(LOGD_DEVICE, - "start setup of %s, kernel ifindex %d", - G_OBJECT_TYPE_NAME(self), - plink ? plink->ifindex : 0); - - klass = NM_DEVICE_GET_CLASS(self); - platform = nm_device_get_platform(self); - - /* Balanced by a thaw in nm_device_realize_finish() */ - g_object_freeze_notify(G_OBJECT(self)); - - priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; - priv->mtu_initial = 0; - priv->ip6_mtu_initial = 0; - priv->ip6_mtu = 0; - _set_mtu(self, 0); - - _assume_state_set(self, assume_state_guess_assume, assume_state_connection_uuid); - - nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_EXTERNAL); - - if (plink) - nm_device_update_from_platform_link(self, plink); - - if (priv->ifindex > 0) { - priv->physical_port_id = nm_platform_link_get_physical_port_id(platform, priv->ifindex); - _notify(self, PROP_PHYSICAL_PORT_ID); - - priv->dev_id = nm_platform_link_get_dev_id(platform, priv->ifindex); - - if (nm_platform_link_is_software(platform, priv->ifindex)) - capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; - - _set_mtu(self, nm_platform_link_get_mtu(platform, priv->ifindex)); - - nm_platform_link_get_driver_info(platform, - priv->ifindex, - NULL, - &priv->driver_version, - &priv->firmware_version); - if (priv->driver_version) - _notify(self, PROP_DRIVER_VERSION); - if (priv->firmware_version) - _notify(self, PROP_FIRMWARE_VERSION); - - if (nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) - priv->ipv6ll_handle = nm_platform_link_get_user_ipv6ll_enabled(platform, priv->ifindex); - - if (nm_platform_link_supports_sriov(platform, priv->ifindex)) - capabilities |= NM_DEVICE_CAP_SRIOV; - } - - if (klass->get_generic_capabilities) - capabilities |= klass->get_generic_capabilities(self); - - _add_capabilities(self, capabilities); - - if (!priv->nm_owned && set_nm_owned && nm_device_is_software(self)) { - priv->nm_owned = TRUE; - _LOGD(LOGD_DEVICE, "set nm-owned from state file"); - } - - if (!priv->udi) { - /* Use a placeholder UDI until we get a real one */ - priv->udi = g_strdup_printf("/virtual/device/placeholder/%d", id++); - _notify(self, PROP_UDI); - } - - nm_device_update_hw_address(self); - nm_device_update_initial_hw_address(self); - nm_device_update_permanent_hw_address(self, FALSE); - - /* Note: initial hardware address must be read before calling get_ignore_carrier() */ - config = nm_config_get(); - priv->ignore_carrier = nm_config_data_get_ignore_carrier(nm_config_get_data(config), self); - if (!priv->config_changed_id) { - priv->config_changed_id = g_signal_connect(config, - NM_CONFIG_SIGNAL_CONFIG_CHANGED, - G_CALLBACK(config_changed), - self); - } - - nm_device_set_carrier_from_platform(self); - - nm_assert(!priv->stats.timeout_id); - real_rate = _stats_refresh_rate_real(priv->stats.refresh_rate_ms); - if (real_rate) - priv->stats.timeout_id = g_timeout_add(real_rate, _stats_timeout_cb, self); - - klass->realize_start_notify(self, plink); - - nm_assert(!nm_device_get_unmanaged_mask(self, NM_UNMANAGED_USER_EXPLICIT)); - nm_device_set_unmanaged_flags(self, NM_UNMANAGED_USER_EXPLICIT, unmanaged_user_explicit); - - /* Do not manage externally created software devices until they are IFF_UP - * or have IP addressing */ - nm_device_set_unmanaged_flags(self, - NM_UNMANAGED_EXTERNAL_DOWN, - is_unmanaged_external_down(self, TRUE)); - - /* Unmanaged the loopback device with an explicit NM_UNMANAGED_BY_TYPE flag. - * Later we might want to manage 'lo' too. Currently, that doesn't work because - * NetworkManager might down the interface or remove the 127.0.0.1 address. */ - nm_device_set_unmanaged_flags(self, NM_UNMANAGED_BY_TYPE, is_loopback(self)); - - nm_device_set_unmanaged_by_user_udev(self); - nm_device_set_unmanaged_by_user_conf(self); - - unmanaged = plink && !plink->initialized && !force_platform_init; - - nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, unmanaged); -} - -/** - * nm_device_realize_finish(): - * @self: the #NMDevice - * @plink: the #NMPlatformLink if backed by a kernel netdevice - * - * Update the device's master/slave or parent/child relationships from - * backing resource properties. After this function finishes, the device - * is ready for network connectivity. - */ -void -nm_device_realize_finish(NMDevice *self, const NMPlatformLink *plink) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(!plink || link_type_compatible(self, plink->type, NULL, NULL)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - g_return_if_fail(!priv->real); - - if (plink) - device_recheck_slave_status(self, plink); - - priv->update_ip_config_completed_v4 = FALSE; - priv->update_ip_config_completed_v6 = FALSE; - - priv->real = TRUE; - _notify(self, PROP_REAL); - - nm_device_recheck_available_connections(self); - - /* Balanced by a freeze in realize_start_setup(). */ - g_object_thaw_notify(G_OBJECT(self)); -} - -static void -unrealize_notify(NMDevice *self) -{ - /* Stub implementation for unrealize_notify(). It does nothing, - * but allows derived classes to uniformly invoke the parent - * implementation. */ -} - -static gboolean -available_connections_check_delete_unrealized_on_idle(gpointer user_data) -{ - NMDevice * self = user_data; - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - priv->check_delete_unrealized_id = 0; - - if (g_hash_table_size(priv->available_connections) == 0 && !nm_device_is_real(self)) - g_signal_emit(self, signals[REMOVED], 0); - - return G_SOURCE_REMOVE; -} - -static void -available_connections_check_delete_unrealized(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - /* always rescheadule the remove signal. */ - nm_clear_g_source(&priv->check_delete_unrealized_id); - - if (g_hash_table_size(priv->available_connections) == 0 && !nm_device_is_real(self)) - priv->check_delete_unrealized_id = - g_idle_add(available_connections_check_delete_unrealized_on_idle, self); -} - -/** - * nm_device_unrealize(): - * @self: the #NMDevice - * @remove_resources: if %TRUE, remove backing resources - * @error: location to store error, or %NULL - * - * Clears any properties that depend on backing resources (kernel devices, - * etc) and removes those resources if @remove_resources is %TRUE. - * - * Returns: %TRUE on success, %FALSE on error - */ -gboolean -nm_device_unrealize(NMDevice *self, gboolean remove_resources, GError **error) -{ - NMDevicePrivate *priv; - int ifindex; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - if (!nm_device_is_software(self) || !nm_device_is_real(self)) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_SOFTWARE, - "This device is not a software device or is not realized"); - return FALSE; - } - - priv = NM_DEVICE_GET_PRIVATE(self); - - g_return_val_if_fail(priv->iface != NULL, FALSE); - g_return_val_if_fail(priv->real, FALSE); - - ifindex = nm_device_get_ifindex(self); - - _LOGD(LOGD_DEVICE, "unrealize (ifindex %d)", ifindex > 0 ? ifindex : 0); - - nm_device_assume_state_reset(self); - - if (remove_resources) { - if (NM_DEVICE_GET_CLASS(self)->unrealize) { - if (!NM_DEVICE_GET_CLASS(self)->unrealize(self, error)) - return FALSE; - } else if (ifindex > 0) { - nm_platform_link_delete(nm_device_get_platform(self), ifindex); - } - } - - nm_clear_g_source(&priv->queued_ip_config_id_4); - nm_clear_g_source(&priv->queued_ip_config_id_6); - - g_object_freeze_notify(G_OBJECT(self)); - NM_DEVICE_GET_CLASS(self)->unrealize_notify(self); - - _parent_set_ifindex(self, 0, FALSE); - - _set_ifindex(self, 0, FALSE); - _set_ifindex(self, 0, TRUE); - if (nm_clear_g_free(&priv->ip_iface_)) - _notify(self, PROP_IP_IFACE); - - _set_mtu(self, 0); - - if (priv->driver_version) { - nm_clear_g_free(&priv->driver_version); - _notify(self, PROP_DRIVER_VERSION); - } - if (priv->firmware_version) { - nm_clear_g_free(&priv->firmware_version); - _notify(self, PROP_FIRMWARE_VERSION); - } - if (priv->udi) { - nm_clear_g_free(&priv->udi); - _notify(self, PROP_UDI); - } - if (priv->path) { - nm_clear_g_free(&priv->path); - _notify(self, PROP_PATH); - } - if (priv->physical_port_id) { - nm_clear_g_free(&priv->physical_port_id); - _notify(self, PROP_PHYSICAL_PORT_ID); - } - - nm_clear_g_source(&priv->stats.timeout_id); - _stats_update_counters(self, 0, 0); - - priv->hw_addr_len_ = 0; - if (nm_clear_g_free(&priv->hw_addr)) - _notify(self, PROP_HW_ADDRESS); - priv->hw_addr_type = HW_ADDR_TYPE_UNSET; - if (nm_clear_g_free(&priv->hw_addr_perm)) - _notify(self, PROP_PERM_HW_ADDRESS); - nm_clear_g_free(&priv->hw_addr_initial); - - priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; - if (NM_DEVICE_GET_CLASS(self)->get_generic_capabilities) - priv->capabilities |= NM_DEVICE_GET_CLASS(self)->get_generic_capabilities(self); - _notify(self, PROP_CAPABILITIES); - - nm_clear_g_signal_handler(nm_config_get(), &priv->config_changed_id); - - priv->real = FALSE; - _notify(self, PROP_REAL); - - g_object_thaw_notify(G_OBJECT(self)); - - nm_device_set_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT, TRUE); - - nm_device_set_unmanaged_flags(self, - NM_UNMANAGED_PARENT | NM_UNMANAGED_BY_TYPE - | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_EXPLICIT - | NM_UNMANAGED_EXTERNAL_DOWN | NM_UNMANAGED_IS_SLAVE, - NM_UNMAN_FLAG_OP_FORGET); - - nm_device_state_changed(self, - NM_DEVICE_STATE_UNMANAGED, - remove_resources ? NM_DEVICE_STATE_REASON_USER_REQUESTED - : NM_DEVICE_STATE_REASON_NOW_UNMANAGED); - - /* Garbage-collect unneeded unrealized devices. */ - nm_device_recheck_available_connections(self); - - return TRUE; -} - -void -nm_device_notify_availability_maybe_changed(NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->state != NM_DEVICE_STATE_DISCONNECTED) - return; - - /* A device could have stayed disconnected because it would - * want to register with a network server that now become - * available. */ - nm_device_recheck_available_connections(self); - if (g_hash_table_size(priv->available_connections) > 0) - nm_device_emit_recheck_auto_activate(self); -} - -/** - * nm_device_owns_iface(): - * @self: the #NMDevice - * @iface: an interface name - * - * Called by the manager to ask if the device or any of its components owns - * @iface. For example, a WWAN implementation would return %TRUE for an - * ethernet interface name that was owned by the WWAN device's modem component, - * because that ethernet interface is controlled by the WWAN device and cannot - * be used independently of the WWAN device. - * - * Returns: %TRUE if @self or its components own the interface name, - * %FALSE if not - */ -gboolean -nm_device_owns_iface(NMDevice *self, const char *iface) -{ - if (NM_DEVICE_GET_CLASS(self)->owns_iface) - return NM_DEVICE_GET_CLASS(self)->owns_iface(self, iface); - return FALSE; -} - -NMConnection * -nm_device_new_default_connection(NMDevice *self) -{ - NMConnection *connection; - GError * error = NULL; - - if (!NM_DEVICE_GET_CLASS(self)->new_default_connection) - return NULL; - - connection = NM_DEVICE_GET_CLASS(self)->new_default_connection(self); - if (!connection) - return NULL; - - if (!nm_connection_normalize(connection, NULL, NULL, &error)) { - _LOGD(LOGD_DEVICE, "device generated an invalid default connection: %s", error->message); - g_error_free(error); - g_return_val_if_reached(NULL); - } - - return connection; -} - -static void -slave_state_changed(NMDevice * slave, - NMDeviceState slave_new_state, - NMDeviceState slave_old_state, - NMDeviceStateReason reason, - NMDevice * self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean release = FALSE; - gboolean configure; - - _LOGD(LOGD_DEVICE, - "slave %s state change %d (%s) -> %d (%s)", - nm_device_get_iface(slave), - slave_old_state, - nm_device_state_to_str(slave_old_state), - slave_new_state, - nm_device_state_to_str(slave_new_state)); - - /* Don't try to enslave slaves until the master is ready */ - if (priv->state < NM_DEVICE_STATE_CONFIG) - return; - - if (slave_new_state == NM_DEVICE_STATE_IP_CONFIG) - nm_device_master_enslave_slave(self, slave, nm_device_get_applied_connection(slave)); - else if (slave_new_state > NM_DEVICE_STATE_ACTIVATED) - release = TRUE; - else if (slave_new_state <= NM_DEVICE_STATE_DISCONNECTED - && slave_old_state > NM_DEVICE_STATE_DISCONNECTED) { - /* Catch failures due to unavailable or unmanaged */ - release = TRUE; - } - - if (release) { - configure = priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED - && nm_device_sys_iface_state_get(slave) != NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; - - nm_device_master_release_one_slave(self, slave, configure, FALSE, reason); - /* Bridge/bond/team interfaces are left up until manually deactivated */ - if (c_list_is_empty(&priv->slaves) && priv->state == NM_DEVICE_STATE_ACTIVATED) - _LOGD(LOGD_DEVICE, "last slave removed; remaining activated"); - } -} - -/** - * nm_device_master_add_slave: - * @self: the master device - * @slave: the slave device to enslave - * @configure: pass %TRUE if the slave should be configured by the master, or - * %FALSE if it is already configured outside NetworkManager - * - * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, - * etc) then this function adds @slave to the slave list for later enslavement. - * - * Returns: %TRUE if the slave was enslaved. %FALSE means, the slave was already - * enslaved and nothing was done. - */ -static gboolean -nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure) -{ - NMDevicePrivate *priv; - NMDevicePrivate *slave_priv; - SlaveInfo * info; - gboolean changed = FALSE; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(NM_IS_DEVICE(slave), FALSE); - g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - slave_priv = NM_DEVICE_GET_PRIVATE(slave); - - info = find_slave_info(self, slave); - - _LOGT(LOGD_CORE, - "master: add one slave %p/%s%s", - slave, - nm_device_get_iface(slave), - info ? " (already registered)" : ""); - - if (configure) - g_return_val_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); - - if (!info) { - g_return_val_if_fail(!slave_priv->master, FALSE); - g_return_val_if_fail(!slave_priv->is_enslaved, FALSE); - - info = g_slice_new0(SlaveInfo); - info->slave = g_object_ref(slave); - info->configure = configure; - info->watch_id = - g_signal_connect(slave, NM_DEVICE_STATE_CHANGED, G_CALLBACK(slave_state_changed), self); - c_list_link_tail(&priv->slaves, &info->lst_slave); - slave_priv->master = g_object_ref(self); - - _active_connection_set_state_flags(self, NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES); - - /* no need to emit - * - * _notify (slave, PROP_MASTER); - * - * because slave_priv->is_enslaved is not true, thus the value - * didn't change yet. */ - - g_warn_if_fail(!NM_FLAGS_HAS(slave_priv->unmanaged_mask, NM_UNMANAGED_IS_SLAVE)); - nm_device_set_unmanaged_by_flags(slave, - NM_UNMANAGED_IS_SLAVE, - FALSE, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - changed = TRUE; - } else - g_return_val_if_fail(slave_priv->master == self, FALSE); - - nm_device_queue_recheck_assume(self); - nm_device_queue_recheck_assume(slave); - - return changed; -} - -/** - * nm_device_master_check_slave_physical_port: - * @self: the master device - * @slave: a slave device - * @log_domain: domain to log a warning in - * - * Checks if @self already has a slave with the same #NMDevice:physical-port-id - * as @slave, and logs a warning if so. - */ -void -nm_device_master_check_slave_physical_port(NMDevice *self, NMDevice *slave, NMLogDomain log_domain) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const char * slave_physical_port_id, *existing_physical_port_id; - SlaveInfo * info; - CList * iter; - - slave_physical_port_id = nm_device_get_physical_port_id(slave); - if (!slave_physical_port_id) - return; - - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry(iter, SlaveInfo, lst_slave); - if (info->slave == slave) - continue; - - existing_physical_port_id = nm_device_get_physical_port_id(info->slave); - if (nm_streq0(slave_physical_port_id, existing_physical_port_id)) { - _LOGW(log_domain, - "slave %s shares a physical port with existing slave %s", - nm_device_get_ip_iface(slave), - nm_device_get_ip_iface(info->slave)); - /* Since this function will get called for every slave, we only have - * to warn about the first match we find; if there are other matches - * later in the list, we will have already warned about them matching - * @existing earlier. - */ - return; - } - } -} - -/* release all slaves */ -static void -nm_device_master_release_slaves(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceStateReason reason; - CList * iter, *safe; - - /* Don't release the slaves if this connection doesn't belong to NM. */ - if (nm_device_sys_iface_state_is_external(self)) - return; - - reason = priv->state_reason; - if (priv->state == NM_DEVICE_STATE_FAILED) - reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; - - c_list_for_each_safe (iter, safe, &priv->slaves) { - SlaveInfo *info = c_list_entry(iter, SlaveInfo, lst_slave); - - nm_device_master_release_one_slave(self, info->slave, TRUE, FALSE, reason); - } -} - -/** - * nm_device_is_master: - * @self: the device - * - * Returns: %TRUE if the device can have slaves - */ -gboolean -nm_device_is_master(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - return NM_DEVICE_GET_CLASS(self)->is_master; -} - -/** - * nm_device_get_master: - * @self: the device - * - * If @self has been enslaved by another device, this returns that - * device. Otherwise, it returns %NULL. (In particular, note that if - * @self is in the process of activating as a slave, but has not yet - * been enslaved by its master, this will return %NULL.) - * - * Returns: (transfer none): @self's master, or %NULL - */ -NMDevice * -nm_device_get_master(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->is_enslaved) { - g_return_val_if_fail(priv->master, NULL); - return priv->master; - } - return NULL; -} - -static gboolean -get_ip_config_may_fail(NMDevice *self, int addr_family) -{ - NMConnection * connection; - NMSettingIPConfig *s_ip; - - connection = nm_device_get_applied_connection(self); - - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - - return !s_ip || nm_setting_ip_config_get_may_fail(s_ip); -} - -/* - * check_ip_state - * - * When @full_state_update is TRUE, transition the device from IP_CONFIG to the - * next state according to the outcome of IPv4 and IPv6 configuration. @may_fail - * indicates that we are called just after the initial configuration and thus - * IPv4/IPv6 are allowed to fail if the ipvx.may-fail properties say so, because - * the IP methods couldn't even be started. - * If @full_state_update is FALSE, just check if the connection should be failed - * due to the state of both ip families and the ipvx.may-fail settings. - */ -static void -check_ip_state(NMDevice *self, gboolean may_fail, gboolean full_state_update) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - gboolean ip4_disabled = FALSE, ip6_disabled = FALSE; - NMSettingIPConfig *s_ip4, *s_ip6; - NMDeviceState state; - - if (full_state_update && nm_device_get_state(self) != NM_DEVICE_STATE_IP_CONFIG) - return; - - /* Don't progress into IP_CHECK or SECONDARIES if we're waiting for the - * master to enslave us. */ - if (nm_active_connection_get_master(NM_ACTIVE_CONNECTION(priv->act_request.obj)) - && !priv->is_enslaved) - return; - - s_ip4 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG); - if (s_ip4 - && nm_streq0(nm_setting_ip_config_get_method(s_ip4), NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - ip4_disabled = TRUE; - - s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); - if (s_ip6 - && NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip6), - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) - ip6_disabled = TRUE; - - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { - /* Both method completed (or disabled), proceed with activation */ - nm_device_state_changed(self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); - return; - } - - if ((priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL - || (ip4_disabled && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE)) - && (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL - || (ip6_disabled && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE))) { - /* Either both methods failed, or only one failed and the other is - * disabled */ - if (nm_device_sys_iface_state_is_external_or_assume(self)) { - /* We have assumed configuration, but couldn't redo it. No problem, - * move to check state. */ - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_DONE); - state = NM_DEVICE_STATE_IP_CHECK; - } else if (may_fail && get_ip_config_may_fail(self, AF_INET) - && get_ip_config_may_fail(self, AF_INET6)) { - /* Couldn't start either IPv6 and IPv4 autoconfiguration, - * but both are allowed to fail. */ - state = NM_DEVICE_STATE_SECONDARIES; - } else { - /* Autoconfiguration attempted without success. */ - state = NM_DEVICE_STATE_FAILED; - } - - if (full_state_update || state == NM_DEVICE_STATE_FAILED) { - nm_device_state_changed(self, state, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } - return; - } - - /* If a method is still pending but required, wait */ - if (priv->ip_state_4 != NM_DEVICE_IP_STATE_DONE && !get_ip_config_may_fail(self, AF_INET)) - return; - if (priv->ip_state_6 != NM_DEVICE_IP_STATE_DONE && !get_ip_config_may_fail(self, AF_INET6)) - return; - - /* If at least a method has completed, proceed with activation */ - if ((priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && !ip4_disabled) - || (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && !ip6_disabled)) { - if (full_state_update) - nm_device_state_changed(self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); - return; - } -} - -/** - * nm_device_slave_notify_enslave: - * @self: the slave device - * @success: whether the enslaving operation succeeded - * - * Notifies a slave that either it has been enslaved, or else its master tried - * to enslave it and failed. - */ -static void -nm_device_slave_notify_enslave(NMDevice *self, gboolean success) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection = nm_device_get_applied_connection(self); - gboolean activating = (priv->state == NM_DEVICE_STATE_IP_CONFIG); - - g_return_if_fail(priv->master); - - if (!priv->is_enslaved) { - if (success) { - if (activating) { - _LOGI(LOGD_DEVICE, - "Activation: connection '%s' enslaved, continuing activation", - nm_connection_get_id(connection)); - } else - _LOGI(LOGD_DEVICE, "enslaved to %s", nm_device_get_iface(priv->master)); - - priv->is_enslaved = TRUE; - - _notify(self, PROP_MASTER); - _notify(priv->master, PROP_SLAVES); - } else if (activating) { - _LOGW(LOGD_DEVICE, - "Activation: connection '%s' could not be enslaved", - nm_connection_get_id(connection)); - } - } - - if (activating) { - if (success) - check_ip_state(self, FALSE, TRUE); - else - nm_device_queue_state(self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_UNKNOWN); - } else - nm_device_queue_recheck_assume(self); -} - -/** - * nm_device_slave_notify_release: - * @self: the slave device - * @reason: the reason associated with the state change - * - * Notifies a slave that it has been released, and why. - */ -static void -nm_device_slave_notify_release(NMDevice *self, NMDeviceStateReason reason) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection = nm_device_get_applied_connection(self); - const char * master_status; - - g_return_if_fail(priv->master); - - if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state <= NM_DEVICE_STATE_ACTIVATED) { - switch (nm_device_state_reason_check(reason)) { - case NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED: - master_status = "failed"; - break; - case NM_DEVICE_STATE_REASON_USER_REQUESTED: - reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; - master_status = "deactivated by user request"; - break; - case NM_DEVICE_STATE_REASON_CONNECTION_REMOVED: - reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; - master_status = "deactivated because master was removed"; - break; - default: - master_status = "deactivated"; - break; - } - - _LOGD(LOGD_DEVICE, - "Activation: connection '%s' master %s", - nm_connection_get_id(connection), - master_status); - - /* Cancel any pending activation sources */ - _cancel_activation(self); - nm_device_queue_state(self, NM_DEVICE_STATE_DEACTIVATING, reason); - } else - _LOGI(LOGD_DEVICE, "released from master device %s", nm_device_get_iface(priv->master)); - - if (priv->is_enslaved) { - priv->is_enslaved = FALSE; - _notify(self, PROP_MASTER); - _notify(priv->master, PROP_SLAVES); - } -} - -/** - * nm_device_removed: - * @self: the #NMDevice - * @unconfigure_ip_config: whether to clear the IP config objects - * of the device (provided, it is still not cleared at this point). - * - * Called by the manager when the device was removed. Releases the device from - * the master in case it's enslaved. - */ -void -nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->master) { - /* this is called when something externally messes with the slave or during shut-down. - * Release the slave from master, but don't touch the device. */ - nm_device_master_release_one_slave(priv->master, - self, - FALSE, - FALSE, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - } - - if (unconfigure_ip_config) { - nm_device_set_ip_config(self, AF_INET, NULL, FALSE, NULL); - nm_device_set_ip_config(self, AF_INET6, NULL, FALSE, NULL); - } else { - if (priv->dhcp_data_4.client) - nm_dhcp_client_stop(priv->dhcp_data_4.client, FALSE); - if (priv->dhcp_data_6.client) - nm_dhcp_client_stop(priv->dhcp_data_6.client, FALSE); - } -} - -static gboolean -is_available(NMDevice *self, NMDeviceCheckDevAvailableFlags flags) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->carrier || priv->ignore_carrier) - return TRUE; - - if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER)) - return TRUE; - - /* master types are always available even without carrier. */ - if (nm_device_is_master(self)) - return TRUE; - - return FALSE; -} - -/** - * nm_device_is_available: - * @self: the #NMDevice - * @flags: additional flags to influence the check. Flags have the - * meaning to increase the availability of a device. - * - * Checks if @self would currently be capable of activating a - * connection. In particular, it checks that the device is ready (eg, - * is not missing firmware), that it has carrier (if necessary), and - * that any necessary external software (eg, ModemManager, - * wpa_supplicant) is available. - * - * @self can only be in a state higher than - * %NM_DEVICE_STATE_UNAVAILABLE when nm_device_is_available() returns - * %TRUE. (But note that it can still be %NM_DEVICE_STATE_UNMANAGED - * when it is available.) - * - * Returns: %TRUE or %FALSE - */ -gboolean -nm_device_is_available(NMDevice *self, NMDeviceCheckDevAvailableFlags flags) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->firmware_missing) - return FALSE; - - return NM_DEVICE_GET_CLASS(self)->is_available(self, flags); -} - -gboolean -nm_device_ignore_carrier_by_default(NMDevice *self) -{ - /* master types ignore-carrier by default. */ - return nm_device_is_master(self); -} - -gboolean -nm_device_get_enabled(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - if (NM_DEVICE_GET_CLASS(self)->get_enabled) - return NM_DEVICE_GET_CLASS(self)->get_enabled(self); - return TRUE; -} - -void -nm_device_set_enabled(NMDevice *self, gboolean enabled) -{ - g_return_if_fail(NM_IS_DEVICE(self)); - - if (NM_DEVICE_GET_CLASS(self)->set_enabled) - NM_DEVICE_GET_CLASS(self)->set_enabled(self, enabled); -} - -static NM_UTILS_FLAGS2STR_DEFINE(_autoconnect_blocked_flags_to_string, - NMDeviceAutoconnectBlockedFlags, - NM_UTILS_FLAGS2STR(NM_DEVICE_AUTOCONNECT_BLOCKED_NONE, "none"), - NM_UTILS_FLAGS2STR(NM_DEVICE_AUTOCONNECT_BLOCKED_USER, "user"), - NM_UTILS_FLAGS2STR(NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN, - "wrong-pin"), - NM_UTILS_FLAGS2STR(NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT, - "manual-disconnect"), ); - -NMDeviceAutoconnectBlockedFlags -nm_device_autoconnect_blocked_get(NMDevice *self, NMDeviceAutoconnectBlockedFlags mask) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - if (mask == 0) - mask = NM_DEVICE_AUTOCONNECT_BLOCKED_ALL; - - priv = NM_DEVICE_GET_PRIVATE(self); - return priv->autoconnect_blocked_flags & mask; -} - -void -nm_device_autoconnect_blocked_set_full(NMDevice * self, - NMDeviceAutoconnectBlockedFlags mask, - NMDeviceAutoconnectBlockedFlags value) -{ - NMDevicePrivate *priv; - gboolean changed; - char buf1[128], buf2[128]; - - g_return_if_fail(NM_IS_DEVICE(self)); - nm_assert(mask); - nm_assert(!NM_FLAGS_ANY(mask, ~NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)); - nm_assert(!NM_FLAGS_ANY(value, ~mask)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - value = (priv->autoconnect_blocked_flags & ~mask) | (mask & value); - if (value == priv->autoconnect_blocked_flags) - return; - - changed = ((!value) != (!priv->autoconnect_blocked_flags)); - - _LOGT( - LOGD_DEVICE, - "autoconnect-blocked: set \"%s\" (was \"%s\")", - _autoconnect_blocked_flags_to_string(value, buf1, sizeof(buf1)), - _autoconnect_blocked_flags_to_string(priv->autoconnect_blocked_flags, buf2, sizeof(buf2))); - - priv->autoconnect_blocked_flags = value; - nm_assert(priv->autoconnect_blocked_flags == value); - if (changed) - _notify(self, PROP_AUTOCONNECT); -} - -static gboolean -autoconnect_allowed_accumulator(GSignalInvocationHint *ihint, - GValue * return_accu, - const GValue * handler_return, - gpointer data) -{ - if (!g_value_get_boolean(handler_return)) - g_value_set_boolean(return_accu, FALSE); - return TRUE; -} - -/** - * nm_device_autoconnect_allowed: - * @self: the #NMDevice - * - * Returns: %TRUE if the device can be auto-connected immediately, taking - * transient conditions into account (like companion devices that may wish to - * block autoconnect for a time). - */ -gboolean -nm_device_autoconnect_allowed(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); - GValue instance = G_VALUE_INIT; - GValue retval = G_VALUE_INIT; - - if (nm_device_autoconnect_blocked_get(self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL)) - return FALSE; - - if (klass->get_autoconnect_allowed && !klass->get_autoconnect_allowed(self)) - return FALSE; - - if (!nm_device_get_enabled(self)) - return FALSE; - - if (nm_device_is_real(self)) { - if (priv->state < NM_DEVICE_STATE_DISCONNECTED) - return FALSE; - } else { - if (!nm_device_check_unrealized_device_managed(self)) - return FALSE; - } - - if (priv->delete_on_deactivate_data) - return FALSE; - - /* The 'autoconnect-allowed' signal is emitted on a device to allow - * other listeners to block autoconnect on the device if they wish. - * This is mainly used by the OLPC Mesh devices to block autoconnect - * on their companion Wi-Fi device as they share radio resources and - * cannot be connected at the same time. - */ - - g_value_init(&instance, G_TYPE_OBJECT); - g_value_set_object(&instance, self); - - g_value_init(&retval, G_TYPE_BOOLEAN); - g_value_set_boolean(&retval, TRUE); - - /* Use g_signal_emitv() rather than g_signal_emit() to avoid the return - * value being changed if no handlers are connected */ - g_signal_emitv(&instance, signals[AUTOCONNECT_ALLOWED], 0, &retval); - g_value_unset(&instance); - - return g_value_get_boolean(&retval); -} - -static gboolean -can_auto_connect(NMDevice *self, NMSettingsConnection *sett_conn, char **specific_object) -{ - nm_assert(!specific_object || !*specific_object); - return TRUE; -} - -/** - * nm_device_can_auto_connect: - * @self: an #NMDevice - * @sett_conn: a #NMSettingsConnection - * @specific_object: (out) (transfer full): on output, the path of an - * object associated with the returned connection, to be passed to - * nm_manager_activate_connection(), or %NULL. - * - * Checks if @sett_conn can be auto-activated on @self right now. - * This requires, at a minimum, that the connection be compatible with - * @self, and that it have the #NMSettingConnection:autoconnect property - * set, and that the device allow auto connections. Some devices impose - * additional requirements. (Eg, a Wi-Fi connection can only be activated - * if its SSID was seen in the last scan.) - * - * Returns: %TRUE, if the @sett_conn can be auto-activated. - **/ -gboolean -nm_device_can_auto_connect(NMDevice *self, NMSettingsConnection *sett_conn, char **specific_object) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(sett_conn), FALSE); - g_return_val_if_fail(!specific_object || !*specific_object, FALSE); - - /* the caller must ensure that nm_device_autoconnect_allowed() returns - * TRUE as well. This is done, because nm_device_can_auto_connect() - * has only one caller, and it iterates over a list of available - * connections. - * - * Hence, we don't need to re-check nm_device_autoconnect_allowed() - * over and over again. The caller is supposed to do that. */ - nm_assert(nm_device_autoconnect_allowed(self)); - - if (!nm_device_check_connection_available(self, - nm_settings_connection_get_connection(sett_conn), - NM_DEVICE_CHECK_CON_AVAILABLE_NONE, - NULL, - NULL)) - return FALSE; - - if (!NM_DEVICE_GET_CLASS(self)->can_auto_connect(self, sett_conn, specific_object)) - return FALSE; - - return TRUE; -} - -static gboolean -device_has_config(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - /* Check for IP configuration. */ - if (priv->ip_config_4 && nm_ip4_config_get_num_addresses(priv->ip_config_4)) - return TRUE; - if (priv->ip_config_6 && nm_ip6_config_get_num_addresses(priv->ip_config_6)) - return TRUE; - - /* The existence of a software device is good enough. */ - if (nm_device_is_software(self) && nm_device_is_real(self)) - return TRUE; - - /* Master-slave relationship is also a configuration */ - if (!c_list_is_empty(&priv->slaves) - || nm_platform_link_get_master(nm_device_get_platform(self), priv->ifindex) > 0) - return TRUE; - - return FALSE; -} - -/** - * nm_device_master_update_slave_connection: - * @self: the master #NMDevice - * @slave: the slave #NMDevice - * @connection: the #NMConnection to update with the slave settings - * @GError: (out): error description - * - * Reads the slave configuration for @slave and updates @connection with those - * properties. This invokes a virtual function on the master device @self. - * - * Returns: %TRUE if the configuration was read and @connection updated, - * %FALSE on failure. - */ -gboolean -nm_device_master_update_slave_connection(NMDevice * self, - NMDevice * slave, - NMConnection *connection, - GError ** error) -{ - NMDeviceClass *klass; - gboolean success; - - g_return_val_if_fail(self, FALSE); - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(slave, FALSE); - g_return_val_if_fail(connection, FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - g_return_val_if_fail(nm_connection_get_setting_connection(connection), FALSE); - - g_return_val_if_fail(nm_device_get_iface(self), FALSE); - - klass = NM_DEVICE_GET_CLASS(self); - if (klass->master_update_slave_connection) { - success = klass->master_update_slave_connection(self, slave, connection, error); - - g_return_val_if_fail(!error || (success && !*error) || *error, success); - return success; - } - - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "master device '%s' cannot update a slave connection for slave device '%s' (master " - "type not supported?)", - nm_device_get_iface(self), - nm_device_get_iface(slave)); - return FALSE; -} - -static gboolean -_get_maybe_ipv6_disabled(NMDevice *self) -{ - NMPlatform *platform; - int ifindex; - const char *path; - char ifname[IFNAMSIZ]; - - ifindex = nm_device_get_ip_ifindex(self); - if (ifindex <= 0) - return FALSE; - - platform = nm_device_get_platform(self); - if (!nm_platform_if_indextoname(platform, ifindex, ifname)) - return FALSE; - - path = nm_sprintf_bufa(128, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname); - return (nm_platform_sysctl_get_int32(platform, NMP_SYSCTL_PATHID_ABSOLUTE(path), 0) == 0); -} - -NMConnection * -nm_device_generate_connection(NMDevice *self, - NMDevice *master, - gboolean *out_maybe_later, - GError ** error) -{ - NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const char * ifname = nm_device_get_iface(self); - gs_unref_object NMConnection *connection = NULL; - NMSetting * s_con; - NMSetting * s_ip4; - NMSetting * s_ip6; - char uuid[37]; - const char * ip4_method, *ip6_method; - GError * local = NULL; - const NMPlatformLink * pllink; - - NM_SET_OUT(out_maybe_later, FALSE); - - /* If update_connection() is not implemented, just fail. */ - if (!klass->update_connection) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "device class %s does not support generating a connection", - G_OBJECT_TYPE_NAME(self)); - return NULL; - } - - /* Return NULL if device is unconfigured. */ - if (!device_has_config(self)) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "device has no existing configuration"); - return NULL; - } - - connection = nm_simple_connection_new(); - s_con = nm_setting_connection_new(); - - g_object_set(s_con, - NM_SETTING_CONNECTION_UUID, - nm_utils_uuid_generate_buf(uuid), - NM_SETTING_CONNECTION_ID, - ifname, - NM_SETTING_CONNECTION_AUTOCONNECT, - FALSE, - NM_SETTING_CONNECTION_INTERFACE_NAME, - ifname, - NM_SETTING_CONNECTION_TIMESTAMP, - (guint64) time(NULL), - NULL); - - if (klass->connection_type_supported) - g_object_set(s_con, NM_SETTING_CONNECTION_TYPE, klass->connection_type_supported, NULL); - - nm_connection_add_setting(connection, s_con); - - /* If the device is a slave, update various slave settings */ - if (master) { - if (!nm_device_master_update_slave_connection(master, self, connection, &local)) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "master device '%s' failed to update slave connection: %s", - nm_device_get_iface(master), - local->message); - g_error_free(local); - return NULL; - } - } else { - /* Only regular and master devices get IP configuration; slaves do not */ - s_ip4 = nm_ip4_config_create_setting(priv->ip_config_4); - nm_connection_add_setting(connection, s_ip4); - - s_ip6 = nm_ip6_config_create_setting(priv->ip_config_6, _get_maybe_ipv6_disabled(self)); - nm_connection_add_setting(connection, s_ip6); - - nm_connection_add_setting(connection, nm_setting_proxy_new()); - - pllink = nm_platform_link_get(nm_device_get_platform(self), priv->ifindex); - if (pllink && pllink->inet6_token.id) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - g_object_set(s_ip6, - NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - NM_IN6_ADDR_GEN_MODE_EUI64, - NM_SETTING_IP6_CONFIG_TOKEN, - nm_utils_inet6_interface_identifier_to_token(pllink->inet6_token, sbuf), - NULL); - } - } - - klass->update_connection(self, connection); - - if (!nm_connection_normalize(connection, NULL, NULL, &local)) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "generated connection does not verify: %s", - local->message); - g_error_free(local); - return NULL; - } - - /* Ignore the connection if it has no IP configuration, - * no slave configuration, and is not a master interface. - */ - ip4_method = nm_utils_get_ip_config_method(connection, AF_INET); - ip6_method = nm_utils_get_ip_config_method(connection, AF_INET6); - if (nm_streq0(ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) - && NM_IN_STRSET(ip6_method, - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED) - && !nm_setting_connection_get_master(NM_SETTING_CONNECTION(s_con)) - && c_list_is_empty(&priv->slaves)) { - NM_SET_OUT(out_maybe_later, TRUE); - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "ignoring generated connection (no IP and not in master-slave relationship)"); - return NULL; - } - - /* Ignore any IPv6LL-only, not master connections without slaves, - * unless they are in the assume-ipv6ll-only list. - */ - if (nm_streq0(ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) - && nm_streq0(ip6_method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) - && !nm_setting_connection_get_master(NM_SETTING_CONNECTION(s_con)) - && c_list_is_empty(&priv->slaves) - && !nm_config_data_get_assume_ipv6ll_only(NM_CONFIG_GET_DATA, self)) { - _LOGD(LOGD_DEVICE, - "ignoring generated connection (IPv6LL-only and not in master-slave relationship)"); - NM_SET_OUT(out_maybe_later, TRUE); - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "ignoring generated connection (IPv6LL-only and not in master-slave relationship)"); - return NULL; - } - - return g_steal_pointer(&connection); -} - -/** - * nm_device_complete_connection: - * - * Complete the connection. This is solely used for AddAndActivate where the user - * may pass in an incomplete connection and a device, and the device tries to - * make sense of it and complete it for activation. Otherwise, this is not - * used. - * - * Returns: success or failure. - */ -gboolean -nm_device_complete_connection(NMDevice * self, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMDeviceClass *klass; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - - klass = NM_DEVICE_GET_CLASS(self); - - if (!klass->complete_connection) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "Device class %s had no complete_connection method", - G_OBJECT_TYPE_NAME(self)); - return FALSE; - } - - if (!klass->complete_connection(self, connection, specific_object, existing_connections, error)) - return FALSE; - - if (!nm_connection_normalize(connection, NULL, NULL, error)) - return FALSE; - - return nm_device_check_connection_compatible(self, connection, error); -} - -gboolean -nm_device_match_parent(NMDevice *self, const char *parent) -{ - NMDevice *parent_device; - - g_return_val_if_fail(parent, FALSE); - - parent_device = nm_device_parent_get_device(self); - if (!parent_device) - return FALSE; - - if (nm_utils_is_uuid(parent)) { - NMConnection *connection; - - /* If the parent is a UUID, the connection matches when there is - * no connection active on the device or when a connection with - * that UUID is active. - */ - connection = nm_device_get_applied_connection(parent_device); - if (connection && !nm_streq0(parent, nm_connection_get_uuid(connection))) - return FALSE; - } else { - /* Interface name */ - if (!nm_streq0(parent, nm_device_get_ip_iface(parent_device))) - return FALSE; - } - - return TRUE; -} - -gboolean -nm_device_match_parent_hwaddr(NMDevice * device, - NMConnection *connection, - gboolean fail_if_no_hwaddr) -{ - NMSettingWired *s_wired; - NMDevice * parent_device; - const char * setting_mac; - const char * parent_mac; - - s_wired = nm_connection_get_setting_wired(connection); - if (!s_wired) - return !fail_if_no_hwaddr; - - setting_mac = nm_setting_wired_get_mac_address(s_wired); - if (!setting_mac) - return !fail_if_no_hwaddr; - - parent_device = nm_device_parent_get_device(device); - if (!parent_device) - return !fail_if_no_hwaddr; - - parent_mac = nm_device_get_permanent_hw_address(parent_device); - return parent_mac && nm_utils_hwaddr_matches(setting_mac, -1, parent_mac, -1); -} - -static gboolean -check_connection_compatible(NMDevice *self, NMConnection *connection, GError **error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const char * device_iface = nm_device_get_iface(self); - gs_free_error GError *local = NULL; - gs_free char * conn_iface = NULL; - NMDeviceClass * klass; - NMSettingMatch * s_match; - - klass = NM_DEVICE_GET_CLASS(self); - if (klass->connection_type_check_compatible) { - if (!_nm_connection_check_main_setting(connection, - klass->connection_type_check_compatible, - error)) - return FALSE; - } else if (klass->check_connection_compatible == check_connection_compatible) { - /* the device class does not implement check_connection_compatible nor set - * connection_type_check_compatible. That means, it is by default not compatible - * with any connection type. */ - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "device does not support any connections"); - return FALSE; - } - - conn_iface = nm_manager_get_connection_iface(NM_MANAGER_GET, connection, NULL, NULL, &local); - - /* We always need a interface name for virtual devices, but for - * physical ones a connection without interface name is fine for - * any device. */ - if (!conn_iface) { - if (nm_connection_is_virtual(connection)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "cannot get interface name due to %s", - local->message); - return FALSE; - } - } else if (!nm_streq0(conn_iface, device_iface)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "mismatching interface name"); - return FALSE; - } - - s_match = (NMSettingMatch *) nm_connection_get_setting(connection, NM_TYPE_SETTING_MATCH); - if (s_match) { - const char *const *patterns; - const char * device_driver; - guint num_patterns = 0; - - patterns = nm_setting_match_get_interface_names(s_match, &num_patterns); - if (!nm_wildcard_match_check(device_iface, patterns, num_patterns)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not satisfy match.interface-name property"); - return FALSE; - } - - patterns = nm_setting_match_get_kernel_command_lines(s_match, &num_patterns); - if (num_patterns > 0 - && !nm_utils_kernel_cmdline_match_check(nm_utils_proc_cmdline_split(), - patterns, - num_patterns, - error)) - return FALSE; - - device_driver = nm_device_get_driver(self); - patterns = nm_setting_match_get_drivers(s_match, &num_patterns); - if (!nm_wildcard_match_check(device_driver, patterns, num_patterns)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not satisfy match.driver property"); - return FALSE; - } - - patterns = nm_setting_match_get_paths(s_match, &num_patterns); - if (!nm_wildcard_match_check(priv->path, patterns, num_patterns)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "device does not satisfy match.path property"); - return FALSE; - } - } - - return TRUE; -} - -/** - * nm_device_check_connection_compatible: - * @self: an #NMDevice - * @connection: an #NMConnection - * @error: optional reason why it is incompatible. Note that the - * error code is set to %NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - * if the profile is fundamentally incompatible with the device - * (most commonly, because the device-type does not support the - * connection-type). - * - * Checks if @connection could potentially be activated on @self. - * This means only that @self has the proper capabilities, and that - * @connection is not locked to some other device. It does not - * necessarily mean that @connection could be activated on @self - * right now. (Eg, it might refer to a Wi-Fi network that is not - * currently available.) - * - * Returns: #TRUE if @connection could potentially be activated on - * @self. - */ -gboolean -nm_device_check_connection_compatible(NMDevice *self, NMConnection *connection, GError **error) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - - return NM_DEVICE_GET_CLASS(self)->check_connection_compatible(self, connection, error); -} - -gboolean -nm_device_check_slave_connection_compatible(NMDevice *self, NMConnection *slave) -{ - NMSettingConnection *s_con; - const char * connection_type, *slave_type; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(NM_IS_CONNECTION(slave), FALSE); - - if (!nm_device_is_master(self)) - return FALSE; - - /* All masters should have connection type set */ - connection_type = NM_DEVICE_GET_CLASS(self)->connection_type_supported; - g_return_val_if_fail(connection_type, FALSE); - - s_con = nm_connection_get_setting_connection(slave); - g_assert(s_con); - slave_type = nm_setting_connection_get_slave_type(s_con); - if (!slave_type) - return FALSE; - - return nm_streq(connection_type, slave_type); -} - -/** - * nm_device_can_assume_connections: - * @self: #NMDevice instance - * - * This is a convenience function to determine whether connection assumption - * is available for this device. - * - * Returns: %TRUE if the device is capable of assuming connections, %FALSE if not - */ -static gboolean -nm_device_can_assume_connections(NMDevice *self) -{ - return !!NM_DEVICE_GET_CLASS(self)->update_connection; -} - -static gboolean -unmanaged_on_quit(NMDevice *self) -{ - NMConnection *connection; - - /* NMDeviceWifi overwrites this function to always unmanage wifi devices. - * - * For all other types, if the device type can assume connections, we leave - * it up on quit. - * - * Originally, we would only keep devices up that can be assumed afterwards. - * However, that meant we unmanged layer-2 only devices. So, this was step - * by step refined to unmanage less (commit 25aaaab3, rh#1311988, rh#1333983). - * But there are more scenarios where we also want to keep the device up - * (rh#1378418, rh#1371126). */ - if (!nm_device_can_assume_connections(self)) - return TRUE; - - /* the only exception are IPv4 shared connections. We unmanage them on quit. */ - connection = nm_device_get_applied_connection(self); - if (connection) { - if (NM_IN_STRSET(nm_utils_get_ip_config_method(connection, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - /* shared connections are to be unmangaed. */ - return TRUE; - } - } - - return FALSE; -} - -gboolean -nm_device_unmanage_on_quit(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - return NM_DEVICE_GET_CLASS(self)->unmanaged_on_quit(self); -} - -static gboolean -nm_device_emit_recheck_assume(gpointer user_data) -{ - NMDevice * self = user_data; - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - priv->recheck_assume_id = 0; - if (!nm_device_get_act_request(self)) - g_signal_emit(self, signals[RECHECK_ASSUME], 0); - - return G_SOURCE_REMOVE; -} - -void -nm_device_queue_recheck_assume(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->recheck_assume_id && nm_device_can_assume_connections(self)) - priv->recheck_assume_id = g_idle_add(nm_device_emit_recheck_assume, self); -} - -static gboolean -recheck_available(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean now_available; - NMDeviceState state = nm_device_get_state(self); - NMDeviceState new_state = NM_DEVICE_STATE_UNKNOWN; - - priv->recheck_available.call_id = 0; - - now_available = nm_device_is_available(self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); - - if (state == NM_DEVICE_STATE_UNAVAILABLE && now_available) { - new_state = NM_DEVICE_STATE_DISCONNECTED; - nm_device_queue_state(self, new_state, priv->recheck_available.available_reason); - } else if (state >= NM_DEVICE_STATE_DISCONNECTED && !now_available) { - new_state = NM_DEVICE_STATE_UNAVAILABLE; - nm_device_queue_state(self, new_state, priv->recheck_available.unavailable_reason); - } - - if (new_state > NM_DEVICE_STATE_UNKNOWN) { - _LOGD(LOGD_DEVICE, - "is %savailable, %s %s", - now_available ? "" : "not ", - new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" - : "will transition to", - nm_device_state_to_str(new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state)); - - priv->recheck_available.available_reason = NM_DEVICE_STATE_REASON_NONE; - priv->recheck_available.unavailable_reason = NM_DEVICE_STATE_REASON_NONE; - } - - if (priv->recheck_available.call_id == 0) - nm_device_remove_pending_action(self, NM_PENDING_ACTION_RECHECK_AVAILABLE, TRUE); - - return G_SOURCE_REMOVE; -} - -void -nm_device_queue_recheck_available(NMDevice * self, - NMDeviceStateReason available_reason, - NMDeviceStateReason unavailable_reason) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->recheck_available.available_reason = available_reason; - priv->recheck_available.unavailable_reason = unavailable_reason; - if (!priv->recheck_available.call_id) { - priv->recheck_available.call_id = g_idle_add(recheck_available, self); - nm_device_add_pending_action (self, NM_PENDING_ACTION_RECHECK_AVAILABLE, - FALSE /* cannot assert, because of how recheck_available() first clears - * the call-id and postpones removing the pending-action. */); - } -} - -void -nm_device_emit_recheck_auto_activate(NMDevice *self) -{ - g_signal_emit(self, signals[RECHECK_AUTO_ACTIVATE], 0); -} - -static void -dnsmasq_state_changed_cb(NMDnsMasqManager *manager, guint32 status, gpointer user_data) -{ - NMDevice *self = NM_DEVICE(user_data); - - switch (status) { - case NM_DNSMASQ_STATUS_DEAD: - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); - break; - default: - break; - } -} - -void -nm_device_auth_request(NMDevice * self, - GDBusMethodInvocation * context, - NMConnection * connection, - const char * permission, - gboolean allow_interaction, - GCancellable * cancellable, - NMManagerDeviceAuthRequestFunc callback, - gpointer user_data) -{ - nm_manager_device_auth_request(nm_device_get_manager(self), - self, - context, - connection, - permission, - allow_interaction, - cancellable, - callback, - user_data); -} - -/*****************************************************************************/ - -static void -activation_source_clear(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - if (priv->activation_source_id_x[IS_IPv4] != 0) { - _LOGD(LOGD_DEVICE, - "activation-stage: clear %s,v%c (id %u)", - _activation_func_to_string(priv->activation_source_func_x[IS_IPv4]), - nm_utils_addr_family_to_char(addr_family), - priv->activation_source_id_x[IS_IPv4]); - nm_clear_g_source(&priv->activation_source_id_x[IS_IPv4]); - priv->activation_source_func_x[IS_IPv4] = NULL; - } -} - -static gboolean -activation_source_handle_cb(NMDevice *self, int addr_family) -{ - NMDevicePrivate * priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); - ActivationHandleFunc activation_source_func; - guint activation_source_id; - - g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - activation_source_func = priv->activation_source_func_x[IS_IPv4]; - activation_source_id = priv->activation_source_id_x[IS_IPv4]; - - g_return_val_if_fail(activation_source_id != 0, G_SOURCE_REMOVE); - nm_assert(activation_source_func); - - priv->activation_source_func_x[IS_IPv4] = NULL; - priv->activation_source_id_x[IS_IPv4] = 0; - - _LOGD(LOGD_DEVICE, - "activation-stage: invoke %s,v%c (id %u)", - _activation_func_to_string(activation_source_func), - nm_utils_addr_family_to_char(addr_family), - activation_source_id); - - activation_source_func(self); - - _LOGT(LOGD_DEVICE, - "activation-stage: complete %s,v%c (id %u)", - _activation_func_to_string(activation_source_func), - nm_utils_addr_family_to_char(addr_family), - activation_source_id); - - return G_SOURCE_REMOVE; -} - -static gboolean -activation_source_handle_cb_4(gpointer user_data) -{ - return activation_source_handle_cb(user_data, AF_INET); -} - -static gboolean -activation_source_handle_cb_6(gpointer user_data) -{ - return activation_source_handle_cb(user_data, AF_INET6); -} - -static void -activation_source_schedule(NMDevice *self, ActivationHandleFunc func, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - guint new_id = 0; - - if (priv->activation_source_id_x[IS_IPv4] != 0 - && priv->activation_source_func_x[IS_IPv4] == func) { - /* Scheduling the same stage multiple times is fine. */ - _LOGT(LOGD_DEVICE, - "activation-stage: already scheduled %s,v%c (id %u)", - _activation_func_to_string(func), - nm_utils_addr_family_to_char(addr_family), - priv->activation_source_id_x[IS_IPv4]); - return; - } - - new_id = - g_idle_add(IS_IPv4 ? activation_source_handle_cb_4 : activation_source_handle_cb_6, self); - - if (priv->activation_source_id_x[IS_IPv4] != 0) { - _LOGD(LOGD_DEVICE, - "activation-stage: schedule %s,v%c which replaces %s,v%c (id %u -> %u)", - _activation_func_to_string(func), - nm_utils_addr_family_to_char(addr_family), - _activation_func_to_string(priv->activation_source_func_x[IS_IPv4]), - nm_utils_addr_family_to_char(addr_family), - priv->activation_source_id_x[IS_IPv4], - new_id); - nm_clear_g_source(&priv->activation_source_id_x[IS_IPv4]); - } else { - _LOGD(LOGD_DEVICE, - "activation-stage: schedule %s,v%c (id %u)", - _activation_func_to_string(func), - nm_utils_addr_family_to_char(addr_family), - new_id); - } - - priv->activation_source_func_x[IS_IPv4] = func; - priv->activation_source_id_x[IS_IPv4] = new_id; -} - -static void -activation_source_invoke_sync(NMDevice *self, ActivationHandleFunc func, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - if (priv->activation_source_id_x[IS_IPv4] == 0) { - _LOGD(LOGD_DEVICE, - "activation-stage: synchronously invoke %s,v%c", - _activation_func_to_string(func), - nm_utils_addr_family_to_char(addr_family)); - } else if (priv->activation_source_func_x[IS_IPv4] == func) { - _LOGD(LOGD_DEVICE, - "activation-stage: synchronously invoke %s,v%c which was already scheduled (id %u)", - _activation_func_to_string(func), - nm_utils_addr_family_to_char(addr_family), - priv->activation_source_id_x[IS_IPv4]); - } else { - _LOGD(LOGD_DEVICE, - "activation-stage: synchronously invoke %s,v%c which replaces %s,v%c (id %u)", - _activation_func_to_string(func), - nm_utils_addr_family_to_char(addr_family), - _activation_func_to_string(priv->activation_source_func_x[IS_IPv4]), - nm_utils_addr_family_to_char(addr_family), - priv->activation_source_id_x[IS_IPv4]); - } - - nm_clear_g_source(&priv->activation_source_id_x[IS_IPv4]); - priv->activation_source_func_x[IS_IPv4] = NULL; - - func(self); -} - -/*****************************************************************************/ - -static void -master_ready(NMDevice *self, NMActiveConnection *active) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMActiveConnection *master_connection; - NMDevice * master; - - /* Notify a master device that it has a new slave */ - nm_assert(nm_active_connection_get_master_ready(active)); - - master_connection = nm_active_connection_get_master(active); - - master = nm_active_connection_get_device(master_connection); - - _LOGD(LOGD_DEVICE, "master connection ready; master device %s", nm_device_get_iface(master)); - - if (priv->master && priv->master != master) - nm_device_master_release_one_slave(priv->master, - self, - FALSE, - FALSE, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - - /* If the master didn't change, add-slave only rechecks whether to assume a connection. */ - nm_device_master_add_slave(master, - self, - !nm_device_sys_iface_state_is_external_or_assume(self)); -} - -static void -master_ready_cb(NMActiveConnection *active, GParamSpec *pspec, NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert(nm_active_connection_get_master_ready(active)); - - if (priv->state == NM_DEVICE_STATE_PREPARE) - nm_device_activate_schedule_stage1_device_prepare(self, FALSE); -} - -static void -lldp_neighbors_changed(NMLldpListener *lldp_listener, GParamSpec *pspec, gpointer user_data) -{ - NMDevice *self = NM_DEVICE(user_data); - - _notify(self, PROP_LLDP_NEIGHBORS); -} - -static NMPlatformVF * -sriov_vf_config_to_platform(NMDevice *self, NMSriovVF *vf, GError **error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free NMPlatformVF *plat_vf = NULL; - const guint * vlan_ids; - GVariant * variant; - guint i, num_vlans; - gsize length; - - g_return_val_if_fail(!error || !*error, FALSE); - - vlan_ids = nm_sriov_vf_get_vlan_ids(vf, &num_vlans); - plat_vf = g_malloc0(sizeof(NMPlatformVF) + sizeof(NMPlatformVFVlan) * num_vlans); - - plat_vf->index = nm_sriov_vf_get_index(vf); - - variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_SPOOF_CHECK); - if (variant) - plat_vf->spoofchk = g_variant_get_boolean(variant); - else - plat_vf->spoofchk = -1; - - variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_TRUST); - if (variant) - plat_vf->trust = g_variant_get_boolean(variant); - else - plat_vf->trust = -1; - - variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_MAC); - if (variant) { - if (!_nm_utils_hwaddr_aton(g_variant_get_string(variant, NULL), - plat_vf->mac.data, - sizeof(plat_vf->mac.data), - &length)) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "invalid MAC %s", - g_variant_get_string(variant, NULL)); - return NULL; - } - if (length != priv->hw_addr_len) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "wrong MAC length %" G_GSIZE_FORMAT ", should be %u", - length, - priv->hw_addr_len); - return NULL; - } - plat_vf->mac.len = length; - } - - variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_MIN_TX_RATE); - if (variant) - plat_vf->min_tx_rate = g_variant_get_uint32(variant); - - variant = nm_sriov_vf_get_attribute(vf, NM_SRIOV_VF_ATTRIBUTE_MAX_TX_RATE); - if (variant) - plat_vf->max_tx_rate = g_variant_get_uint32(variant); - - plat_vf->num_vlans = num_vlans; - plat_vf->vlans = (NMPlatformVFVlan *) (&plat_vf[1]); - for (i = 0; i < num_vlans; i++) { - plat_vf->vlans[i].id = vlan_ids[i]; - plat_vf->vlans[i].qos = nm_sriov_vf_get_vlan_qos(vf, vlan_ids[i]); - plat_vf->vlans[i].proto_ad = - nm_sriov_vf_get_vlan_protocol(vf, vlan_ids[i]) == NM_SRIOV_VF_VLAN_PROTOCOL_802_1AD; - } - - return g_steal_pointer(&plat_vf); -} - -static void -sriov_params_cb(GError *error, gpointer data) -{ - NMDevice * self; - NMDevicePrivate *priv; - nm_auto_freev NMPlatformVF **plat_vfs = NULL; - - nm_utils_user_data_unpack(data, &self, &plat_vfs); - - if (nm_utils_error_is_cancelled_or_disposing(error)) - return; - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (error) { - _LOGE(LOGD_DEVICE, "failed to set SR-IOV parameters: %s", error->message); - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return; - } - - if (!nm_platform_link_set_sriov_vfs(nm_device_get_platform(self), - priv->ifindex, - (const NMPlatformVF *const *) plat_vfs)) { - _LOGE(LOGD_DEVICE, "failed to apply SR-IOV VFs"); - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return; - } - - priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_COMPLETED; - - nm_device_activate_schedule_stage1_device_prepare(self, FALSE); -} - -/* - * activate_stage1_device_prepare - * - * Prepare for device activation - * - */ -static void -activate_stage1_device_prepare(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - NMActiveConnection *active; - NMActiveConnection *master; - NMDeviceClass * klass; - - priv->v4_route_table_initialized = FALSE; - priv->v6_route_table_initialized = FALSE; - - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_NONE); - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_NONE); - - /* Notify the new ActiveConnection along with the state change */ - nm_dbus_track_obj_path_set(&priv->act_request, priv->act_request.obj, TRUE); - - nm_device_state_changed(self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); - - if (priv->stage1_sriov_state != NM_DEVICE_STAGE_STATE_COMPLETED) { - NMSettingSriov *s_sriov; - - if (nm_device_sys_iface_state_is_external_or_assume(self)) { - /* pass */ - } else if (priv->stage1_sriov_state == NM_DEVICE_STAGE_STATE_PENDING) - return; - else if (priv->ifindex > 0 && nm_device_has_capability(self, NM_DEVICE_CAP_SRIOV) - && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { - nm_auto_freev NMPlatformVF **plat_vfs = NULL; - gs_free_error GError *error = NULL; - NMSriovVF * vf; - NMTernary autoprobe; - guint i, num; - - autoprobe = nm_setting_sriov_get_autoprobe_drivers(s_sriov); - if (autoprobe == NM_TERNARY_DEFAULT) { - autoprobe = nm_config_data_get_connection_default_int64( - NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("sriov.autoprobe-drivers"), - self, - NM_TERNARY_FALSE, - NM_TERNARY_TRUE, - NM_TERNARY_TRUE); - } - - num = nm_setting_sriov_get_num_vfs(s_sriov); - plat_vfs = g_new0(NMPlatformVF *, num + 1); - for (i = 0; i < num; i++) { - vf = nm_setting_sriov_get_vf(s_sriov, i); - plat_vfs[i] = sriov_vf_config_to_platform(self, vf, &error); - if (!plat_vfs[i]) { - _LOGE(LOGD_DEVICE, - "failed to apply SR-IOV VF '%s': %s", - nm_utils_sriov_vf_to_str(vf, FALSE, NULL), - error->message); - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SRIOV_CONFIGURATION_FAILED); - return; - } - } - - /* When changing the number of VFs the kernel can block - * for very long time in the write to sysfs, especially - * if autoprobe-drivers is enabled. Do it asynchronously - * to avoid blocking the entire NM process. - */ - sriov_op_queue(self, - nm_setting_sriov_get_total_vfs(s_sriov), - autoprobe, - sriov_params_cb, - nm_utils_user_data_pack(self, g_steal_pointer(&plat_vfs))); - priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_PENDING; - return; - } - priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_COMPLETED; - } - - /* Assumed connections were already set up outside NetworkManager */ - klass = NM_DEVICE_GET_CLASS(self); - - if (klass->act_stage1_prepare_set_hwaddr_ethernet - && !nm_device_sys_iface_state_is_external_or_assume(self)) { - if (!nm_device_hw_addr_set_cloned(self, nm_device_get_applied_connection(self), FALSE)) { - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - } - - if (klass->act_stage1_prepare_also_for_external_or_assume - || !nm_device_sys_iface_state_is_external_or_assume(self)) { - nm_assert(!klass->act_stage1_prepare_also_for_external_or_assume - || klass->act_stage1_prepare); - if (klass->act_stage1_prepare) { - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - - ret = klass->act_stage1_prepare(self, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); - return; - } - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - return; - - nm_assert(ret == NM_ACT_STAGE_RETURN_SUCCESS); - } - } - - active = NM_ACTIVE_CONNECTION(priv->act_request.obj); - master = nm_active_connection_get_master(active); - if (master) { - if (nm_active_connection_get_state(master) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { - _LOGD(LOGD_DEVICE, "master connection is deactivating"); - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); - return; - } - /* If the master connection is ready for slaves, attach ourselves */ - if (!nm_active_connection_get_master_ready(active)) { - if (priv->master_ready_id == 0) { - _LOGD(LOGD_DEVICE, "waiting for master connection to become ready"); - priv->master_ready_id = - g_signal_connect(active, - "notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY, - (GCallback) master_ready_cb, - self); - } - return; - } - } - nm_clear_g_signal_handler(priv->act_request.obj, &priv->master_ready_id); - if (master) - master_ready(self, active); - else if (priv->master) { - nm_device_master_release_one_slave(priv->master, - self, - TRUE, - TRUE, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - } - - nm_device_activate_schedule_stage2_device_config(self, TRUE); -} - -void -nm_device_activate_schedule_stage1_device_prepare(NMDevice *self, gboolean do_sync) -{ - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_DEVICE_GET_PRIVATE(self)->act_request.obj); - - if (!do_sync) { - activation_source_schedule(self, activate_stage1_device_prepare, AF_INET); - return; - } - - activation_source_invoke_sync(self, activate_stage1_device_prepare, AF_INET); -} - -static NMActStageReturn -act_stage2_config(NMDevice *self, NMDeviceStateReason *out_failure_reason) -{ - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static void -lldp_init(NMDevice *self, gboolean restart) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->ifindex > 0 && _prop_get_connection_lldp(self)) { - gs_free_error GError *error = NULL; - - if (priv->lldp_listener) { - if (restart && nm_lldp_listener_is_running(priv->lldp_listener)) - nm_lldp_listener_stop(priv->lldp_listener); - } else { - priv->lldp_listener = nm_lldp_listener_new(); - g_signal_connect(priv->lldp_listener, - "notify::" NM_LLDP_LISTENER_NEIGHBORS, - G_CALLBACK(lldp_neighbors_changed), - self); - } - - if (!nm_lldp_listener_is_running(priv->lldp_listener)) { - if (nm_lldp_listener_start(priv->lldp_listener, nm_device_get_ifindex(self), &error)) - _LOGD(LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener); - else { - _LOGD(LOGD_DEVICE, - "LLDP listener %p could not be started: %s", - priv->lldp_listener, - error->message); - } - } - } else { - if (priv->lldp_listener) - nm_lldp_listener_stop(priv->lldp_listener); - } -} - -/* set-mode can be: - * - TRUE: sync with new rules. - * - FALSE: sync, but remove all rules (== flush) - * - DEFAULT: forget about all the rules that we previously tracked, - * but don't actually remove them. This is when quitting NM - * we want to keep the rules. - * The problem is, after restart of NM, the rule manager will - * no longer remember that NM added these rules and treat them - * as externally added ones. Don't restart NetworkManager if - * you care about that. - */ -static void -_routing_rules_sync(NMDevice *self, NMTernary set_mode) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMPRulesManager *rules_manager = nm_netns_get_rules_manager(nm_device_get_netns(self)); - NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); - gboolean untrack_only_dirty = FALSE; - gboolean keep_deleted_rules; - gpointer user_tag_1; - gpointer user_tag_2; - - /* take two arbitrary user-tag pointers that belong to @self. */ - user_tag_1 = &priv->v4_route_table; - user_tag_2 = &priv->v6_route_table; - - if (set_mode == NM_TERNARY_TRUE) { - NMConnection * applied_connection; - NMSettingIPConfig *s_ip; - guint i, num; - int is_ipv4; - - untrack_only_dirty = TRUE; - nmp_rules_manager_set_dirty(rules_manager, user_tag_1); - if (klass->get_extra_rules) - nmp_rules_manager_set_dirty(rules_manager, user_tag_2); - - applied_connection = nm_device_get_applied_connection(self); - - for (is_ipv4 = 0; applied_connection && is_ipv4 < 2; is_ipv4++) { - int addr_family = is_ipv4 ? AF_INET : AF_INET6; - - s_ip = nm_connection_get_setting_ip_config(applied_connection, addr_family); - if (!s_ip) - continue; - - num = nm_setting_ip_config_get_num_routing_rules(s_ip); - for (i = 0; i < num; i++) { - NMPlatformRoutingRule plrule; - NMIPRoutingRule * rule; - - rule = nm_setting_ip_config_get_routing_rule(s_ip, i); - nm_ip_routing_rule_to_platform(rule, &plrule); - - /* We track this rule, but we also make it explicitly not weakly-tracked - * (meaning to untrack NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG at - * the same time). */ - nmp_rules_manager_track(rules_manager, - &plrule, - 10, - user_tag_1, - NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); - } - } - - if (klass->get_extra_rules) { - gs_unref_ptrarray GPtrArray *extra_rules = NULL; - - extra_rules = klass->get_extra_rules(self); - if (extra_rules) { - for (i = 0; i < extra_rules->len; i++) { - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(extra_rules->pdata[i]), - 10, - user_tag_2, - NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); - } - } - } - } - - nmp_rules_manager_untrack_all(rules_manager, user_tag_1, !untrack_only_dirty); - if (klass->get_extra_rules) - nmp_rules_manager_untrack_all(rules_manager, user_tag_2, !untrack_only_dirty); - - keep_deleted_rules = FALSE; - if (set_mode == NM_TERNARY_DEFAULT) { - /* when exiting NM, we leave the device up and the rules configured. - * We just all nmp_rules_manager_sync() to forget about the synced rules, - * but we don't actually delete them. - * - * FIXME: that is a problem after restart of NetworkManager, because these - * rules will look like externally added, and NM will no longer remove - * them. - * To fix that, we could during "assume" mark the rules of the profile - * as owned (and "added" by the device). The problem with that is that it - * wouldn't cover rules that devices add by internal decision (not because - * of a setting in the profile, e.g. WireGuard could setup policy routing). - * Maybe it would be better to remember these orphaned rules at exit in a - * file and track them after restart again. */ - keep_deleted_rules = TRUE; - } - nmp_rules_manager_sync(rules_manager, keep_deleted_rules); -} - -static gboolean -tc_commit(NMDevice *self) -{ - NMConnection * connection = NULL; - gs_unref_ptrarray GPtrArray *qdiscs = NULL; - gs_unref_ptrarray GPtrArray *tfilters = NULL; - NMSettingTCConfig * s_tc = NULL; - NMPlatform * platform; - int ip_ifindex; - - platform = nm_device_get_platform(self); - connection = nm_device_get_applied_connection(self); - if (connection) - s_tc = nm_connection_get_setting_tc_config(connection); - - ip_ifindex = nm_device_get_ip_ifindex(self); - if (!ip_ifindex) - return s_tc == NULL; - - if (s_tc) { - qdiscs = nm_utils_qdiscs_from_tc_setting(platform, s_tc, ip_ifindex); - tfilters = nm_utils_tfilters_from_tc_setting(platform, s_tc, ip_ifindex); - } - - if (!nm_platform_qdisc_sync(platform, ip_ifindex, qdiscs)) - return FALSE; - - if (!nm_platform_tfilter_sync(platform, ip_ifindex, tfilters)) - return FALSE; - - return TRUE; -} - -/* - * activate_stage2_device_config - * - * Determine device parameters and set those on the device, ie - * for wireless devices, set SSID, keys, etc. - * - */ -static void -activate_stage2_device_config(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceClass * klass; - NMActStageReturn ret; - gboolean no_firmware = FALSE; - CList * iter; - - nm_device_state_changed(self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); - - if (!nm_device_sys_iface_state_is_external_or_assume(self)) - _ethtool_state_set(self); - - if (!nm_device_sys_iface_state_is_external_or_assume(self)) { - if (!tc_commit(self)) { - _LOGW(LOGD_IP6, "failed applying traffic control rules"); - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - } - - _routing_rules_sync(self, NM_TERNARY_TRUE); - - if (!nm_device_sys_iface_state_is_external_or_assume(self)) { - if (!nm_device_bring_up(self, FALSE, &no_firmware)) { - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - no_firmware ? NM_DEVICE_STATE_REASON_FIRMWARE_MISSING - : NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - } - - klass = NM_DEVICE_GET_CLASS(self); - if (klass->act_stage2_config_also_for_external_or_assume - || !nm_device_sys_iface_state_is_external_or_assume(self)) { - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - - ret = klass->act_stage2_config(self, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - return; - if (ret != NM_ACT_STAGE_RETURN_SUCCESS) { - nm_assert(ret == NM_ACT_STAGE_RETURN_FAILURE); - nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); - return; - } - } - - /* If we have slaves that aren't yet enslaved, do that now */ - c_list_for_each (iter, &priv->slaves) { - SlaveInfo * info = c_list_entry(iter, SlaveInfo, lst_slave); - NMDeviceState slave_state = nm_device_get_state(info->slave); - - if (slave_state == NM_DEVICE_STATE_IP_CONFIG) - nm_device_master_enslave_slave(self, - info->slave, - nm_device_get_applied_connection(info->slave)); - else if (priv->act_request.obj && nm_device_sys_iface_state_is_external(self) - && slave_state <= NM_DEVICE_STATE_DISCONNECTED) - nm_device_queue_recheck_assume(info->slave); - } - - lldp_init(self, TRUE); - - nm_device_activate_schedule_stage3_ip_config_start(self); -} - -void -nm_device_activate_schedule_stage2_device_config(NMDevice *self, gboolean do_sync) -{ - g_return_if_fail(NM_IS_DEVICE(self)); - - if (!do_sync) { - activation_source_schedule(self, activate_stage2_device_config, AF_INET); - return; - } - - activation_source_invoke_sync(self, activate_stage2_device_config, AF_INET); -} - -void -nm_device_ip_method_failed(NMDevice *self, int addr_family, NMDeviceStateReason reason) -{ - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - - _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_FAIL); - - if (get_ip_config_may_fail(self, addr_family)) - check_ip_state(self, FALSE, (nm_device_get_state(self) == NM_DEVICE_STATE_IP_CONFIG)); - else - nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, reason); -} - -/*****************************************************************************/ - -static void -acd_data_destroy(gpointer ptr) -{ - AcdData *data = ptr; - int i; - - for (i = 0; data->configs && data->configs[i]; i++) - g_object_unref(data->configs[i]); - g_free(data->configs); - g_slice_free(AcdData, data); -} - -static void -ipv4_manual_method_apply(NMDevice *self, NMIP4Config **configs, gboolean success) -{ - NMConnection *connection; - const char * method; - - connection = nm_device_get_applied_connection(self); - nm_assert(connection); - method = nm_utils_get_ip_config_method(connection, AF_INET); - nm_assert(NM_IN_STRSET(method, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL, - NM_SETTING_IP4_CONFIG_METHOD_AUTO)); - - if (!success) { - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); - return; - } - - if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) - nm_device_activate_schedule_ip_config_result(self, AF_INET, NULL); - else { - if (NM_DEVICE_GET_PRIVATE(self)->ip_state_4 != NM_DEVICE_IP_STATE_DONE) - ip_config_merge_and_apply(self, AF_INET, TRUE); - } -} - -static void -acd_manager_probe_terminated(NMAcdManager *acd_manager, gpointer user_data) -{ - AcdData * data = user_data; - NMDevice * self; - NMDevicePrivate * priv; - NMDedupMultiIter ipconf_iter; - const NMPlatformIP4Address *address; - gboolean result, success = TRUE; - int i; - - g_assert(data); - self = data->device; - priv = NM_DEVICE_GET_PRIVATE(self); - - for (i = 0; data->configs && data->configs[i]; i++) { - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, data->configs[i], &address) { - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - result = nm_acd_manager_check_address(acd_manager, address->address); - success &= result; - - _NMLOG(result ? LOGL_DEBUG : LOGL_WARN, - LOGD_DEVICE, - "IPv4 DAD result: address %s is %s", - _nm_utils_inet4_ntop(address->address, sbuf), - result ? "unique" : "duplicate"); - } - } - - data->callback(self, data->configs, success); - - priv->acd.dad_list = g_slist_remove(priv->acd.dad_list, acd_manager); - nm_acd_manager_free(acd_manager); -} - -/** - * ipv4_dad_start: - * @self: device instance - * @configs: NULL-terminated array of IPv4 configurations - * @cb: callback function - * - * Start IPv4 DAD on device @self, check addresses in @configs and call @cb - * when the procedure ends. @cb will be called in any case, even if DAD can't - * be started. @configs will be unreferenced after @cb has been called. - */ -static void -ipv4_dad_start(NMDevice *self, NMIP4Config **configs, AcdCallback cb) -{ - static const NMAcdCallbacks acd_callbacks = { - .probe_terminated_callback = acd_manager_probe_terminated, - .user_data_destroy = acd_data_destroy, - }; - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMAcdManager * acd_manager; - const NMPlatformIP4Address *address; - NMDedupMultiIter ipconf_iter; - AcdData * data; - guint timeout; - gboolean addr_found; - int r; - const guint8 * hwaddr_arr; - size_t length; - guint i; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(configs); - g_return_if_fail(cb); - - for (i = 0, addr_found = FALSE; configs[i]; i++) { - if (nm_ip4_config_get_num_addresses(configs[i]) > 0) { - addr_found = TRUE; - break; - } - } - - timeout = _prop_get_ipv4_dad_timeout(self); - hwaddr_arr = nm_platform_link_get_address(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - &length); - - if (!timeout || !hwaddr_arr || !addr_found || length != ETH_ALEN - || nm_device_sys_iface_state_is_external_or_assume(self)) { - /* DAD not needed, signal success */ - cb(self, configs, TRUE); - - for (i = 0; configs[i]; i++) - g_object_unref(configs[i]); - g_free(configs); - - return; - } - - data = g_slice_new0(AcdData); - data->configs = configs; - data->callback = cb; - data->device = self; - - acd_manager = nm_acd_manager_new(nm_device_get_ip_ifindex(self), - hwaddr_arr, - length, - &acd_callbacks, - data); - priv->acd.dad_list = g_slist_append(priv->acd.dad_list, acd_manager); - - for (i = 0; configs[i]; i++) { - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, configs[i], &address) - nm_acd_manager_add_address(acd_manager, address->address); - } - - r = nm_acd_manager_start_probe(acd_manager, timeout); - if (r < 0) { - _LOGW(LOGD_DEVICE, "acd probe failed"); - - /* DAD could not be started, signal success */ - cb(self, configs, TRUE); - - priv->acd.dad_list = g_slist_remove(priv->acd.dad_list, acd_manager); - nm_acd_manager_free(acd_manager); - } -} - -/*****************************************************************************/ -/* IPv4LL stuff */ - -static void -ipv4ll_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->ipv4ll) { - sd_ipv4ll_set_callback(priv->ipv4ll, NULL, NULL); - sd_ipv4ll_stop(priv->ipv4ll); - priv->ipv4ll = sd_ipv4ll_unref(priv->ipv4ll); - } - - nm_clear_g_source(&priv->ipv4ll_timeout); -} - -static NMIP4Config * -ipv4ll_get_ip4_config(NMDevice *self, guint32 lla) -{ - NMIP4Config * config = NULL; - NMPlatformIP4Address address; - NMPlatformIP4Route route; - - config = nm_device_ip4_config_new(self); - g_assert(config); - - memset(&address, 0, sizeof(address)); - nm_platform_ip4_address_set_addr(&address, lla, 16); - address.addr_source = NM_IP_CONFIG_SOURCE_IP4LL; - nm_ip4_config_add_address(config, &address); - - /* Add a multicast route for link-local connections: destination= 224.0.0.0, netmask=240.0.0.0 */ - memset(&route, 0, sizeof(route)); - route.network = htonl(0xE0000000L); - route.plen = 4; - route.rt_source = NM_IP_CONFIG_SOURCE_IP4LL; - route.table_coerced = nm_platform_route_table_coerce(nm_device_get_route_table(self, AF_INET)); - route.metric = nm_device_get_route_metric(self, AF_INET); - nm_ip4_config_add_route(config, &route, NULL); - - return config; -} - -static void -nm_device_handle_ipv4ll_event(sd_ipv4ll *ll, int event, void *data) -{ - NMDevice * self = data; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - struct in_addr address; - NMIP4Config * config; - int r; - - if (priv->act_request.obj == NULL) - return; - - nm_assert(nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)); - - switch (event) { - case SD_IPV4LL_EVENT_BIND: - r = sd_ipv4ll_get_address(ll, &address); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "invalid IPv4 link-local address received, error %d.", r); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); - return; - } - - if (!nm_utils_ip4_address_is_link_local(address.s_addr)) { - _LOGE(LOGD_AUTOIP4, "invalid address %08x received (not link-local).", address.s_addr); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_ERROR); - return; - } - - config = ipv4ll_get_ip4_config(self, address.s_addr); - if (config == NULL) { - _LOGE(LOGD_AUTOIP4, "failed to get IPv4LL config"); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); - return; - } - - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { - nm_clear_g_source(&priv->ipv4ll_timeout); - nm_device_activate_schedule_ip_config_result(self, AF_INET, NM_IP_CONFIG_CAST(config)); - } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - applied_config_init(&priv->dev_ip_config_4, config); - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { - _LOGE(LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); - } - } else - g_assert_not_reached(); - - g_object_unref(config); - break; - default: - _LOGW(LOGD_AUTOIP4, "IPv4LL address no longer valid after event %d.", event); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); - } -} - -static gboolean -ipv4ll_timeout_cb(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->ipv4ll_timeout) { - _LOGI(LOGD_AUTOIP4, "IPv4LL configuration timed out."); - priv->ipv4ll_timeout = 0; - ipv4ll_cleanup(self); - - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_timeout(self, AF_INET); - } - - return FALSE; -} - -static NMActStageReturn -ipv4ll_start(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const struct ether_addr *addr; - int ifindex, r; - size_t addr_len; - - ipv4ll_cleanup(self); - - r = sd_ipv4ll_new(&priv->ipv4ll); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: new() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_attach_event(priv->ipv4ll, NULL, 0); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: attach_event() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - ifindex = nm_device_get_ip_ifindex(self); - addr = nm_platform_link_get_address(nm_device_get_platform(self), ifindex, &addr_len); - if (!addr || addr_len != ETH_ALEN) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: can't retrieve hardware address"); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_mac(priv->ipv4ll, addr); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: set_mac() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_ifindex(priv->ipv4ll, ifindex); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: set_ifindex() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_set_callback(priv->ipv4ll, nm_device_handle_ipv4ll_event, self); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: set_callback() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - r = sd_ipv4ll_start(priv->ipv4ll); - if (r < 0) { - _LOGE(LOGD_AUTOIP4, "IPv4LL: start() failed with error %d", r); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - _LOGI(LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started"); - - /* Start a timeout to bound the address attempt */ - priv->ipv4ll_timeout = g_timeout_add_seconds(20, ipv4ll_timeout_cb, self); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static void -ensure_con_ip_config(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMIPConfig * con_ip_config; - - if (priv->con_ip_config_x[IS_IPv4]) - return; - - connection = nm_device_get_applied_connection(self); - if (!connection) - return; - - con_ip_config = nm_device_ip_config_new(self, addr_family); - - if (IS_IPv4) { - nm_ip4_config_merge_setting(NM_IP4_CONFIG(con_ip_config), - nm_connection_get_setting_ip4_config(connection), - _prop_get_connection_mdns(self), - _prop_get_connection_llmnr(self), - nm_device_get_route_table(self, addr_family), - nm_device_get_route_metric(self, addr_family)); - } else { - nm_ip6_config_merge_setting(NM_IP6_CONFIG(con_ip_config), - nm_connection_get_setting_ip6_config(connection), - nm_device_get_route_table(self, addr_family), - nm_device_get_route_metric(self, addr_family)); - } - - if (nm_device_sys_iface_state_is_external_or_assume(self)) { - /* For assumed connections ignore all addresses and routes. */ - nm_ip_config_reset_addresses(con_ip_config); - nm_ip_config_reset_routes(con_ip_config); - } - - priv->con_ip_config_x[IS_IPv4] = con_ip_config; -} - -/*****************************************************************************/ - -static void -dhcp4_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->dhcp_data_4.was_active = FALSE; - nm_clear_g_source(&priv->dhcp_data_4.grace_id); - priv->dhcp_data_4.grace_pending = FALSE; - nm_clear_g_free(&priv->dhcp4.pac_url); - - if (priv->dhcp_data_4.client) { - /* Stop any ongoing DHCP transaction on this device */ - nm_clear_g_signal_handler(priv->dhcp_data_4.client, &priv->dhcp_data_4.state_sigid); - - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) - nm_dhcp_client_stop(priv->dhcp_data_4.client, release); - - g_clear_object(&priv->dhcp_data_4.client); - } - - if (priv->dhcp_data_4.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); - _notify(self, PROP_DHCP4_CONFIG); - } -} - -static gboolean -ip_config_merge_and_apply(NMDevice *self, int addr_family, gboolean commit) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean success; - gs_unref_object NMIPConfig *composite = NULL; - NMIPConfig * config; - gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL; - NMConnection * connection; - gboolean ignore_auto_routes = FALSE; - gboolean ignore_auto_dns = FALSE; - gboolean ignore_default_routes = FALSE; - GSList * iter; - const char * ip6_addr_gen_token = NULL; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - if (nm_device_sys_iface_state_is_external(self)) - commit = FALSE; - - connection = nm_device_get_applied_connection(self); - - /* Apply ignore-auto-routes and ignore-auto-dns settings */ - if (connection) { - NMSettingIPConfig *s_ip; - - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - if (s_ip) { - ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes(s_ip); - ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns(s_ip); - - /* if the connection has an explicit gateway, we also ignore - * the default routes from other sources. */ - ignore_default_routes = nm_setting_ip_config_get_never_default(s_ip) - || nm_setting_ip_config_get_gateway(s_ip); - - if (!IS_IPv4) { - NMSettingIP6Config *s_ip6 = NM_SETTING_IP6_CONFIG(s_ip); - - if (nm_setting_ip6_config_get_addr_gen_mode(s_ip6) - == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) - ip6_addr_gen_token = nm_setting_ip6_config_get_token(s_ip6); - } - } - } - - composite = nm_device_ip_config_new(self, addr_family); - - if (!IS_IPv4) { - nm_ip6_config_set_privacy(NM_IP6_CONFIG(composite), - priv->ndisc ? priv->ndisc_use_tempaddr - : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - } - - init_ip_config_dns_priority(self, composite); - - if (commit) { - if (priv->queued_ip_config_id_x[IS_IPv4]) - update_ext_ip_config(self, addr_family, FALSE); - ensure_con_ip_config(self, addr_family); - } - - if (!IS_IPv4) { - if (commit && priv->ipv6ll_has) { - const NMPlatformIP6Address ll_a = { - .address = priv->ipv6ll_addr, - .plen = 64, - .addr_source = NM_IP_CONFIG_SOURCE_IP6LL, - }; - const NMPlatformIP6Route ll_r = { - .network.s6_addr16[0] = htons(0xfe80u), - .plen = 64, - .metric = nm_device_get_route_metric(self, addr_family), - .rt_source = NM_IP_CONFIG_SOURCE_IP6LL, - }; - - nm_assert(IN6_IS_ADDR_LINKLOCAL(&priv->ipv6ll_addr)); - - nm_ip6_config_add_address(NM_IP6_CONFIG(composite), &ll_a); - nm_ip6_config_add_route(NM_IP6_CONFIG(composite), &ll_r, NULL); - } - } - - if (commit) { - gboolean v; - - v = default_route_metric_penalty_detect(self, addr_family); - if (IS_IPv4) - priv->default_route_metric_penalty_ip4_has = v; - else - priv->default_route_metric_penalty_ip6_has = v; - } - - /* Merge all the IP configs into the composite config */ - - if (IS_IPv4) { - config = applied_config_get_current(&priv->dev_ip_config_4); - if (config) { - nm_ip4_config_merge( - NM_IP4_CONFIG(composite), - NM_IP4_CONFIG(config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get(self, addr_family)); - } - } - - if (!IS_IPv4) { - config = applied_config_get_current(&priv->ac_ip6_config); - if (config) { - nm_ip6_config_merge( - NM_IP6_CONFIG(composite), - NM_IP6_CONFIG(config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get(self, addr_family)); - } - } - - if (!IS_IPv4) { - config = applied_config_get_current(&priv->dhcp6.ip6_config); - if (config) { - nm_ip6_config_merge( - NM_IP6_CONFIG(composite), - NM_IP6_CONFIG(config), - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get(self, addr_family)); - } - } - - for (iter = priv->vpn_configs_x[IS_IPv4]; iter; iter = iter->next) - nm_ip_config_merge(composite, iter->data, NM_IP_CONFIG_MERGE_DEFAULT, 0); - - if (priv->ext_ip_config_x[IS_IPv4]) - nm_ip_config_merge(composite, - priv->ext_ip_config_x[IS_IPv4], - NM_IP_CONFIG_MERGE_EXTERNAL, - 0); - - /* Merge WWAN config *last* to ensure modem-given settings overwrite - * any external stuff set by pppd or other scripts. - */ - config = applied_config_get_current(&priv->dev2_ip_config_x[IS_IPv4]); - if (config) { - nm_ip_config_merge(composite, - config, - (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) - | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) - | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), - default_route_metric_penalty_get(self, addr_family)); - } - - if (!IS_IPv4) { - if (priv->rt6_temporary_not_available) { - const NMPObject *o; - GHashTableIter hiter; - - g_hash_table_iter_init(&hiter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next(&hiter, (gpointer *) &o, NULL)) { - nm_ip6_config_add_route(NM_IP6_CONFIG(composite), - NMP_OBJECT_CAST_IP6_ROUTE(o), - NULL); - } - } - } - - /* Merge user overrides into the composite config. For assumed connections, - * con_ip_config_x is empty. */ - if (priv->con_ip_config_x[IS_IPv4]) { - nm_ip_config_merge(composite, - priv->con_ip_config_x[IS_IPv4], - NM_IP_CONFIG_MERGE_DEFAULT, - default_route_metric_penalty_get(self, addr_family)); - } - - if (commit) { - gboolean is_vrf; - - is_vrf = priv->master && nm_device_get_device_type(priv->master) == NM_DEVICE_TYPE_VRF; - - if (IS_IPv4) { - nm_ip4_config_add_dependent_routes(NM_IP4_CONFIG(composite), - nm_device_get_route_table(self, addr_family), - nm_device_get_route_metric(self, addr_family), - is_vrf, - &ip4_dev_route_blacklist); - } else { - nm_ip6_config_add_dependent_routes(NM_IP6_CONFIG(composite), - nm_device_get_route_table(self, addr_family), - nm_device_get_route_metric(self, addr_family), - is_vrf); - } - } - - if (IS_IPv4) { - if (commit) { - if (NM_DEVICE_GET_CLASS(self)->ip4_config_pre_commit) - NM_DEVICE_GET_CLASS(self)->ip4_config_pre_commit(self, NM_IP4_CONFIG(composite)); - } - } - - if (!IS_IPv4) { - NMUtilsIPv6IfaceId iid; - - if (commit && priv->ndisc_started && ip6_addr_gen_token - && nm_utils_ipv6_interface_identifier_get_from_token(&iid, ip6_addr_gen_token)) { - set_ipv6_token(self, iid, ip6_addr_gen_token); - } - } - - success = - nm_device_set_ip_config(self, addr_family, composite, commit, ip4_dev_route_blacklist); - if (commit) { - if (IS_IPv4) - priv->v4_commit_first_time = FALSE; - else - priv->v6_commit_first_time = FALSE; - } - - return success; -} - -static gboolean -dhcp4_lease_change(NMDevice *self, NMIP4Config *config, gboolean bound) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - - g_return_val_if_fail(config, FALSE); - - applied_config_init(&priv->dev_ip_config_4, config); - - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { - _LOGW(LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); - return FALSE; - } - - /* TODO: we should perform DAD again whenever we obtain a - * new lease after an expiry. But what should we do if - * a duplicate address is detected? Fail the connection; - * restart DHCP; continue without an address? */ - if (bound && !nm_dhcp_client_accept(priv->dhcp_data_4.client, &error)) { - _LOGW(LOGD_DHCP4, "error accepting lease: %s", error->message); - return FALSE; - } - - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP4_CHANGE, self, NULL, NULL, NULL, NULL); - - return TRUE; -} - -static gboolean -dhcp_grace_period_expired(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - priv->dhcp_data_x[IS_IPv4].grace_id = 0; - priv->dhcp_data_x[IS_IPv4].grace_pending = FALSE; - - _LOGI(LOGD_DHCP_from_addr_family(addr_family), - "DHCPv%c: grace period expired", - nm_utils_addr_family_to_char(addr_family)); - - nm_device_ip_method_failed(self, addr_family, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - /* If the device didn't fail, the DHCP client will continue */ - - return G_SOURCE_REMOVE; -} - -static gboolean -dhcp_grace_period_expired_4(gpointer user_data) -{ - return dhcp_grace_period_expired(user_data, AF_INET); -} - -static gboolean -dhcp_grace_period_expired_6(gpointer user_data) -{ - return dhcp_grace_period_expired(user_data, AF_INET6); -} - -static gboolean -dhcp_grace_period_start(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - guint32 timeout; - - /* In any other case (expired lease, assumed connection, etc.), - * wait for some time before failing the IP method. - */ - if (priv->dhcp_data_x[IS_IPv4].grace_pending) { - /* already pending. */ - return FALSE; - } - - /* Start a grace period equal to the DHCP timeout multiplied - * by a constant factor. */ - timeout = _prop_get_ipvx_dhcp_timeout(self, addr_family); - if (timeout == NM_DHCP_TIMEOUT_INFINITY) - _LOGI(LOGD_DHCP_from_addr_family(addr_family), - "DHCPv%c: trying to acquire a new lease", - nm_utils_addr_family_to_char(addr_family)); - else { - timeout = dhcp_grace_period_from_timeout(timeout); - _LOGI(LOGD_DHCP_from_addr_family(addr_family), - "DHCPv%c: trying to acquire a new lease within %u seconds", - nm_utils_addr_family_to_char(addr_family), - timeout); - nm_assert(!priv->dhcp_data_x[IS_IPv4].grace_id); - priv->dhcp_data_x[IS_IPv4].grace_id = g_timeout_add_seconds( - timeout, - IS_IPv4 ? dhcp_grace_period_expired_4 : dhcp_grace_period_expired_6, - self); - } - - priv->dhcp_data_x[IS_IPv4].grace_pending = TRUE; - - return TRUE; -} -static void -dhcp4_fail(NMDevice *self, NMDhcpState dhcp_state) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - _LOGD(LOGD_DHCP4, - "DHCPv4 failed (ip_state %s, was_active %d)", - _ip_state_to_string(priv->ip_state_4), - priv->dhcp_data_4.was_active); - - /* The client is always left running after a failure. */ - - /* Nothing to do if we failed before... */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) - goto clear_config; - - /* ... and also if there are static addresses configured - * on the interface. - */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE && priv->con_ip_config_4 - && nm_ip4_config_get_num_addresses(priv->con_ip_config_4) > 0) - goto clear_config; - - /* Fail the method when one of the following is true: - * 1) the DHCP client terminated: it does not make sense to start a grace - * period without a client running; - * 2) we failed to get an initial lease AND the client was - * not active before. - */ - if (dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp_data_4.was_active && priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF)) { - nm_device_activate_schedule_ip_config_timeout(self, AF_INET); - return; - } - - if (dhcp_grace_period_start(self, AF_INET)) - goto clear_config; - - return; - -clear_config: - /* The previous configuration is no longer valid */ - if (priv->dhcp_data_4.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); - priv->dhcp_data_4.config = nm_dhcp_config_new(AF_INET); - _notify(self, PROP_DHCP4_CONFIG); - } -} - -static void -dhcp4_dad_cb(NMDevice *self, NMIP4Config **configs, gboolean success) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (success) { - nm_device_activate_schedule_ip_config_result(self, AF_INET, NM_IP_CONFIG_CAST(configs[1])); - } else { - nm_dhcp_client_decline(priv->dhcp_data_4.client, "Address conflict detected", NULL); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_IP_ADDRESS_DUPLICATE); - } -} - -static void -dhcp4_state_changed(NMDhcpClient *client, - NMDhcpState state, - NMIP4Config * ip4_config, - GHashTable * options, - gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIP4Config * manual, **configs; - NMConnection * connection; - - g_return_if_fail(nm_dhcp_client_get_addr_family(client) == AF_INET); - g_return_if_fail(!ip4_config || NM_IS_IP4_CONFIG(ip4_config)); - - _LOGD(LOGD_DHCP4, "new DHCPv4 client state %d", state); - - switch (state) { - case NM_DHCP_STATE_BOUND: - case NM_DHCP_STATE_EXTENDED: - if (!ip4_config) { - _LOGW(LOGD_DHCP4, "failed to get IPv4 config in response to DHCP event."); - dhcp4_fail(self, state); - break; - } - - nm_clear_g_source(&priv->dhcp_data_4.grace_id); - priv->dhcp_data_4.grace_pending = FALSE; - - /* After some failures, we have been able to renew the lease: - * update the ip state - */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_CONF); - - g_free(priv->dhcp4.pac_url); - priv->dhcp4.pac_url = g_strdup(g_hash_table_lookup(options, "wpad")); - nm_device_set_proxy_config(self, priv->dhcp4.pac_url); - - nm_dhcp_config_set_options(priv->dhcp_data_4.config, options); - _notify(self, PROP_DHCP4_CONFIG); - - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) { - connection = nm_device_get_applied_connection(self); - g_assert(connection); - - manual = nm_device_ip4_config_new(self); - nm_ip4_config_merge_setting(manual, - nm_connection_get_setting_ip4_config(connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, - NM_SETTING_CONNECTION_LLMNR_DEFAULT, - nm_device_get_route_table(self, AF_INET), - nm_device_get_route_metric(self, AF_INET)); - - configs = g_new0(NMIP4Config *, 3); - configs[0] = manual; - configs[1] = g_object_ref(ip4_config); - - ipv4_dad_start(self, configs, dhcp4_dad_cb); - } else if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - if (dhcp4_lease_change(self, ip4_config, state == NM_DHCP_STATE_BOUND)) - nm_device_update_metered(self); - else - dhcp4_fail(self, state); - } - break; - case NM_DHCP_STATE_TIMEOUT: - dhcp4_fail(self, state); - break; - case NM_DHCP_STATE_EXPIRE: - /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF) - break; - /* fall-through */ - case NM_DHCP_STATE_DONE: - case NM_DHCP_STATE_FAIL: - case NM_DHCP_STATE_TERMINATED: - dhcp4_fail(self, state); - break; - default: - break; - } -} - -static NMActStageReturn -dhcp4_start(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingIPConfig *s_ip4; - gs_unref_bytes GBytes *vendor_class_identifier = NULL; - gs_unref_bytes GBytes *hwaddr = NULL; - gs_unref_bytes GBytes *bcast_hwaddr = NULL; - gs_unref_bytes GBytes *client_id = NULL; - gs_free char * mud_url_free = NULL; - NMConnection * connection; - NMSettingConnection * s_con; - GError * error = NULL; - const NMPlatformLink * pllink; - const char *const * reject_servers; - - connection = nm_device_get_applied_connection(self); - g_return_val_if_fail(connection, FALSE); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - - s_con = nm_connection_get_setting_connection(connection); - nm_assert(s_con); - - /* Clear old exported DHCP options */ - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_4.config); - priv->dhcp_data_4.config = nm_dhcp_config_new(AF_INET); - - pllink = nm_platform_link_get(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); - if (pllink) { - hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); - bcast_hwaddr = nmp_link_address_get_as_bytes(&pllink->l_broadcast); - } - - client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr); - vendor_class_identifier = - _prop_get_ipv4_dhcp_vendor_class_identifier(self, NM_SETTING_IP4_CONFIG(s_ip4)); - reject_servers = nm_setting_ip_config_get_dhcp_reject_servers(s_ip4, NULL); - - g_warn_if_fail(priv->dhcp_data_4.client == NULL); - priv->dhcp_data_4.client = - nm_dhcp_manager_start_ip4(nm_dhcp_manager_get(), - nm_netns_get_multi_idx(nm_device_get_netns(self)), - nm_device_get_ip_iface(self), - nm_device_get_ip_ifindex(self), - hwaddr, - bcast_hwaddr, - nm_connection_get_uuid(connection), - nm_device_get_route_table(self, AF_INET), - nm_device_get_route_metric(self, AF_INET), - nm_setting_ip_config_get_dhcp_send_hostname(s_ip4), - nm_setting_ip_config_get_dhcp_hostname(s_ip4), - nm_setting_ip4_config_get_dhcp_fqdn(NM_SETTING_IP4_CONFIG(s_ip4)), - _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET), - _prop_get_connection_mud_url(self, s_con, &mud_url_free), - client_id, - _prop_get_ipvx_dhcp_timeout(self, AF_INET), - priv->dhcp_anycast_address, - NULL, - vendor_class_identifier, - reject_servers, - &error); - if (!priv->dhcp_data_4.client) { - _LOGW(LOGD_DHCP4, "failure to start DHCP: %s", error->message); - g_clear_error(&error); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - priv->dhcp_data_4.state_sigid = g_signal_connect(priv->dhcp_data_4.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK(dhcp4_state_changed), - self); - - if (nm_device_sys_iface_state_is_external_or_assume(self)) - priv->dhcp_data_4.was_active = TRUE; - - /* DHCP devices will be notified by the DHCP manager when stuff happens */ - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -gboolean -nm_device_dhcp4_renew(NMDevice *self, gboolean release) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - g_return_val_if_fail(priv->dhcp_data_4.client != NULL, FALSE); - - _LOGI(LOGD_DHCP4, "DHCPv4 lease renewal requested"); - - /* Terminate old DHCP instance and release the old lease */ - dhcp4_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release); - - /* Start DHCP again on the interface */ - return dhcp4_start(self) != NM_ACT_STAGE_RETURN_FAILURE; -} - -/*****************************************************************************/ - -static NMIP4Config * -shared4_new_config(NMDevice *self, NMConnection *connection) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMIP4Config * config; - NMSettingIPConfig * s_ip4; - NMPlatformIP4Address address = { - .addr_source = NM_IP_CONFIG_SOURCE_SHARED, - }; - - g_return_val_if_fail(self, NULL); - g_return_val_if_fail(connection, NULL); - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (s_ip4 && nm_setting_ip_config_get_num_addresses(s_ip4) > 0) { - /* Use the first user-supplied address */ - NMIPAddress *user = nm_setting_ip_config_get_address(s_ip4, 0); - in_addr_t a; - - nm_ip_address_get_address_binary(user, &a); - nm_platform_ip4_address_set_addr(&address, a, nm_ip_address_get_prefix(user)); - nm_clear_pointer(&priv->shared_ip_handle, nm_netns_shared_ip_release); - } else { - if (!priv->shared_ip_handle) - priv->shared_ip_handle = nm_netns_shared_ip_reserve(nm_device_get_netns(self)); - nm_platform_ip4_address_set_addr(&address, priv->shared_ip_handle->addr, 24); - } - - config = nm_device_ip4_config_new(self); - nm_ip4_config_add_address(config, &address); - - return config; -} - -/*****************************************************************************/ - -static gboolean -connection_ip_method_requires_carrier(NMConnection *connection, - int addr_family, - gboolean * out_ip_enabled) -{ - const char *method; - - method = nm_utils_get_ip_config_method(connection, addr_family); - - if (addr_family == AF_INET) { - NM_SET_OUT(out_ip_enabled, !nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)); - return NM_IN_STRSET(method, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); - } - - NM_SET_OUT(out_ip_enabled, - !NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)); - return NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP, - NM_SETTING_IP6_CONFIG_METHOD_SHARED, - NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL); -} - -static gboolean -connection_requires_carrier(NMConnection *connection) -{ - NMSettingIPConfig * s_ip4, *s_ip6; - NMSettingConnection *s_con; - gboolean ip4_carrier_wanted, ip6_carrier_wanted; - gboolean ip4_used = FALSE, ip6_used = FALSE; - - /* We can progress to IP_CONFIG now, so that we're enslaved. - * That may actually cause carrier to go up and thus continue activation. */ - s_con = nm_connection_get_setting_connection(connection); - if (nm_setting_connection_get_master(s_con)) - return FALSE; - - ip4_carrier_wanted = connection_ip_method_requires_carrier(connection, AF_INET, &ip4_used); - if (ip4_carrier_wanted) { - /* If IPv4 wants a carrier and cannot fail, the whole connection - * requires a carrier regardless of the IPv6 method. - */ - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (s_ip4 && !nm_setting_ip_config_get_may_fail(s_ip4)) - return TRUE; - } - - ip6_carrier_wanted = connection_ip_method_requires_carrier(connection, AF_INET6, &ip6_used); - if (ip6_carrier_wanted) { - /* If IPv6 wants a carrier and cannot fail, the whole connection - * requires a carrier regardless of the IPv4 method. - */ - s_ip6 = nm_connection_get_setting_ip6_config(connection); - if (s_ip6 && !nm_setting_ip_config_get_may_fail(s_ip6)) - return TRUE; - } - - /* If an IP version wants a carrier and the other IP version isn't - * used, the connection requires carrier since it will just fail without one. - */ - if (ip4_carrier_wanted && !ip6_used) - return TRUE; - if (ip6_carrier_wanted && !ip4_used) - return TRUE; - - /* If both want a carrier, the whole connection wants a carrier */ - return ip4_carrier_wanted && ip6_carrier_wanted; -} - -static gboolean -have_any_ready_slaves(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - SlaveInfo * info; - CList * iter; - - /* Any enslaved slave is "ready" in the generic case as it's - * at least >= NM_DEVCIE_STATE_IP_CONFIG and has had Layer 2 - * properties set up. - */ - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry(iter, SlaveInfo, lst_slave); - if (NM_DEVICE_GET_PRIVATE(info->slave)->is_enslaved) - return TRUE; - } - return FALSE; -} - -/*****************************************************************************/ -/* DHCPv6 stuff */ - -static void -dhcp6_cleanup(NMDevice *self, CleanupType cleanup_type, gboolean release) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->dhcp_data_6.was_active = FALSE; - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - applied_config_clear(&priv->dhcp6.ip6_config); - nm_clear_g_free(&priv->dhcp6.event_id); - nm_clear_g_source(&priv->dhcp_data_6.grace_id); - priv->dhcp_data_6.grace_pending = FALSE; - - if (priv->dhcp_data_6.client) { - nm_clear_g_signal_handler(priv->dhcp_data_6.client, &priv->dhcp_data_6.state_sigid); - nm_clear_g_signal_handler(priv->dhcp_data_6.client, &priv->dhcp6.prefix_sigid); - - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) - nm_dhcp_client_stop(priv->dhcp_data_6.client, release); - - g_clear_object(&priv->dhcp_data_6.client); - } - - if (priv->dhcp_data_6.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); - _notify(self, PROP_DHCP6_CONFIG); - } -} - -static gboolean -dhcp6_lease_change(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingsConnection *settings_connection; - - if (!applied_config_get_current(&priv->dhcp6.ip6_config)) { - _LOGW(LOGD_DHCP6, "failed to get DHCPv6 config for rebind"); - return FALSE; - } - - g_assert(priv->dhcp_data_6.client); /* sanity check */ - - settings_connection = nm_device_get_settings_connection(self); - g_assert(settings_connection); - - /* Apply the updated config */ - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) { - _LOGW(LOGD_DHCP6, "failed to update IPv6 config in response to DHCP event"); - return FALSE; - } - - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP6_CHANGE, self, NULL, NULL, NULL, NULL); - - return TRUE; -} - -static void -dhcp6_fail(NMDevice *self, NMDhcpState dhcp_state) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean is_dhcp_managed; - - _LOGD(LOGD_DHCP6, - "DHCPv6 failed (ip_state %s, was_active %d)", - _ip_state_to_string(priv->ip_state_6), - priv->dhcp_data_6.was_active); - - /* The client is always left running after a failure. */ - - /* Nothing to do if we failed before... */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) - goto clear_config; - - is_dhcp_managed = (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED); - - if (is_dhcp_managed) { - /* ... and also if there are static addresses configured - * on the interface. - */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE && priv->con_ip_config_6 - && nm_ip6_config_get_num_addresses(priv->con_ip_config_6)) - goto clear_config; - - /* Fail the method when one of the following is true: - * 1) the DHCP client terminated: it does not make sense to start a grace - * period without a client running; - * 2) we failed to get an initial lease AND the client was - * not active before. - */ - if (dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp_data_6.was_active && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF)) { - nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); - return; - } - - if (dhcp_grace_period_start(self, AF_INET6)) - goto clear_config; - } else { - /* not a hard failure; just live with the RA info */ - dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } - return; - -clear_config: - /* The previous configuration is no longer valid */ - if (priv->dhcp_data_6.config) { - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); - priv->dhcp_data_6.config = nm_dhcp_config_new(AF_INET6); - _notify(self, PROP_DHCP6_CONFIG); - } -} - -static void -dhcp6_state_changed(NMDhcpClient *client, - NMDhcpState state, - NMIP6Config * ip6_config, - GHashTable * options, - gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free char * event_id = NULL; - - g_return_if_fail(nm_dhcp_client_get_addr_family(client) == AF_INET6); - g_return_if_fail(!ip6_config || NM_IS_IP6_CONFIG(ip6_config)); - - _LOGD(LOGD_DHCP6, "new DHCPv6 client state %d", state); - - switch (state) { - case NM_DHCP_STATE_BOUND: - case NM_DHCP_STATE_EXTENDED: - nm_clear_g_source(&priv->dhcp_data_6.grace_id); - priv->dhcp_data_6.grace_pending = FALSE; - /* If the server sends multiple IPv6 addresses, we receive a state - * changed event for each of them. Use the event ID to merge IPv6 - * addresses from the same transaction into a single configuration. - */ - - event_id = nm_dhcp_utils_get_dhcp6_event_id(options); - - if (ip6_config && event_id && priv->dhcp6.event_id - && nm_streq(event_id, priv->dhcp6.event_id)) { - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *a; - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6_config, &a) - applied_config_add_address(&priv->dhcp6.ip6_config, NM_PLATFORM_IP_ADDRESS_CAST(a)); - } else { - nm_clear_g_free(&priv->dhcp6.event_id); - if (ip6_config) { - applied_config_init(&priv->dhcp6.ip6_config, ip6_config); - priv->dhcp6.event_id = g_strdup(event_id); - nm_dhcp_config_set_options(priv->dhcp_data_6.config, options); - _notify(self, PROP_DHCP6_CONFIG); - } else - applied_config_clear(&priv->dhcp6.ip6_config); - } - - /* After long time we have been able to renew the lease: - * update the ip state - */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_CONF); - - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { - if (!applied_config_get_current(&priv->dhcp6.ip6_config)) { - nm_device_ip_method_failed(self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED); - break; - } - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } else if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) - if (!dhcp6_lease_change(self)) - dhcp6_fail(self, state); - break; - case NM_DHCP_STATE_TIMEOUT: - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) - dhcp6_fail(self, state); - else { - /* not a hard failure; just live with the RA info */ - dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, FALSE); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } - break; - case NM_DHCP_STATE_EXPIRE: - /* Ignore expiry before we even have a lease (NAK, old lease, etc) */ - if (priv->ip_state_6 != NM_DEVICE_IP_STATE_CONF) - dhcp6_fail(self, state); - break; - case NM_DHCP_STATE_TERMINATED: - /* In IPv6 info-only mode, the client doesn't handle leases so it - * may exit right after getting a response from the server. That's - * normal. In that case we just ignore the exit. - */ - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) - break; - /* fall-through */ - case NM_DHCP_STATE_DONE: - case NM_DHCP_STATE_FAIL: - dhcp6_fail(self, state); - break; - default: - break; - } -} - -static void -dhcp6_prefix_delegated(NMDhcpClient *client, NMPlatformIP6Address *prefix, gpointer user_data) -{ - NMDevice *self = NM_DEVICE(user_data); - - /* Just re-emit. The device just contributes the prefix to the - * pool in NMPolicy, which decides about subnet allocation - * on the shared devices. */ - g_signal_emit(self, signals[IP6_PREFIX_DELEGATED], 0, prefix); -} - -/*****************************************************************************/ - -static gboolean -dhcp6_start_with_link_ready(NMDevice *self, NMConnection *connection) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingIPConfig *s_ip6; - gs_unref_bytes GBytes *hwaddr = NULL; - gs_unref_bytes GBytes * duid = NULL; - gboolean enforce_duid = FALSE; - const NMPlatformLink * pllink; - gs_free char * mud_url_free = NULL; - GError * error = NULL; - guint32 iaid; - gboolean iaid_explicit; - NMSettingConnection * s_con; - const NMPlatformIP6Address *ll_addr = NULL; - - g_return_val_if_fail(connection, FALSE); - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - nm_assert(s_ip6); - s_con = nm_connection_get_setting_connection(connection); - nm_assert(s_con); - - if (priv->ext_ip6_config_captured) { - ll_addr = nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL); - } - - if (!ll_addr) { - _LOGW(LOGD_DHCP6, "can't start DHCPv6: no link-local address"); - return FALSE; - } - - pllink = nm_platform_link_get(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); - if (pllink) - hwaddr = nmp_link_address_get_as_bytes(&pllink->l_address); - - iaid = _prop_get_ipvx_dhcp_iaid(self, AF_INET6, connection, &iaid_explicit); - duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid); - - priv->dhcp_data_6.client = nm_dhcp_manager_start_ip6( - nm_dhcp_manager_get(), - nm_device_get_multi_index(self), - nm_device_get_ip_iface(self), - nm_device_get_ip_ifindex(self), - &ll_addr->address, - nm_connection_get_uuid(connection), - nm_device_get_route_table(self, AF_INET6), - nm_device_get_route_metric(self, AF_INET6), - nm_setting_ip_config_get_dhcp_send_hostname(s_ip6), - nm_setting_ip_config_get_dhcp_hostname(s_ip6), - _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6), - _prop_get_connection_mud_url(self, s_con, &mud_url_free), - duid, - enforce_duid, - iaid, - iaid_explicit, - _prop_get_ipvx_dhcp_timeout(self, AF_INET6), - priv->dhcp_anycast_address, - (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF) ? TRUE : FALSE, - nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip6)), - priv->dhcp6.needed_prefixes, - &error); - if (!priv->dhcp_data_6.client) { - _LOGW(LOGD_DHCP6, "failure to start DHCPv6: %s", error->message); - g_clear_error(&error); - if (nm_device_sys_iface_state_is_external_or_assume(self)) - priv->dhcp_data_6.was_active = TRUE; - return FALSE; - } - - priv->dhcp_data_6.state_sigid = g_signal_connect(priv->dhcp_data_6.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK(dhcp6_state_changed), - self); - priv->dhcp6.prefix_sigid = g_signal_connect(priv->dhcp_data_6.client, - NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED, - G_CALLBACK(dhcp6_prefix_delegated), - self); - - if (nm_device_sys_iface_state_is_external_or_assume(self)) - priv->dhcp_data_6.was_active = TRUE; - - return TRUE; -} - -static gboolean -dhcp6_start(NMDevice *self, gboolean wait_for_ll) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - - nm_dbus_object_clear_and_unexport(&priv->dhcp_data_6.config); - priv->dhcp_data_6.config = nm_dhcp_config_new(AF_INET6); - - nm_assert(!applied_config_get_current(&priv->dhcp6.ip6_config)); - applied_config_clear(&priv->dhcp6.ip6_config); - nm_clear_g_free(&priv->dhcp6.event_id); - - connection = nm_device_get_applied_connection(self); - g_return_val_if_fail(connection, FALSE); - - if (wait_for_ll) { - /* ensure link local is ready... */ - if (!linklocal6_start(self)) { - /* wait for the LL address to show up */ - return TRUE; - } - /* already have the LL address; kick off DHCP */ - } - - if (!dhcp6_start_with_link_ready(self, connection)) - return FALSE; - - return TRUE; -} - -gboolean -nm_device_dhcp6_renew(NMDevice *self, gboolean release) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - g_return_val_if_fail(priv->dhcp_data_6.client != NULL, FALSE); - - _LOGI(LOGD_DHCP6, "DHCPv6 lease renewal requested"); - - /* Terminate old DHCP instance and release the old lease */ - dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, release); - - /* Start DHCP again on the interface */ - return dhcp6_start(self, FALSE); -} - -/*****************************************************************************/ - -/* - * Called on the requesting interface when a subnet can't be obtained - * from known prefixes for a newly active shared connection. - */ -void -nm_device_request_ip6_prefixes(NMDevice *self, int needed_prefixes) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->dhcp6.needed_prefixes = needed_prefixes; - - if (priv->dhcp_data_6.client) { - _LOGD(LOGD_IP6, "ipv6-pd: asking DHCPv6 for %d prefixes", needed_prefixes); - nm_device_dhcp6_renew(self, FALSE); - } else { - _LOGI(LOGD_IP6, "ipv6-pd: device doesn't use DHCPv6, can't request prefixes"); - } -} - -gboolean -nm_device_needs_ip6_subnet(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->needs_ip6_subnet; -} - -/* - * Called on the ipv6.method=shared interface when a new subnet is allocated - * or the prefix from which it is allocated is renewed. - */ -void -nm_device_use_ip6_subnet(NMDevice *self, const NMPlatformIP6Address *subnet) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMPlatformIP6Address address = *subnet; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - if (!applied_config_get_current(&priv->ac_ip6_config)) - applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); - - /* Assign a ::1 address in the subnet for us. */ - address.address.s6_addr32[3] |= htonl(1); - applied_config_add_address(&priv->ac_ip6_config, NM_PLATFORM_IP_ADDRESS_CAST(&address)); - - _LOGD(LOGD_IP6, - "ipv6-pd: using %s address (preferred for %u seconds)", - _nm_utils_inet6_ntop(&address.address, sbuf), - subnet->preferred); - - /* This also updates the ndisc if there are actual changes. */ - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "ipv6-pd: failed applying IP6 config for connection sharing"); -} - -/* - * Called whenever the policy picks a default IPv6 device. - * The ipv6.method=shared devices just reuse its DNS configuration. - */ -void -nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIP6Config * from_config = NULL; - guint i, len; - - if (applied_config_get_current(&priv->ac_ip6_config)) { - applied_config_reset_nameservers(&priv->ac_ip6_config); - applied_config_reset_searches(&priv->ac_ip6_config); - } else - applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); - - if (from_device) - from_config = nm_device_get_ip6_config(from_device); - if (!from_config) - return; - - len = nm_ip6_config_get_num_nameservers(from_config); - for (i = 0; i < len; i++) { - applied_config_add_nameserver( - &priv->ac_ip6_config, - (const NMIPAddr *) nm_ip6_config_get_nameserver(from_config, i)); - } - - len = nm_ip6_config_get_num_searches(from_config); - for (i = 0; i < len; i++) { - applied_config_add_search(&priv->ac_ip6_config, nm_ip6_config_get_search(from_config, i)); - } - - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "ipv6-pd: failed applying DNS config for connection sharing"); -} - -/*****************************************************************************/ - -static void -linklocal6_failed(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_clear_g_source(&priv->linklocal6_timeout_id); - nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); -} - -static gboolean -linklocal6_timeout_cb(gpointer user_data) -{ - NMDevice *self = user_data; - - _LOGD(LOGD_DEVICE, "linklocal6: waiting for link-local addresses failed due to timeout"); - linklocal6_failed(self); - return G_SOURCE_REMOVE; -} - -static void -linklocal6_check_complete(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - const char * method; - - if (!priv->linklocal6_timeout_id) { - /* we are not waiting for linklocal to complete. Nothing to do. */ - return; - } - - if (!priv->ext_ip6_config_captured - || !nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) { - /* we don't have a non-tentative link local address yet. Wait longer. */ - return; - } - - nm_clear_g_source(&priv->linklocal6_timeout_id); - - connection = nm_device_get_applied_connection(self); - g_assert(connection); - - method = nm_device_get_effective_ip_config_method(self, AF_INET6); - - _LOGD(LOGD_DEVICE, - "linklocal6: waiting for link-local addresses successful, continue with method %s", - method); - - if (NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_SHARED)) - addrconf6_start_with_link_ready(self); - else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { - if (!dhcp6_start_with_link_ready(self, connection)) { - /* Time out IPv6 instead of failing the entire activation */ - nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); - } - } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - else - g_return_if_fail(FALSE); -} - -static void -check_and_add_ipv6ll_addr(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - struct in6_addr lladdr; - NMConnection * connection; - NMSettingIP6Config *s_ip6 = NULL; - GError * error = NULL; - const char * addr_type; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - if (!priv->ipv6ll_handle) - return; - - if (priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE)) { - /* Already have an LL address, nothing to do */ - return; - } - - priv->ipv6ll_has = FALSE; - memset(&priv->ipv6ll_addr, 0, sizeof(priv->ipv6ll_addr)); - - memset(&lladdr, 0, sizeof(lladdr)); - lladdr.s6_addr16[0] = htons(0xfe80); - - connection = nm_device_get_applied_connection(self); - if (connection) - s_ip6 = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection)); - - if (s_ip6 - && nm_setting_ip6_config_get_addr_gen_mode(s_ip6) - == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { - NMUtilsStableType stable_type; - const char * stable_id; - - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); - if (!nm_utils_ipv6_addr_set_stable_privacy(stable_type, - &lladdr, - nm_device_get_iface(self), - stable_id, - priv->linklocal6_dad_counter++, - &error)) { - _LOGW(LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message); - g_clear_error(&error); - linklocal6_failed(self); - return; - } - addr_type = "stable-privacy"; - } else { - NMUtilsIPv6IfaceId iid; - - if (priv->linklocal6_timeout_id) { - /* We already started and attempt to add a LL address. For the EUI-64 - * mode we can't pick a new one, we'll just fail. */ - _LOGW(LOGD_IP6, "linklocal6: DAD failed for an EUI-64 address"); - linklocal6_failed(self); - return; - } - - if (!nm_device_get_ip_iface_identifier(self, &iid, TRUE)) { - _LOGW(LOGD_IP6, "linklocal6: failed to get interface identifier; IPv6 cannot continue"); - return; - } - nm_utils_ipv6_addr_set_interface_identifier(&lladdr, iid); - addr_type = "EUI-64"; - } - - _LOGD(LOGD_IP6, - "linklocal6: generated %s IPv6LL address %s", - addr_type, - _nm_utils_inet6_ntop(&lladdr, sbuf)); - priv->ipv6ll_has = TRUE; - priv->ipv6ll_addr = lladdr; - ip_config_merge_and_apply(self, AF_INET6, TRUE); -} - -static gboolean -linklocal6_start(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_clear_g_source(&priv->linklocal6_timeout_id); - - if (priv->ext_ip6_config_captured - && nm_ip6_config_find_first_address(priv->ext_ip6_config_captured, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL)) - return TRUE; - - _LOGD(LOGD_DEVICE, - "linklocal6: starting IPv6 with method '%s', but the device has no link-local addresses " - "configured. Wait.", - nm_device_get_effective_ip_config_method(self, AF_INET6)); - - check_and_add_ipv6ll_addr(self); - - /* Depending on the network and what the 'dad_transmits' and 'retrans_time_ms' - * sysctl values are, DAD for the IPv6LL address may take quite a while. - * FIXME: use dad/retrans sysctl values if they are higher than a minimum time. - * (rh #1101809) - */ - priv->linklocal6_timeout_id = g_timeout_add_seconds(15, linklocal6_timeout_cb, self); - return FALSE; -} - -/*****************************************************************************/ - -gint64 -nm_device_get_configured_mtu_from_connection_default(NMDevice * self, - const char *property_name, - guint32 max_mtu) -{ - return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - property_name, - self, - 0, - max_mtu, - -1); -} - -guint32 -nm_device_get_configured_mtu_from_connection(NMDevice * self, - GType setting_type, - NMDeviceMtuSource *out_source) -{ - const char * global_property_name; - NMConnection *connection; - NMSetting * setting; - gint64 mtu_default; - guint32 mtu = 0; - guint32 max_mtu = G_MAXUINT32; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(out_source); - - connection = nm_device_get_applied_connection(self); - if (!connection) - g_return_val_if_reached(0); - - setting = nm_connection_get_setting(connection, setting_type); - - if (setting_type == NM_TYPE_SETTING_WIRED) { - if (setting) - mtu = nm_setting_wired_get_mtu(NM_SETTING_WIRED(setting)); - global_property_name = NM_CON_DEFAULT("ethernet.mtu"); - } else if (setting_type == NM_TYPE_SETTING_WIRELESS) { - if (setting) - mtu = nm_setting_wireless_get_mtu(NM_SETTING_WIRELESS(setting)); - global_property_name = NM_CON_DEFAULT("wifi.mtu"); - } else if (setting_type == NM_TYPE_SETTING_INFINIBAND) { - if (setting) - mtu = nm_setting_infiniband_get_mtu(NM_SETTING_INFINIBAND(setting)); - global_property_name = NM_CON_DEFAULT("infiniband.mtu"); - max_mtu = NM_INFINIBAND_MAX_MTU; - } else if (setting_type == NM_TYPE_SETTING_IP_TUNNEL) { - if (setting) - mtu = nm_setting_ip_tunnel_get_mtu(NM_SETTING_IP_TUNNEL(setting)); - global_property_name = NM_CON_DEFAULT("ip-tunnel.mtu"); - } else if (setting_type == NM_TYPE_SETTING_WIREGUARD) { - if (setting) - mtu = nm_setting_wireguard_get_mtu(NM_SETTING_WIREGUARD(setting)); - global_property_name = NM_CON_DEFAULT("wireguard.mtu"); - } else - g_return_val_if_reached(0); - - if (mtu) { - *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; - return mtu; - } - - mtu_default = - nm_device_get_configured_mtu_from_connection_default(self, global_property_name, max_mtu); - if (mtu_default >= 0) { - *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; - return (guint32) mtu_default; - } - - *out_source = NM_DEVICE_MTU_SOURCE_NONE; - return 0; -} - -guint32 -nm_device_get_configured_mtu_for_wired(NMDevice * self, - NMDeviceMtuSource *out_source, - gboolean * out_force) -{ - return nm_device_get_configured_mtu_from_connection(self, NM_TYPE_SETTING_WIRED, out_source); -} - -guint32 -nm_device_get_configured_mtu_wired_parent(NMDevice * self, - NMDeviceMtuSource *out_source, - gboolean * out_force) -{ - guint32 mtu = 0; - guint32 parent_mtu = 0; - int ifindex; - - ifindex = nm_device_parent_get_ifindex(self); - if (ifindex > 0) { - parent_mtu = nm_platform_link_get_mtu(nm_device_get_platform(self), ifindex); - if (parent_mtu >= NM_DEVICE_GET_CLASS(self)->mtu_parent_delta) - parent_mtu -= NM_DEVICE_GET_CLASS(self)->mtu_parent_delta; - else - parent_mtu = 0; - } - - mtu = nm_device_get_configured_mtu_for_wired(self, out_source, NULL); - - if (parent_mtu && mtu > parent_mtu) { - /* Trying to set a MTU that is out of range from configuration: - * fall back to the parent MTU and set force flag so that it - * overrides an MTU with higher priority already configured. - */ - *out_source = NM_DEVICE_MTU_SOURCE_PARENT; - *out_force = TRUE; - return parent_mtu; - } - - if (*out_source != NM_DEVICE_MTU_SOURCE_NONE) { - nm_assert(mtu > 0); - return mtu; - } - - /* Inherit the MTU from parent device, if any */ - if (parent_mtu) { - mtu = parent_mtu; - *out_source = NM_DEVICE_MTU_SOURCE_PARENT; - } - - return mtu; -} - -/*****************************************************************************/ - -static void -_set_mtu(NMDevice *self, guint32 mtu) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->mtu == mtu) - return; - - priv->mtu = mtu; - _notify(self, PROP_MTU); - - if (priv->master) { - /* changing the MTU of a slave, might require the master to reset - * its MTU. Note that the master usually cannot set a MTU larger - * then the slave's. Hence, when the slave increases the MTU, - * master might want to retry setting the MTU. */ - nm_device_commit_mtu(priv->master); - } -} - -static gboolean -set_platform_mtu(NMDevice *self, guint32 mtu) -{ - int r; - - r = nm_platform_link_set_mtu(nm_device_get_platform(self), nm_device_get_ip_ifindex(self), mtu); - return (r != -NME_PL_CANT_SET_MTU); -} - -static void -_commit_mtu(NMDevice *self, const NMIP4Config *config) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceMtuSource source = NM_DEVICE_MTU_SOURCE_NONE; - guint32 ip6_mtu, ip6_mtu_orig; - guint32 mtu_desired, mtu_desired_orig; - guint32 mtu_plat; - struct { - gboolean initialized; - guint32 value; - } ip6_mtu_sysctl = { - 0, - }; - int ifindex; - char sbuf[64], sbuf1[64], sbuf2[64]; - gboolean success = TRUE; - - ifindex = nm_device_get_ip_ifindex(self); - if (ifindex <= 0) - return; - - if (!nm_device_get_applied_connection(self) - || nm_device_sys_iface_state_is_external_or_assume(self)) { - /* we don't tamper with the MTU of disconnected and - * external/assumed devices. */ - return; - } - - { - guint32 mtu = 0; - gboolean force = FALSE; - - /* We take the MTU from various sources: (in order of increasing - * priority) parent link, IP configuration (which contains the - * MTU from DHCP/PPP), connection profile. - * - * We could just compare it with the platform MTU and apply it - * when different, but this would revert at random times manual - * changes done by the user with the MTU from the connection. - * - * Instead, we remember the source of the currently configured - * MTU and apply the new one only when the new source has a - * higher priority, so that we don't set a MTU from same source - * multiple times. An exception to this is for the PARENT - * source, since we need to keep tracking the parent MTU when it - * changes. - * - * The subclass can set the @force argument to TRUE to signal that the - * returned MTU should be applied even if it has a lower priority. This - * is useful when the value from a lower source should - * preempt the one from higher ones. - */ - - if (NM_DEVICE_GET_CLASS(self)->get_configured_mtu) - mtu = NM_DEVICE_GET_CLASS(self)->get_configured_mtu(self, &source, &force); - - if (config && !force && source < NM_DEVICE_MTU_SOURCE_IP_CONFIG - && nm_ip4_config_get_mtu(config)) { - mtu = nm_ip4_config_get_mtu(config); - source = NM_DEVICE_MTU_SOURCE_IP_CONFIG; - } - - if (mtu != 0) { - _LOGT(LOGD_DEVICE, - "mtu: value %u from source '%s' (%u), current source '%s' (%u)%s", - (guint) mtu, - mtu_source_to_str(source), - (guint) source, - mtu_source_to_str(priv->mtu_source), - (guint) priv->mtu_source, - force ? " (forced)" : ""); - } - - if (mtu != 0 - && (force || source > priv->mtu_source - || (priv->mtu_source == NM_DEVICE_MTU_SOURCE_PARENT && source == priv->mtu_source))) - mtu_desired = mtu; - else { - mtu_desired = 0; - source = NM_DEVICE_MTU_SOURCE_NONE; - } - } - - if (mtu_desired && mtu_desired < 1280) { - NMSettingIPConfig *s_ip6; - - s_ip6 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP6_CONFIG); - if (s_ip6 - && !NM_IN_STRSET(nm_setting_ip_config_get_method(s_ip6), - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { - /* the interface has IPv6 enabled. The MTU with IPv6 cannot be smaller - * then 1280. - * - * For slave-devices (that don't have @s_ip6 we) don't do this fixup because - * it's anyway an unsolved problem when the slave configures a conflicting - * MTU. */ - mtu_desired = 1280; - } - } - - ip6_mtu = priv->ip6_mtu; - if (!ip6_mtu && priv->mtu_source == NM_DEVICE_MTU_SOURCE_NONE) { - /* initially, if the IPv6 MTU is not specified, grow it as large as the - * link MTU @mtu_desired. Only exception is, if @mtu_desired is so small - * to disable IPv6. */ - if (mtu_desired >= 1280) - ip6_mtu = mtu_desired; - } - - if (!ip6_mtu && !mtu_desired) - return; - - mtu_desired_orig = mtu_desired; - ip6_mtu_orig = ip6_mtu; - - mtu_plat = nm_platform_link_get_mtu(nm_device_get_platform(self), ifindex); - - if (ip6_mtu) { - ip6_mtu = NM_MAX(1280, ip6_mtu); - - if (!mtu_desired) - mtu_desired = mtu_plat; - - if (mtu_desired) { - mtu_desired = NM_MAX(1280, mtu_desired); - - if (mtu_desired < ip6_mtu) - ip6_mtu = mtu_desired; - } - } - - if (mtu_desired && NM_DEVICE_GET_CLASS(self)->mtu_force_set && !priv->mtu_force_set_done) { - priv->mtu_force_set_done = TRUE; - - if (mtu_desired == mtu_plat) { - mtu_plat--; - if (NM_DEVICE_GET_CLASS(self)->set_platform_mtu(self, mtu_desired - 1)) { - _LOGD(LOGD_DEVICE, "mtu: force-set MTU to %u", mtu_desired - 1); - } else - _LOGW(LOGD_DEVICE, "mtu: failure to force-set MTU to %u", mtu_desired - 1); - } - } - - _LOGT(LOGD_DEVICE, - "mtu: device-mtu: %u%s, ipv6-mtu: %u%s, ifindex: %d", - (guint) mtu_desired, - mtu_desired == mtu_desired_orig - ? "" - : nm_sprintf_buf(sbuf1, " (was %u)", (guint) mtu_desired_orig), - (guint) ip6_mtu, - ip6_mtu == ip6_mtu_orig ? "" : nm_sprintf_buf(sbuf2, " (was %u)", (guint) ip6_mtu_orig), - ifindex); - -#define _IP6_MTU_SYS() \ - ({ \ - if (!ip6_mtu_sysctl.initialized) { \ - ip6_mtu_sysctl.value = nm_device_sysctl_ip_conf_get_int_checked(self, \ - AF_INET6, \ - "mtu", \ - 10, \ - 0, \ - G_MAXUINT32, \ - 0); \ - ip6_mtu_sysctl.initialized = TRUE; \ - } \ - ip6_mtu_sysctl.value; \ - }) - if ((mtu_desired && mtu_desired != mtu_plat) || (ip6_mtu && ip6_mtu != _IP6_MTU_SYS())) { - gboolean anticipated_failure = FALSE; - - if (!priv->mtu_initial && !priv->ip6_mtu_initial) { - /* before touching any of the MTU parameters, record the - * original setting to restore on deactivation. */ - priv->mtu_initial = mtu_plat; - priv->ip6_mtu_initial = _IP6_MTU_SYS(); - } - - if (mtu_desired && mtu_desired != mtu_plat) { - if (!NM_DEVICE_GET_CLASS(self)->set_platform_mtu(self, mtu_desired)) { - anticipated_failure = TRUE; - success = FALSE; - _LOGW(LOGD_DEVICE, - "mtu: failure to set MTU. %s", - NM_IS_DEVICE_VLAN(self) - ? "Is the parent's MTU size large enough?" - : (!c_list_is_empty(&priv->slaves) - ? "Are the MTU sizes of the slaves large enough?" - : "Did you configure the MTU correctly?")); - } - priv->carrier_wait_until_ms = - nm_utils_get_monotonic_timestamp_msec() + CARRIER_WAIT_TIME_AFTER_MTU_MS; - } - - if (ip6_mtu && ip6_mtu != _IP6_MTU_SYS()) { - if (!nm_device_sysctl_ip_conf_set(self, - AF_INET6, - "mtu", - nm_sprintf_buf(sbuf, "%u", (unsigned) ip6_mtu))) { - int errsv = errno; - NMLogLevel level = LOGL_WARN; - const char *msg = NULL; - - success = FALSE; - - if (anticipated_failure && errsv == EINVAL) { - level = LOGL_DEBUG; - msg = "Is the underlying MTU value successfully set?"; - } else if (!g_file_test("/proc/sys/net/ipv6", G_FILE_TEST_IS_DIR)) { - level = LOGL_DEBUG; - msg = "IPv6 is disabled"; - success = TRUE; - } - - _NMLOG(level, - LOGD_DEVICE, - "mtu: failure to set IPv6 MTU%s%s", - msg ? ": " : "", - msg ?: ""); - } - priv->carrier_wait_until_ms = - nm_utils_get_monotonic_timestamp_msec() + CARRIER_WAIT_TIME_AFTER_MTU_MS; - } - } - - if (success && source != NM_DEVICE_MTU_SOURCE_NONE) - priv->mtu_source = source; - -#undef _IP6_MTU_SYS -} - -void -nm_device_commit_mtu(NMDevice *self) -{ - NMDeviceState state; - - g_return_if_fail(NM_IS_DEVICE(self)); - - state = nm_device_get_state(self); - if (state >= NM_DEVICE_STATE_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) { - _LOGT(LOGD_DEVICE, "mtu: commit-mtu..."); - _commit_mtu(self, NM_DEVICE_GET_PRIVATE(self)->ip_config_4); - } else - _LOGT(LOGD_DEVICE, - "mtu: commit-mtu... skip due to state %s", - nm_device_state_to_str(state)); -} - -static void -ndisc_config_changed(NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_int, NMDevice *self) -{ - NMNDiscConfigMap changed = changed_int; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - guint i; - - g_return_if_fail(priv->act_request.obj); - - if (!applied_config_get_current(&priv->ac_ip6_config)) - applied_config_init_new(&priv->ac_ip6_config, self, AF_INET6); - - if (changed & NM_NDISC_CONFIG_ADDRESSES) { - guint8 plen; - guint32 ifa_flags; - - /* Check, whether kernel is recent enough to help user space handling RA. - * If it's not supported, we have no ipv6-privacy and must add autoconf - * addresses as /128. The reason for the /128 is to prevent the kernel - * from adding a prefix route for this address. */ - ifa_flags = 0; - if (nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) { - ifa_flags |= IFA_F_NOPREFIXROUTE; - if (NM_IN_SET(priv->ndisc_use_tempaddr, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)) - ifa_flags |= IFA_F_MANAGETEMPADDR; - plen = 64; - } else - plen = 128; - - nm_ip6_config_reset_addresses_ndisc((NMIP6Config *) priv->ac_ip6_config.orig, - rdata->addresses, - rdata->addresses_n, - plen, - ifa_flags); - if (priv->ac_ip6_config.current) { - nm_ip6_config_reset_addresses_ndisc((NMIP6Config *) priv->ac_ip6_config.current, - rdata->addresses, - rdata->addresses_n, - plen, - ifa_flags); - } - } - - if (NM_FLAGS_ANY(changed, NM_NDISC_CONFIG_ROUTES | NM_NDISC_CONFIG_GATEWAYS)) { - nm_ip6_config_reset_routes_ndisc( - (NMIP6Config *) priv->ac_ip6_config.orig, - rdata->gateways, - rdata->gateways_n, - rdata->routes, - rdata->routes_n, - nm_device_get_route_table(self, AF_INET6), - nm_device_get_route_metric(self, AF_INET6), - nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); - if (priv->ac_ip6_config.current) { - nm_ip6_config_reset_routes_ndisc( - (NMIP6Config *) priv->ac_ip6_config.current, - rdata->gateways, - rdata->gateways_n, - rdata->routes, - rdata->routes_n, - nm_device_get_route_table(self, AF_INET6), - nm_device_get_route_metric(self, AF_INET6), - nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_RTA_PREF)); - } - } - - if (changed & NM_NDISC_CONFIG_DNS_SERVERS) { - /* Rebuild DNS server list from neighbor discovery cache. */ - applied_config_reset_nameservers(&priv->ac_ip6_config); - - for (i = 0; i < rdata->dns_servers_n; i++) - applied_config_add_nameserver(&priv->ac_ip6_config, - (const NMIPAddr *) &rdata->dns_servers[i].address); - } - - if (changed & NM_NDISC_CONFIG_DNS_DOMAINS) { - /* Rebuild domain list from neighbor discovery cache. */ - applied_config_reset_searches(&priv->ac_ip6_config); - - for (i = 0; i < rdata->dns_domains_n; i++) - applied_config_add_search(&priv->ac_ip6_config, rdata->dns_domains[i].domain); - } - - if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) { - dhcp6_cleanup(self, CLEANUP_TYPE_DECONFIGURE, TRUE); - - priv->dhcp6.mode = rdata->dhcp_level; - if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE) { - _LOGD(LOGD_DEVICE | LOGD_DHCP6, - "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" - " as requested by IPv6 router..."); - if (!dhcp6_start(self, FALSE)) { - if (priv->dhcp6.mode == NM_NDISC_DHCP_LEVEL_MANAGED) { - nm_device_state_changed(self, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DHCP_START_FAILED); - return; - } - } - } - } - - if (changed & NM_NDISC_CONFIG_HOP_LIMIT) - nm_platform_sysctl_ip_conf_set_ipv6_hop_limit_safe(nm_device_get_platform(self), - nm_device_get_ip_iface(self), - rdata->hop_limit); - - if (changed & NM_NDISC_CONFIG_REACHABLE_TIME) { - nm_platform_sysctl_ip_neigh_set_ipv6_reachable_time(nm_device_get_platform(self), - nm_device_get_ip_iface(self), - rdata->reachable_time_ms); - } - - if (changed & NM_NDISC_CONFIG_RETRANS_TIMER) { - nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(nm_device_get_platform(self), - nm_device_get_ip_iface(self), - rdata->retrans_timer_ms); - } - - if (changed & NM_NDISC_CONFIG_MTU) { - if (priv->ip6_mtu != rdata->mtu) { - _LOGD(LOGD_DEVICE, "mtu: set IPv6 MTU to %u", (guint) rdata->mtu); - priv->ip6_mtu = rdata->mtu; - } - } - - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); -} - -static void -ndisc_ra_timeout(NMNDisc *ndisc, NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - /* We don't want to stop listening for router advertisements completely, - * but instead let device activation continue activating. If an RA - * shows up later, we'll use it as long as the device is not disconnected. - */ - - _LOGD(LOGD_IP6, "timed out waiting for IPv6 router advertisement"); - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { - /* If RA is our only source of addressing information and we don't - * ever receive one, then time out IPv6. But if there is other - * IPv6 configuration, like manual IPv6 addresses or external IPv6 - * config, consider that sufficient for IPv6 success. - * - * FIXME: it doesn't seem correct to determine this based on which - * addresses we find inside priv->ip_config_6. - */ - if (priv->ip_config_6 - && nm_ip6_config_find_first_address(priv->ip_config_6, - NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL - | NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - else - nm_device_activate_schedule_ip_config_timeout(self, AF_INET6); - } -} - -static void -addrconf6_start_with_link_ready(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMUtilsIPv6IfaceId iid; - - g_assert(priv->ndisc); - - if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) { - _LOGD(LOGD_IP6, "addrconf6: using the device EUI-64 identifier"); - nm_ndisc_set_iid(priv->ndisc, iid); - } else { - /* Don't abort the addrconf at this point -- if ndisc needs the iid - * it will notice this itself. */ - _LOGI(LOGD_IP6, "addrconf6: no interface identifier; IPv6 address creation may fail"); - } - - /* Apply any manual configuration before starting RA */ - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "failed to apply manual IPv6 configuration"); - - if (nm_ndisc_get_node_type(priv->ndisc) == NM_NDISC_NODE_TYPE_ROUTER) { - nm_device_sysctl_ip_conf_set(self, AF_INET6, "forwarding", "1"); - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - priv->needs_ip6_subnet = TRUE; - g_signal_emit(self, signals[IP6_SUBNET_NEEDED], 0); - } - - priv->ndisc_changed_id = g_signal_connect(priv->ndisc, - NM_NDISC_CONFIG_RECEIVED, - G_CALLBACK(ndisc_config_changed), - self); - priv->ndisc_timeout_id = g_signal_connect(priv->ndisc, - NM_NDISC_RA_TIMEOUT_SIGNAL, - G_CALLBACK(ndisc_ra_timeout), - self); - - ndisc_set_router_config(priv->ndisc, self); - nm_ndisc_start(priv->ndisc); - priv->ndisc_started = TRUE; - return; -} - -static gboolean -addrconf6_start(NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - NMSettingIP6Config *s_ip6 = NULL; - GError * error = NULL; - NMUtilsStableType stable_type; - const char * stable_id; - NMNDiscNodeType node_type; - int max_addresses; - int router_solicitations; - int router_solicitation_interval; - guint32 ra_timeout; - guint32 default_ra_timeout; - - connection = nm_device_get_applied_connection(self); - g_assert(connection); - - nm_assert(!applied_config_get_current(&priv->ac_ip6_config)); - applied_config_clear(&priv->ac_ip6_config); - - nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source(&priv->rt6_temporary_not_available_id); - - s_ip6 = NM_SETTING_IP6_CONFIG(nm_connection_get_setting_ip6_config(connection)); - g_assert(s_ip6); - - if (nm_streq(nm_device_get_effective_ip_config_method(self, AF_INET6), - NM_SETTING_IP4_CONFIG_METHOD_SHARED)) - node_type = NM_NDISC_NODE_TYPE_ROUTER; - else - node_type = NM_NDISC_NODE_TYPE_HOST; - - nm_lndp_ndisc_get_sysctl(nm_device_get_platform(self), - nm_device_get_ip_iface(self), - &max_addresses, - &router_solicitations, - &router_solicitation_interval, - &default_ra_timeout); - - if (node_type == NM_NDISC_NODE_TYPE_ROUTER) - ra_timeout = 0u; - else { - ra_timeout = _prop_get_ipv6_ra_timeout(self); - if (ra_timeout == 0u) - ra_timeout = default_ra_timeout; - } - - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); - priv->ndisc = nm_lndp_ndisc_new(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - nm_device_get_ip_iface(self), - stable_type, - stable_id, - nm_setting_ip6_config_get_addr_gen_mode(s_ip6), - node_type, - max_addresses, - router_solicitations, - router_solicitation_interval, - ra_timeout, - &error); - if (!priv->ndisc) { - _LOGE(LOGD_IP6, "addrconf6: failed to start neighbor discovery: %s", error->message); - g_error_free(error); - return FALSE; - } - - priv->ndisc_use_tempaddr = use_tempaddr; - - if (NM_IN_SET(use_tempaddr, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, - NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) - && !nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_EXTENDED_IFA_FLAGS)) { - _LOGW(LOGD_IP6, - "The kernel does not support extended IFA_FLAGS needed by NM for " - "IPv6 private addresses. This feature is not available"); - } - - /* ensure link local is ready... */ - if (!linklocal6_start(self)) { - /* wait for the LL address to show up */ - return TRUE; - } - - /* already have the LL address; kick off neighbor discovery */ - addrconf6_start_with_link_ready(self); - return TRUE; -} - -static void -addrconf6_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->ndisc_started = FALSE; - nm_clear_g_signal_handler(priv->ndisc, &priv->ndisc_changed_id); - nm_clear_g_signal_handler(priv->ndisc, &priv->ndisc_timeout_id); - - applied_config_clear(&priv->ac_ip6_config); - nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source(&priv->rt6_temporary_not_available_id); - if (priv->ndisc) { - nm_ndisc_stop(priv->ndisc); - g_clear_object(&priv->ndisc); - } -} - -/*****************************************************************************/ - -static void -save_ip6_properties(NMDevice *self) -{ - static const char *const ip6_properties_to_save[] = { - "accept_ra", - "forwarding", - "disable_ipv6", - "hop_limit", - "use_tempaddr", - }; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMPlatform * platform = nm_device_get_platform(self); - const char * ifname; - char * value; - int i; - - g_hash_table_remove_all(priv->ip6_saved_properties); - - ifname = nm_device_get_ip_iface_from_platform(self); - if (!ifname) - return; - - for (i = 0; i < G_N_ELEMENTS(ip6_properties_to_save); i++) { - value = - nm_platform_sysctl_ip_conf_get(platform, AF_INET6, ifname, ip6_properties_to_save[i]); - if (value) { - g_hash_table_insert(priv->ip6_saved_properties, - (char *) ip6_properties_to_save[i], - value); - } - } -} - -static void -restore_ip6_properties(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - GHashTableIter iter; - gpointer key, value; - - g_hash_table_iter_init(&iter, priv->ip6_saved_properties); - while (g_hash_table_iter_next(&iter, &key, &value)) { - /* Don't touch "disable_ipv6" if we're doing userland IPv6LL */ - if (priv->ipv6ll_handle && nm_streq(key, "disable_ipv6")) - continue; - nm_device_sysctl_ip_conf_set(self, AF_INET6, key, value); - } -} - -static void -set_disable_ipv6(NMDevice *self, const char *value) -{ - /* We only touch disable_ipv6 when NM is not managing the IPv6LL address */ - if (!NM_DEVICE_GET_PRIVATE(self)->ipv6ll_handle) - nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", value); -} - -static void -set_nm_ipv6ll(NMDevice *self, gboolean enable) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - int ifindex = nm_device_get_ip_ifindex(self); - - if (!nm_platform_kernel_support_get(NM_PLATFORM_KERNEL_SUPPORT_TYPE_USER_IPV6LL)) - return; - - priv->ipv6ll_handle = enable; - if (ifindex > 0) { - const char *detail = enable ? "enable" : "disable"; - int r; - - _LOGD(LOGD_IP6, "will %s userland IPv6LL", detail); - r = nm_platform_link_set_user_ipv6ll_enabled(nm_device_get_platform(self), ifindex, enable); - if (r < 0) { - _NMLOG(NM_IN_SET(r, -NME_PL_NOT_FOUND, -NME_PL_OPNOTSUPP) ? LOGL_DEBUG : LOGL_WARN, - LOGD_IP6, - "failed to %s userspace IPv6LL address handling (%s)", - detail, - nm_strerror(r)); - } - - if (enable) { - gs_free char *value = NULL; - - /* Bounce IPv6 to ensure the kernel stops IPv6LL address generation */ - value = nm_device_sysctl_ip_conf_get(self, AF_INET6, "disable_ipv6"); - if (nm_streq0(value, "0")) - nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1"); - - /* Ensure IPv6 is enabled */ - nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "0"); - } - } -} - -/*****************************************************************************/ - -static gboolean -ip_requires_slaves(NMDevice *self, int addr_family) -{ - const char *method; - - method = nm_device_get_effective_ip_config_method(self, addr_family); - - if (addr_family == AF_INET) - return nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - - /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) - * to complete addressing. SLAAC and DHCP need a peer to provide a prefix. - */ - return NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP); -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * self, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - const char * method; - - nm_assert_addr_family(addr_family); - - connection = nm_device_get_applied_connection(self); - - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - if (connection_ip_method_requires_carrier(connection, addr_family, NULL) - && nm_device_is_master(self) && !priv->carrier) { - _LOGI(LOGD_IP | LOGD_DEVICE, - "IPv%c config waiting until carrier is on", - nm_utils_addr_family_to_char(addr_family)); - return NM_ACT_STAGE_RETURN_IP_WAIT; - } - - if (nm_device_is_master(self) && ip_requires_slaves(self, addr_family)) { - /* If the master has no ready slaves, and depends on slaves for - * a successful IP configuration attempt, then postpone IP addressing. - */ - if (!have_any_ready_slaves(self)) { - _LOGI(LOGD_DEVICE | LOGD_IP, - "IPv%c config waiting until slaves are ready", - nm_utils_addr_family_to_char(addr_family)); - return NM_ACT_STAGE_RETURN_IP_WAIT; - } - } - - if (!IS_IPv4) - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; - - method = nm_device_get_effective_ip_config_method(self, addr_family); - - _LOGD(LOGD_IP | LOGD_DEVICE, - "IPv%c config method is %s", - nm_utils_addr_family_to_char(addr_family), - method); - - if (IS_IPv4) { - if (NM_IN_STRSET(method, - NM_SETTING_IP4_CONFIG_METHOD_AUTO, - NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) { - NMSettingIPConfig *s_ip4; - NMIP4Config ** configs, *config; - guint num_addresses; - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - g_return_val_if_fail(s_ip4, NM_ACT_STAGE_RETURN_FAILURE); - num_addresses = nm_setting_ip_config_get_num_addresses(s_ip4); - - if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - ret = dhcp4_start(self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_DHCP_START_FAILED); - return ret; - } - } else { - g_return_val_if_fail(num_addresses != 0, NM_ACT_STAGE_RETURN_FAILURE); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (num_addresses) { - config = nm_device_ip4_config_new(self); - nm_ip4_config_merge_setting(config, - nm_connection_get_setting_ip4_config(connection), - NM_SETTING_CONNECTION_MDNS_DEFAULT, - NM_SETTING_CONNECTION_LLMNR_DEFAULT, - nm_device_get_route_table(self, AF_INET), - nm_device_get_route_metric(self, AF_INET)); - configs = g_new0(NMIP4Config *, 2); - configs[0] = config; - ipv4_dad_start(self, configs, ipv4_manual_method_apply); - } - } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { - ret = ipv4ll_start(self); - if (ret == NM_ACT_STAGE_RETURN_FAILURE) - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED); - } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - if (out_config) { - *out_config = shared4_new_config(self, connection); - if (*out_config) { - priv->dnsmasq_manager = nm_dnsmasq_manager_new(nm_device_get_ip_iface(self)); - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - } else - g_return_val_if_reached(NM_ACT_STAGE_RETURN_FAILURE); - } else if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - ret = NM_ACT_STAGE_RETURN_SUCCESS; - else - _LOGW(LOGD_IP4, "unhandled IPv4 config method '%s'; will fail", method); - - return ret; - } else { - NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - const char * ip6_privacy_str = "0"; - NMPlatform * platform; - int ifindex; - - if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { - nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1"); - return NM_ACT_STAGE_RETURN_IP_DONE; - } - - if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { - if (!nm_device_sys_iface_state_is_external(self)) { - if (priv->master) { - /* If a device only has an IPv6 link-local address, - * we don't generate an assumed connection. Therefore, - * when a new slave connection (without IP configuration) - * is activated on the device, the link-local address - * remains configured. The IP configuration of an activated - * slave should not depend on the previous state. Flush - * addresses and routes on activation. - */ - ifindex = nm_device_get_ip_ifindex(self); - platform = nm_device_get_platform(self); - - if (ifindex > 0) { - gs_unref_object NMIP6Config *config = nm_device_ip6_config_new(self); - - nm_platform_ip_route_flush(platform, AF_INET6, ifindex); - nm_platform_ip_address_flush(platform, AF_INET6, ifindex); - nm_device_set_ip_config(self, AF_INET6, (NMIPConfig *) config, FALSE, NULL); - } - } else { - gboolean ipv6ll_handle_old = priv->ipv6ll_handle; - - /* When activating an IPv6 'ignore' connection we need to revert back - * to kernel IPv6LL, but the kernel won't actually assign an address - * to the interface until disable_ipv6 is bounced. - */ - set_nm_ipv6ll(self, FALSE); - if (ipv6ll_handle_old) - nm_device_sysctl_ip_conf_set(self, AF_INET6, "disable_ipv6", "1"); - restore_ip6_properties(self); - } - } - return NM_ACT_STAGE_RETURN_IP_DONE; - } - - /* Ensure the MTU makes sense. If it was below 1280 the kernel would not - * expose any ipv6 sysctls or allow presence of any addresses on the interface, - * including LL, which * would make it impossible to autoconfigure MTU to a - * correct value. */ - _commit_mtu(self, priv->ip_config_4); - - /* Any method past this point requires an IPv6LL address. Use NM-controlled - * IPv6LL if this is not an assumed connection, since assumed connections - * will already have IPv6 set up. - */ - if (!nm_device_sys_iface_state_is_external_or_assume(self)) - set_nm_ipv6ll(self, TRUE); - - /* Re-enable IPv6 on the interface */ - nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", "0"); - set_disable_ipv6(self, "0"); - - /* Synchronize external IPv6 configuration with kernel, since - * linklocal6_start() uses the information there to determine if we can - * proceed with the selected method (SLAAC, DHCP, link-local). - */ - nm_platform_process_events(nm_device_get_platform(self)); - g_clear_object(&priv->ext_ip6_config_captured); - priv->ext_ip6_config_captured = - nm_ip6_config_capture(nm_device_get_multi_index(self), - nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - - ip6_privacy = _prop_get_ipv6_ip6_privacy(self); - - if (NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - if (!addrconf6_start(self, ip6_privacy)) { - /* IPv6 might be disabled; allow IPv4 to proceed */ - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - } else - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { - ret = - linklocal6_start(self) ? NM_ACT_STAGE_RETURN_SUCCESS : NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { - priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_MANAGED; - if (!dhcp6_start(self, TRUE)) { - /* IPv6 might be disabled; allow IPv4 to proceed */ - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - } else - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) - ret = NM_ACT_STAGE_RETURN_SUCCESS; - else - _LOGW(LOGD_IP6, "unhandled IPv6 config method '%s'; will fail", method); - - if (ret != NM_ACT_STAGE_RETURN_FAILURE - && !nm_device_sys_iface_state_is_external_or_assume(self)) { - switch (ip6_privacy) { - case NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN: - case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: - ip6_privacy_str = "0"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR: - ip6_privacy_str = "1"; - break; - case NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR: - ip6_privacy_str = "2"; - break; - } - nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", ip6_privacy_str); - } - - return ret; - } -} - -/** - * nm_device_activate_stage3_ip4_start: - * @self: the device - * - * Try starting IPv4 configuration. - */ -gboolean -nm_device_activate_stage3_ip4_start(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMActStageReturn ret; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - gs_unref_object NMIP4Config *ip4_config = NULL; - - g_assert(priv->ip_state_4 == NM_DEVICE_IP_STATE_WAIT); - - if (nm_device_sys_iface_state_is_external(self)) { - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); - check_ip_state(self, FALSE, TRUE); - return TRUE; - } - - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_CONF); - ret = NM_DEVICE_GET_CLASS(self)->act_stage3_ip_config_start(self, - AF_INET, - (gpointer *) &ip4_config, - &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) - nm_device_activate_schedule_ip_config_result(self, AF_INET, NM_IP_CONFIG_CAST(ip4_config)); - else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); - check_ip_state(self, FALSE, TRUE); - } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); - return FALSE; - } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { - /* Activation not wanted */ - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_FAIL); - } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { - /* Wait for something to try IP config again */ - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_WAIT); - } else - g_assert(ret == NM_ACT_STAGE_RETURN_POSTPONE); - - return TRUE; -} - -/** - * nm_device_activate_stage3_ip6_start: - * @self: the device - * - * Try starting IPv6 configuration. - */ -gboolean -nm_device_activate_stage3_ip6_start(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMActStageReturn ret; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - gs_unref_object NMIP6Config *ip6_config = NULL; - - g_assert(priv->ip_state_6 == NM_DEVICE_IP_STATE_WAIT); - - if (nm_device_sys_iface_state_is_external(self)) { - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_DONE); - check_ip_state(self, FALSE, TRUE); - return TRUE; - } - - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_CONF); - ret = NM_DEVICE_GET_CLASS(self)->act_stage3_ip_config_start(self, - AF_INET6, - (gpointer *) &ip6_config, - &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { - if (!ip6_config) - ip6_config = nm_device_ip6_config_new(self); - /* Here we get a static IPv6 config, like for Shared where it's - * autogenerated or from modems where it comes from ModemManager. - */ - nm_assert(!applied_config_get_current(&priv->ac_ip6_config)); - applied_config_init(&priv->ac_ip6_config, ip6_config); - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) { - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_DONE); - check_ip_state(self, FALSE, TRUE); - } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); - return FALSE; - } else if (ret == NM_ACT_STAGE_RETURN_IP_FAIL) { - /* Activation not wanted */ - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_FAIL); - } else if (ret == NM_ACT_STAGE_RETURN_IP_WAIT) { - /* Wait for something to try IP config again */ - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); - } else - g_assert(ret == NM_ACT_STAGE_RETURN_POSTPONE); - - return TRUE; -} - -/* - * activate_stage3_ip_config_start - * - * Begin automatic/manual IP configuration - * - */ -static void -activate_stage3_ip_config_start(NMDevice *self) -{ - int ifindex; - - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_WAIT); - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); - - _active_connection_set_state_flags(self, NM_ACTIVATION_STATE_FLAG_LAYER2_READY); - - nm_device_state_changed(self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); - - /* Device should be up before we can do anything with it */ - if ((ifindex = nm_device_get_ip_ifindex(self)) > 0 - && !nm_platform_link_is_up(nm_device_get_platform(self), ifindex)) - _LOGW(LOGD_DEVICE, - "interface %s not up for IP configuration", - nm_device_get_ip_iface(self)); - - /* IPv4 */ - if (nm_device_activate_ip4_state_in_wait(self) && !nm_device_activate_stage3_ip4_start(self)) - return; - - /* IPv6 */ - if (nm_device_activate_ip6_state_in_wait(self) && !nm_device_activate_stage3_ip6_start(self)) - return; - - /* Proxy */ - nm_device_set_proxy_config(self, NULL); - - check_ip_state(self, TRUE, TRUE); -} - -static void -fw_change_zone_cb(NMFirewallManager * firewall_manager, - NMFirewallManagerCallId *call_id, - GError * error, - gpointer user_data) -{ - NMDevice * self = user_data; - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->fw_call != call_id) - g_return_if_reached(); - - priv->fw_call = NULL; - - if (nm_utils_error_is_cancelled(error)) - return; - - switch (priv->fw_state) { - case FIREWALL_STATE_WAIT_STAGE_3: - priv->fw_state = FIREWALL_STATE_INITIALIZED; - nm_device_activate_schedule_stage3_ip_config_start(self); - break; - case FIREWALL_STATE_WAIT_IP_CONFIG: - priv->fw_state = FIREWALL_STATE_INITIALIZED; - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - || priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) - nm_device_start_ip_check(self); - break; - case FIREWALL_STATE_INITIALIZED: - break; - default: - g_return_if_reached(); - } -} - -static void -fw_change_zone(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * applied_connection; - NMSettingConnection *s_con; - const char * zone; - - nm_assert(priv->fw_state >= FIREWALL_STATE_INITIALIZED); - - applied_connection = nm_device_get_applied_connection(self); - nm_assert(applied_connection); - - s_con = nm_connection_get_setting_connection(applied_connection); - nm_assert(s_con); - - if (priv->fw_call) { - nm_firewall_manager_cancel_call(priv->fw_call); - nm_assert(!priv->fw_call); - } - - if (G_UNLIKELY(!priv->fw_mgr)) - priv->fw_mgr = g_object_ref(nm_firewall_manager_get()); - - zone = nm_setting_connection_get_zone(s_con); -#if WITH_FIREWALLD_ZONE - if (!zone || zone[0] == '\0') { - if (nm_streq0(nm_device_get_effective_ip_config_method(self, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_SHARED) - || nm_streq0(nm_device_get_effective_ip_config_method(self, AF_INET6), - NM_SETTING_IP6_CONFIG_METHOD_SHARED)) - zone = "nm-shared"; - } -#endif - priv->fw_call = nm_firewall_manager_add_or_change_zone(priv->fw_mgr, - nm_device_get_ip_iface(self), - zone, - FALSE, /* change zone */ - fw_change_zone_cb, - self); -} - -/* - * nm_device_activate_schedule_stage3_ip_config_start - * - * Schedule IP configuration start - */ -void -nm_device_activate_schedule_stage3_ip_config_start(NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - g_return_if_fail(priv->act_request.obj); - - /* Add the interface to the specified firewall zone */ - if (priv->fw_state == FIREWALL_STATE_UNMANAGED) { - if (!nm_device_sys_iface_state_is_external(self)) { - priv->fw_state = FIREWALL_STATE_WAIT_STAGE_3; - fw_change_zone(self); - return; - } - - /* fake success. */ - priv->fw_state = FIREWALL_STATE_INITIALIZED; - } else if (priv->fw_state == FIREWALL_STATE_WAIT_STAGE_3) { - /* a firewall call for stage3 is pending. Return and wait. */ - return; - } - - nm_assert(priv->fw_state == FIREWALL_STATE_INITIALIZED); - - activation_source_schedule(self, activate_stage3_ip_config_start, AF_INET); -} - -static NMActStageReturn -act_stage4_ip_config_timeout(NMDevice * self, - int addr_family, - NMDeviceStateReason *out_failure_reason) -{ - nm_assert_addr_family(addr_family); - - if (!get_ip_config_may_fail(self, addr_family)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -/* - * nm_device_activate_stage4_ip4_config_timeout - * - * Time out on retrieving the IPv4 config. - * - */ -static void -activate_stage4_ip_config_timeout_4(NMDevice *self) -{ - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - - ret = NM_DEVICE_GET_CLASS(self)->act_stage4_ip_config_timeout(self, AF_INET, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - return; - else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); - return; - } - g_assert(ret == NM_ACT_STAGE_RETURN_SUCCESS); - - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_FAIL); - - check_ip_state(self, FALSE, TRUE); -} - -void -nm_device_activate_schedule_ip_config_timeout(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - g_return_if_fail(priv->act_request.obj); - - activation_source_schedule(self, activate_stage4_ip_config_timeout_x[IS_IPv4], addr_family); -} - -static void -activate_stage4_ip_config_timeout_6(NMDevice *self) -{ - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - - ret = NM_DEVICE_GET_CLASS(self)->act_stage4_ip_config_timeout(self, AF_INET6, &failure_reason); - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - return; - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - nm_device_state_changed(self, NM_DEVICE_STATE_FAILED, failure_reason); - return; - } - g_assert(ret == NM_ACT_STAGE_RETURN_SUCCESS); - - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_FAIL); - - check_ip_state(self, FALSE, TRUE); -} - -static gboolean -share_init(NMDevice *self, GError **error) -{ - char * modules[] = {"ip_tables", - "iptable_nat", - "nf_nat_ftp", - "nf_nat_irc", - "nf_nat_sip", - "nf_nat_tftp", - "nf_nat_pptp", - "nf_nat_h323", - NULL}; - char **iter; - int errsv; - - if (nm_platform_sysctl_get_int32(nm_device_get_platform(self), - NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"), - -1) - == 1) { - /* nothing to do. */ - } else if (!nm_platform_sysctl_set(nm_device_get_platform(self), - NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_forward"), - "1")) { - errsv = errno; - _LOGD(LOGD_SHARING, - "share: error enabling IPv4 forwarding: (%d) %s", - errsv, - nm_strerror_native(errsv)); - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "cannot set ipv4/ip_forward: %s", - nm_strerror_native(errsv)); - return FALSE; - } - - if (nm_platform_sysctl_get_int32(nm_device_get_platform(self), - NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_dynaddr"), - -1) - == 1) { - /* nothing to do. */ - } else if (!nm_platform_sysctl_set(nm_device_get_platform(self), - NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv4/ip_dynaddr"), - "1")) { - errsv = errno; - _LOGD(LOGD_SHARING, - "share: error enabling dynamic addresses: (%d) %s", - errsv, - nm_strerror_native(errsv)); - } - - for (iter = modules; *iter; iter++) - nm_utils_modprobe(NULL, FALSE, *iter, NULL); - - return TRUE; -} - -#define add_share_rule(req, table, ...) \ - G_STMT_START \ - { \ - char *_cmd = g_strdup_printf(__VA_ARGS__); \ - nm_act_request_add_share_rule(req, table, _cmd); \ - g_free(_cmd); \ - } \ - G_STMT_END - -static gboolean -start_sharing(NMDevice *self, NMIP4Config *config, GError **error) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMActRequest * req; - char str_addr[INET_ADDRSTRLEN]; - char str_mask[INET_ADDRSTRLEN]; - guint32 netmask, network; - const NMPlatformIP4Address *ip4_addr = NULL; - const char * ip_iface; - GError * local = NULL; - NMConnection * conn; - NMSettingConnection * s_con; - gboolean announce_android_metered; - - g_return_val_if_fail(config, FALSE); - - ip_iface = nm_device_get_ip_iface(self); - if (!ip_iface) { - g_set_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "device has no ip interface"); - return FALSE; - } - - ip4_addr = nm_ip4_config_get_first_address(config); - if (!ip4_addr || !ip4_addr->address) { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "could not determine IPv4 address"); - return FALSE; - } - - if (!share_init(self, error)) - return FALSE; - - req = nm_device_get_act_request(self); - g_return_val_if_fail(req, FALSE); - - netmask = _nm_utils_ip4_prefix_to_netmask(ip4_addr->plen); - _nm_utils_inet4_ntop(netmask, str_mask); - - network = ip4_addr->address & netmask; - _nm_utils_inet4_ntop(network, str_addr); - - add_share_rule(req, - "nat", - "POSTROUTING --source %s/%s ! --destination %s/%s --jump MASQUERADE", - str_addr, - str_mask, - str_addr, - str_mask); - add_share_rule(req, - "filter", - "FORWARD --destination %s/%s --out-interface %s --match state --state " - "ESTABLISHED,RELATED --jump ACCEPT", - str_addr, - str_mask, - ip_iface); - add_share_rule(req, - "filter", - "FORWARD --source %s/%s --in-interface %s --jump ACCEPT", - str_addr, - str_mask, - ip_iface); - add_share_rule(req, - "filter", - "FORWARD --in-interface %s --out-interface %s --jump ACCEPT", - ip_iface, - ip_iface); - add_share_rule(req, "filter", "FORWARD --out-interface %s --jump REJECT", ip_iface); - add_share_rule(req, "filter", "FORWARD --in-interface %s --jump REJECT", ip_iface); - add_share_rule(req, - "filter", - "INPUT --in-interface %s --protocol udp --destination-port 67 --jump ACCEPT", - ip_iface); - add_share_rule(req, - "filter", - "INPUT --in-interface %s --protocol tcp --destination-port 67 --jump ACCEPT", - ip_iface); - add_share_rule(req, - "filter", - "INPUT --in-interface %s --protocol udp --destination-port 53 --jump ACCEPT", - ip_iface); - add_share_rule(req, - "filter", - "INPUT --in-interface %s --protocol tcp --destination-port 53 --jump ACCEPT", - ip_iface); - - nm_act_request_set_shared(req, TRUE); - - conn = nm_act_request_get_applied_connection(req); - s_con = nm_connection_get_setting_connection(conn); - - switch (nm_setting_connection_get_metered(s_con)) { - case NM_METERED_YES: - /* honor the metered flag. Note that reapply on the device does not affect - * the metered setting. This is different from other profiles, where the - * metered flag of an activated profile can be changed (reapplied). */ - announce_android_metered = TRUE; - break; - case NM_METERED_UNKNOWN: - /* we pick up the current value and announce it. But again, we cannot update - * the announced setting without restarting dnsmasq. That means, if the default - * route changes w.r.t. being metered, then the shared connection does not get - * updated before reactivating. */ - announce_android_metered = - NM_IN_SET(nm_manager_get_metered(NM_MANAGER_GET), NM_METERED_YES, NM_METERED_GUESS_YES); - break; - default: - announce_android_metered = FALSE; - break; - } - - if (!nm_dnsmasq_manager_start(priv->dnsmasq_manager, - config, - announce_android_metered, - &local)) { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "could not start dnsmasq due to %s", - local->message); - g_error_free(local); - nm_act_request_set_shared(req, FALSE); - return FALSE; - } - - priv->dnsmasq_state_id = g_signal_connect(priv->dnsmasq_manager, - NM_DNS_MASQ_MANAGER_STATE_CHANGED, - G_CALLBACK(dnsmasq_state_changed_cb), - self); - return TRUE; -} - -static void -arp_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_clear_pointer(&priv->acd.announcing, nm_acd_manager_free); -} - -void -nm_device_arp_announce(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - NMSettingIPConfig *s_ip4; - guint num, i; - const guint8 * hw_addr; - size_t hw_addr_len = 0; - - arp_cleanup(self); - - hw_addr = nm_platform_link_get_address(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - &hw_addr_len); - - if (!hw_addr || hw_addr_len != ETH_ALEN) - return; - - /* We only care about manually-configured addresses; DHCP- and autoip-configured - * ones should already have been seen on the network at this point. - */ - connection = nm_device_get_applied_connection(self); - if (!connection) - return; - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (!s_ip4) - return; - num = nm_setting_ip_config_get_num_addresses(s_ip4); - if (num == 0) - return; - - priv->acd.announcing = - nm_acd_manager_new(nm_device_get_ip_ifindex(self), hw_addr, hw_addr_len, NULL, NULL); - - for (i = 0; i < num; i++) { - NMIPAddress *ip = nm_setting_ip_config_get_address(s_ip4, i); - in_addr_t addr; - - if (inet_pton(AF_INET, nm_ip_address_get_address(ip), &addr) == 1) - nm_acd_manager_add_address(priv->acd.announcing, addr); - else - g_warn_if_reached(); - } - - nm_acd_manager_announce_addresses(priv->acd.announcing); -} - -static void -activate_stage5_ip_config_result_4(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMActRequest * req; - const char * method; - int ip_ifindex; - gboolean do_announce = FALSE; - - req = nm_device_get_act_request(self); - g_assert(req); - - /* Interface must be IFF_UP before IP config can be applied */ - ip_ifindex = nm_device_get_ip_ifindex(self); - if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex) - && !nm_device_sys_iface_state_is_external_or_assume(self)) { - nm_platform_link_set_up(nm_device_get_platform(self), ip_ifindex, NULL); - if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex)) - _LOGW(LOGD_DEVICE, - "interface %s not up for IP configuration", - nm_device_get_ip_iface(self)); - } - - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) { - _LOGD(LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed"); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - - /* Start IPv4 sharing if we need it */ - method = nm_device_get_effective_ip_config_method(self, AF_INET); - if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) { - gs_free_error GError *error = NULL; - - if (!start_sharing(self, priv->ip_config_4, &error)) { - _LOGW(LOGD_SHARING, - "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed: %s", - error->message); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); - return; - } - } - - if (priv->dhcp_data_4.client) { - gs_free_error GError *error = NULL; - - if (!nm_dhcp_client_accept(priv->dhcp_data_4.client, &error)) { - _LOGW(LOGD_DHCP4, - "Activation: Stage 5 of 5 (IPv4 Commit) error accepting lease: %s", - error->message); - nm_device_ip_method_failed(self, AF_INET, NM_DEVICE_STATE_REASON_DHCP_ERROR); - return; - } - } - - /* If IPv4 wasn't the first to complete, and DHCP was used, then ensure - * dispatcher scripts get the DHCP lease information. - */ - if (priv->dhcp_data_4.client && nm_device_activate_ip4_state_in_conf(self) - && (nm_device_get_state(self) > NM_DEVICE_STATE_IP_CONFIG)) { - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP4_CHANGE, self, NULL, NULL, NULL, NULL); - } - - /* Send ARP announcements */ - - if (nm_device_is_master(self)) { - CList * iter; - SlaveInfo *info; - - /* Skip announcement if there are no device enslaved, for two reasons: - * 1) the master has a temporary MAC address until the first slave comes - * 2) announcements are going to be dropped anyway without slaves - */ - do_announce = FALSE; - - c_list_for_each (iter, &priv->slaves) { - info = c_list_entry(iter, SlaveInfo, lst_slave); - if (info->slave_is_enslaved) { - do_announce = TRUE; - break; - } - } - } else - do_announce = TRUE; - - if (do_announce) - nm_device_arp_announce(self); - - /* Enter the IP_CHECK state if this is the first method to complete */ - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_DONE); - check_ip_state(self, FALSE, TRUE); -} - -void -nm_device_activate_schedule_ip_config_result(NMDevice *self, int addr_family, NMIPConfig *config) -{ - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - g_return_if_fail( - !config || (addr_family == AF_INET && nm_ip_config_get_addr_family(config) == AF_INET)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (IS_IPv4) { - applied_config_init(&priv->dev_ip_config_4, config); - } else { - /* If IP had previously failed, move it back to NM_DEVICE_IP_STATE_CONF since we - * clearly now have configuration. - */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_FAIL) - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_CONF); - } - - activation_source_schedule(self, activate_stage5_ip_config_result_x[IS_IPv4], addr_family); -} - -NMDeviceIPState -nm_device_activate_get_ip_state(NMDevice *self, int addr_family) -{ - const gboolean IS_IPv4 = (addr_family == AF_INET); - - g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_IP_STATE_NONE); - g_return_val_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6), NM_DEVICE_IP_STATE_NONE); - - return NM_DEVICE_GET_PRIVATE(self)->ip_state_x[IS_IPv4]; -} - -static void -dad6_add_pending_address(NMDevice * self, - NMPlatform * platform, - int ifindex, - const struct in6_addr *address, - NMIP6Config ** dad6_config) -{ - const NMPlatformIP6Address *pl_addr; - - pl_addr = nm_platform_ip6_address_get(platform, ifindex, address); - if (pl_addr && NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_TENTATIVE) - && !NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_DADFAILED) - && !NM_FLAGS_HAS(pl_addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - _LOGt(LOGD_DEVICE, - "IPv6 DAD: pending address %s", - nm_platform_ip6_address_to_string(pl_addr, NULL, 0)); - - if (!*dad6_config) - *dad6_config = nm_device_ip6_config_new(self); - - nm_ip6_config_add_address(*dad6_config, pl_addr); - } -} - -/* - * Returns a NMIP6Config containing NM-configured addresses which - * have the tentative flag, or NULL if none is present. - */ -static NMIP6Config * -dad6_get_pending_addresses(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIP6Config * confs[] = {(NMIP6Config *) applied_config_get_current(&priv->ac_ip6_config), - (NMIP6Config *) applied_config_get_current(&priv->dhcp6.ip6_config), - priv->con_ip_config_6, - (NMIP6Config *) applied_config_get_current(&priv->dev2_ip_config_6)}; - const NMPlatformIP6Address *addr; - NMIP6Config * dad6_config = NULL; - NMDedupMultiIter ipconf_iter; - guint i; - int ifindex; - NMPlatform * platform; - - ifindex = nm_device_get_ip_ifindex(self); - g_return_val_if_fail(ifindex > 0, NULL); - - platform = nm_device_get_platform(self); - - if (priv->ipv6ll_has) { - dad6_add_pending_address(self, platform, ifindex, &priv->ipv6ll_addr, &dad6_config); - } - - /* We are interested only in addresses that we have explicitly configured, - * not in externally added ones. - */ - for (i = 0; i < G_N_ELEMENTS(confs); i++) { - if (!confs[i]) - continue; - - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, confs[i], &addr) { - dad6_add_pending_address(self, platform, ifindex, &addr->address, &dad6_config); - } - } - - return dad6_config; -} - -static void -activate_stage5_ip_config_result_6(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMActRequest * req; - const char * method; - int ip_ifindex; - int errsv; - - req = nm_device_get_act_request(self); - g_assert(req); - - /* Interface must be IFF_UP before IP config can be applied */ - ip_ifindex = nm_device_get_ip_ifindex(self); - g_return_if_fail(ip_ifindex); - - if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex) - && !nm_device_sys_iface_state_is_external_or_assume(self)) { - nm_platform_link_set_up(nm_device_get_platform(self), ip_ifindex, NULL); - if (!nm_platform_link_is_up(nm_device_get_platform(self), ip_ifindex)) - _LOGW(LOGD_DEVICE, - "interface %s not up for IP configuration", - nm_device_get_ip_iface(self)); - } - - if (ip_config_merge_and_apply(self, AF_INET6, TRUE)) { - if (priv->dhcp6.mode != NM_NDISC_DHCP_LEVEL_NONE - && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF) { - if (applied_config_get_current(&priv->dhcp6.ip6_config)) { - /* If IPv6 wasn't the first IP to complete, and DHCP was used, - * then ensure dispatcher scripts get the DHCP lease information. - */ - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP6_CHANGE, - self, - NULL, - NULL, - NULL, - NULL); - } else { - /* still waiting for first dhcp6 lease. */ - return; - } - } - - /* Start IPv6 forwarding if we need it */ - method = nm_device_get_effective_ip_config_method(self, AF_INET6); - if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { - if (!nm_platform_sysctl_set( - nm_device_get_platform(self), - NMP_SYSCTL_PATHID_ABSOLUTE("/proc/sys/net/ipv6/conf/all/forwarding"), - "1")) { - errsv = errno; - _LOGE(LOGD_SHARING, - "share: error enabling IPv6 forwarding: (%d) %s", - errsv, - nm_strerror_native(errsv)); - nm_device_ip_method_failed(self, - AF_INET6, - NM_DEVICE_STATE_REASON_SHARED_START_FAILED); - } - } - - /* Check if we have to wait for DAD */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF && !priv->dad6_ip6_config) { - if (!priv->carrier && priv->ignore_carrier && get_ip_config_may_fail(self, AF_INET6)) - _LOGI(LOGD_DEVICE | LOGD_IP6, - "IPv6 DAD: carrier missing and ignored, not delaying activation"); - else - priv->dad6_ip6_config = dad6_get_pending_addresses(self); - - if (priv->dad6_ip6_config) { - _LOGD(LOGD_DEVICE | LOGD_IP6, "IPv6 DAD: awaiting termination"); - } else { - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_DONE); - check_ip_state(self, FALSE, TRUE); - } - } - } else { - _LOGW(LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) failed"); - nm_device_ip_method_failed(self, AF_INET6, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - } -} - -/*****************************************************************************/ - -static void -act_request_set(NMDevice *self, NMActRequest *act_request) -{ - NMDevicePrivate *priv; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(!act_request || NM_IS_ACT_REQUEST(act_request)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->act_request.visible && priv->act_request.obj == act_request) - return; - - /* always clear the public flag. The few callers that set a new @act_request - * don't want that the property is public yet. */ - nm_dbus_track_obj_path_set(&priv->act_request, act_request, FALSE); - - if (act_request) { - switch (nm_active_connection_get_activation_type(NM_ACTIVE_CONNECTION(act_request))) { - case NM_ACTIVATION_TYPE_EXTERNAL: - break; - case NM_ACTIVATION_TYPE_ASSUME: - if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_EXTERNAL) - nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_ASSUME); - break; - case NM_ACTIVATION_TYPE_MANAGED: - if (NM_IN_SET_TYPED(NMDeviceSysIfaceState, - priv->sys_iface_state, - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME)) - nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); - break; - } - } -} - -static void -dnsmasq_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->dnsmasq_manager) - return; - - nm_clear_g_signal_handler(priv->dnsmasq_manager, &priv->dnsmasq_state_id); - - nm_dnsmasq_manager_stop(priv->dnsmasq_manager); - g_object_unref(priv->dnsmasq_manager); - priv->dnsmasq_manager = NULL; -} - -gboolean -nm_device_is_nm_owned(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->nm_owned; -} - -/* - * delete_on_deactivate_link_delete - * - * Function will be queued with g_idle_add to call - * nm_platform_link_delete for the underlying resources - * of the device. - */ -static gboolean -delete_on_deactivate_link_delete(gpointer user_data) -{ - DeleteOnDeactivateData *data = user_data; - NMDevice * self = data->device; - - _LOGD(LOGD_DEVICE, - "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)", - data->ifindex, - data->idle_add_id); - - if (data->device) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(data->device); - gs_free_error GError *error = NULL; - - g_object_remove_weak_pointer(G_OBJECT(data->device), (void **) &data->device); - priv->delete_on_deactivate_data = NULL; - - if (!nm_device_unrealize(data->device, TRUE, &error)) - _LOGD(LOGD_DEVICE, - "delete_on_deactivate: unrealizing %d failed (%s)", - data->ifindex, - error->message); - } else if (data->ifindex > 0) - nm_platform_link_delete(nm_device_get_platform(self), data->ifindex); - - nm_device_emit_recheck_auto_activate(self); - - g_free(data); - return FALSE; -} - -static void -delete_on_deactivate_unschedule(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->delete_on_deactivate_data) { - DeleteOnDeactivateData *data = priv->delete_on_deactivate_data; - - priv->delete_on_deactivate_data = NULL; - - g_source_remove(data->idle_add_id); - g_object_remove_weak_pointer(G_OBJECT(self), (void **) &data->device); - _LOGD(LOGD_DEVICE, - "delete_on_deactivate: cancel cleanup and delete virtual link #%d (id=%u)", - data->ifindex, - data->idle_add_id); - g_free(data); - } -} - -static void -delete_on_deactivate_check_and_schedule(NMDevice *self, int ifindex) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - DeleteOnDeactivateData *data; - - if (!priv->nm_owned) - return; - if (priv->queued_act_request) - return; - if (!nm_device_is_software(self) || !nm_device_is_real(self)) - return; - if (nm_device_get_state(self) == NM_DEVICE_STATE_UNMANAGED) - return; - if (nm_device_get_state(self) == NM_DEVICE_STATE_UNAVAILABLE) - return; - delete_on_deactivate_unschedule(self); /* always cancel and reschedule */ - - data = g_new(DeleteOnDeactivateData, 1); - g_object_add_weak_pointer(G_OBJECT(self), (void **) &data->device); - data->device = self; - data->ifindex = ifindex; - data->idle_add_id = g_idle_add(delete_on_deactivate_link_delete, data); - priv->delete_on_deactivate_data = data; - - _LOGD(LOGD_DEVICE, - "delete_on_deactivate: schedule cleanup and delete virtual link #%d (id=%u)", - ifindex, - data->idle_add_id); -} - -static void -_cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - - _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_NONE); - - if (nm_clear_g_source(&priv->queued_ip_config_id_x[IS_IPv4])) { - _LOGD(LOGD_DEVICE, - "clearing queued IP%c config change", - nm_utils_addr_family_to_char(addr_family)); - } - - if (IS_IPv4) { - dhcp4_cleanup(self, cleanup_type, FALSE); - arp_cleanup(self); - dnsmasq_cleanup(self); - ipv4ll_cleanup(self); - g_slist_free_full(priv->acd.dad_list, (GDestroyNotify) nm_acd_manager_free); - priv->acd.dad_list = NULL; - } else { - g_slist_free_full(priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - priv->dad6_failed_addrs = NULL; - g_clear_object(&priv->dad6_ip6_config); - dhcp6_cleanup(self, cleanup_type, FALSE); - nm_clear_g_source(&priv->linklocal6_timeout_id); - addrconf6_cleanup(self); - } -} - -gboolean -_nm_device_hash_check_invalid_keys(GHashTable * hash, - const char * setting_name, - GError ** error, - const char *const *whitelist) -{ - guint found_whitelisted_keys = 0; - guint i; - - nm_assert(hash && g_hash_table_size(hash) > 0); - nm_assert(whitelist && whitelist[0]); - -#if NM_MORE_ASSERTS > 10 - /* Require whitelist to only contain unique keys. */ - { - gs_unref_hashtable GHashTable *check_dups = - g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, NULL); - - for (i = 0; whitelist[i]; i++) { - if (!g_hash_table_add(check_dups, (char *) whitelist[i])) - nm_assert(FALSE); - } - nm_assert(g_hash_table_size(check_dups) > 0); - } -#endif - - for (i = 0; whitelist[i]; i++) { - if (g_hash_table_contains(hash, whitelist[i])) - found_whitelisted_keys++; - } - - if (found_whitelisted_keys == g_hash_table_size(hash)) { - /* Good, there are only whitelisted keys in the hash. */ - return TRUE; - } - - if (error) { - GHashTableIter iter; - const char * k = NULL; - const char * first_invalid_key = NULL; - - g_hash_table_iter_init(&iter, hash); - while (g_hash_table_iter_next(&iter, (gpointer *) &k, NULL)) { - if (nm_utils_strv_find_first((char **) whitelist, -1, k) < 0) { - first_invalid_key = k; - break; - } - } - if (setting_name) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply changes to '%s.%s' setting", - setting_name, - first_invalid_key); - } else { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply any changes to '%s' setting", - first_invalid_key); - } - g_return_val_if_fail(first_invalid_key, FALSE); - } - - return FALSE; -} - -void -nm_device_reactivate_ip4_config(NMDevice * self, - NMSettingIPConfig *s_ip4_old, - NMSettingIPConfig *s_ip4_new) -{ - NMDevicePrivate *priv; - const char * method_old, *method_new; - - g_return_if_fail(NM_IS_DEVICE(self)); - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->ip_state_4 != NM_DEVICE_IP_STATE_NONE) { - g_clear_object(&priv->con_ip_config_4); - g_clear_object(&priv->ext_ip_config_4); - g_clear_object(&priv->dev_ip_config_4.current); - g_clear_object(&priv->dev2_ip_config_4.current); - priv->con_ip_config_4 = nm_device_ip4_config_new(self); - nm_ip4_config_merge_setting(priv->con_ip_config_4, - s_ip4_new, - _prop_get_connection_mdns(self), - _prop_get_connection_llmnr(self), - nm_device_get_route_table(self, AF_INET), - nm_device_get_route_metric(self, AF_INET)); - - method_old = s_ip4_old ? nm_setting_ip_config_get_method(s_ip4_old) - : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - method_new = s_ip4_new ? nm_setting_ip_config_get_method(s_ip4_new) - : NM_SETTING_IP4_CONFIG_METHOD_DISABLED; - - if (!nm_streq0(method_old, method_new)) { - _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_DECONFIGURE); - _set_ip_state(self, AF_INET, NM_DEVICE_IP_STATE_WAIT); - if (!nm_device_activate_stage3_ip4_start(self)) - _LOGW(LOGD_IP4, "Failed to apply IPv4 configuration"); - return; - } - - if (s_ip4_old && s_ip4_new) { - gint64 metric_old, metric_new; - - /* For dynamic IP methods (DHCP, IPv4LL, WWAN) the route metric is - * set at activation/renewal time using the value from static - * configuration. To support runtime change we need to update the - * dynamic configuration in place and tell the DHCP client the new - * value to use for future renewals. - */ - metric_old = nm_setting_ip_config_get_route_metric(s_ip4_old); - metric_new = nm_setting_ip_config_get_route_metric(s_ip4_new); - - if (metric_old != metric_new) { - if (priv->dev_ip_config_4.orig) { - nm_ip4_config_update_routes_metric((NMIP4Config *) priv->dev_ip_config_4.orig, - nm_device_get_route_metric(self, AF_INET)); - } - if (priv->dev2_ip_config_4.orig) { - nm_ip4_config_update_routes_metric((NMIP4Config *) priv->dev2_ip_config_4.orig, - nm_device_get_route_metric(self, AF_INET)); - } - if (priv->dhcp_data_4.client) { - nm_dhcp_client_set_route_metric(priv->dhcp_data_4.client, - nm_device_get_route_metric(self, AF_INET)); - } - } - } - - if (nm_device_get_ip_ifindex(self) > 0 && !ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "Failed to reapply IPv4 configuration"); - } -} - -void -nm_device_reactivate_ip6_config(NMDevice * self, - NMSettingIPConfig *s_ip6_old, - NMSettingIPConfig *s_ip6_new) -{ - NMDevicePrivate *priv; - const char * method_old, *method_new; - - g_return_if_fail(NM_IS_DEVICE(self)); - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->ip_state_6 != NM_DEVICE_IP_STATE_NONE) { - g_clear_object(&priv->con_ip_config_6); - g_clear_object(&priv->ext_ip_config_6); - g_clear_object(&priv->ac_ip6_config.current); - g_clear_object(&priv->dhcp6.ip6_config.current); - g_clear_object(&priv->dev2_ip_config_6.current); - if (priv->ipv6ll_handle && !IN6_IS_ADDR_UNSPECIFIED(&priv->ipv6ll_addr)) - priv->ipv6ll_has = TRUE; - priv->con_ip_config_6 = nm_device_ip6_config_new(self); - nm_ip6_config_merge_setting(priv->con_ip_config_6, - s_ip6_new, - nm_device_get_route_table(self, AF_INET6), - nm_device_get_route_metric(self, AF_INET6)); - - method_old = s_ip6_old ? nm_setting_ip_config_get_method(s_ip6_old) - : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - method_new = s_ip6_new ? nm_setting_ip_config_get_method(s_ip6_new) - : NM_SETTING_IP6_CONFIG_METHOD_IGNORE; - - if (!nm_streq0(method_old, method_new)) { - _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); - _set_ip_state(self, AF_INET6, NM_DEVICE_IP_STATE_WAIT); - if (!nm_device_activate_stage3_ip6_start(self)) - _LOGW(LOGD_IP6, "Failed to apply IPv6 configuration"); - return; - } - - if (s_ip6_old && s_ip6_new) { - gint64 metric_old, metric_new; - - /* See comment in nm_device_reactivate_ip4_config() */ - metric_old = nm_setting_ip_config_get_route_metric(s_ip6_old); - metric_new = nm_setting_ip_config_get_route_metric(s_ip6_new); - - if (metric_old != metric_new) { - if (priv->ac_ip6_config.orig) { - nm_ip6_config_update_routes_metric((NMIP6Config *) priv->ac_ip6_config.orig, - nm_device_get_route_metric(self, AF_INET6)); - } - if (priv->dhcp6.ip6_config.orig) { - nm_ip6_config_update_routes_metric((NMIP6Config *) priv->dhcp6.ip6_config.orig, - nm_device_get_route_metric(self, AF_INET6)); - } - if (priv->dev2_ip_config_6.orig) { - nm_ip6_config_update_routes_metric((NMIP6Config *) priv->dev2_ip_config_6.orig, - nm_device_get_route_metric(self, AF_INET6)); - } - if (priv->dhcp_data_6.client) { - nm_dhcp_client_set_route_metric(priv->dhcp_data_6.client, - nm_device_get_route_metric(self, AF_INET6)); - } - } - } - - if (nm_device_get_ip_ifindex(self) > 0 && !ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP4, "Failed to reapply IPv6 configuration"); - } -} - -static void -_pacrunner_manager_add(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); - - priv->pacrunner_conf_id = nm_pacrunner_manager_add(nm_pacrunner_manager_get(), - priv->proxy_config, - nm_device_get_ip_iface(self), - NULL, - NULL); -} - -static void -reactivate_proxy_config(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->pacrunner_conf_id) - return; - nm_device_set_proxy_config(self, priv->dhcp4.pac_url); - _pacrunner_manager_add(self); -} - -static gboolean -can_reapply_change(NMDevice * self, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error) -{ - if (nm_streq(setting_name, NM_SETTING_CONNECTION_SETTING_NAME)) { - /* Whitelist allowed properties from "connection" setting which are - * allowed to differ. - * - * This includes UUID, there is no principal problem with reapplying a - * connection and changing its UUID. In fact, disallowing it makes it - * cumbersome for the user to reapply any connection but the original - * settings-connection. */ - return nm_device_hash_check_invalid_keys(diffs, - NM_SETTING_CONNECTION_SETTING_NAME, - error, - NM_SETTING_CONNECTION_ID, - NM_SETTING_CONNECTION_UUID, - NM_SETTING_CONNECTION_STABLE_ID, - NM_SETTING_CONNECTION_AUTOCONNECT, - NM_SETTING_CONNECTION_ZONE, - NM_SETTING_CONNECTION_METERED, - NM_SETTING_CONNECTION_LLDP, - NM_SETTING_CONNECTION_MDNS, - NM_SETTING_CONNECTION_LLMNR); - } else if (NM_IN_STRSET(setting_name, - NM_SETTING_USER_SETTING_NAME, - NM_SETTING_PROXY_SETTING_NAME, - NM_SETTING_IP4_CONFIG_SETTING_NAME, - NM_SETTING_IP6_CONFIG_SETTING_NAME)) { - return TRUE; - } else if (nm_streq(setting_name, NM_SETTING_WIRED_SETTING_NAME) - && NM_IN_SET(NM_DEVICE_GET_CLASS(self)->get_configured_mtu, - nm_device_get_configured_mtu_wired_parent, - nm_device_get_configured_mtu_for_wired)) { - return nm_device_hash_check_invalid_keys(diffs, - NM_SETTING_WIRED_SETTING_NAME, - error, - NM_SETTING_WIRED_MTU); - } else { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Can't reapply any changes to '%s' setting", - setting_name); - return FALSE; - } -} - -static void -reapply_connection(NMDevice *self, NMConnection *con_old, NMConnection *con_new) -{} - -/* check_and_reapply_connection: - * @connection: the new connection settings to be applied or %NULL to reapply - * the current settings connection - * @version_id: either zero, or the current version id for the applied - * connection. - * @audit_args: on return, a string representing the changes - * @error: the error if %FALSE is returned - * - * Change configuration of an already configured device if possible. - * Updates the device's applied connection upon success. - * - * Return: %FALSE if the new configuration can not be reapplied. - */ -static gboolean -check_and_reapply_connection(NMDevice * self, - NMConnection *connection, - guint64 version_id, - char ** audit_args, - GError ** error) -{ - NMDeviceClass * klass = NM_DEVICE_GET_CLASS(self); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * applied = nm_device_get_applied_connection(self); - gs_unref_object NMConnection *applied_clone = NULL; - gs_unref_hashtable GHashTable *diffs = NULL; - NMConnection * con_old, *con_new; - NMSettingIPConfig * s_ip4_old, *s_ip4_new; - NMSettingIPConfig * s_ip6_old, *s_ip6_new; - GHashTableIter iter; - - if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not activated"); - return FALSE; - } - - nm_connection_diff(connection, - applied, - NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP - | NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, - &diffs); - - if (audit_args) { - if (diffs && nm_audit_manager_audit_enabled(nm_audit_manager_get())) - *audit_args = nm_utils_format_con_diff_for_audit(diffs); - else - *audit_args = NULL; - } - - /************************************************************************** - * check for unsupported changes and reject to reapply - *************************************************************************/ - if (diffs) { - char * setting_name; - GHashTable *setting_diff; - - g_hash_table_iter_init(&iter, diffs); - while ( - g_hash_table_iter_next(&iter, (gpointer *) &setting_name, (gpointer *) &setting_diff)) { - if (!klass->can_reapply_change( - self, - setting_name, - nm_connection_get_setting_by_name(applied, setting_name), - nm_connection_get_setting_by_name(connection, setting_name), - setting_diff, - error)) - return FALSE; - } - } - - if (version_id != 0 - && version_id - != nm_active_connection_version_id_get( - (NMActiveConnection *) priv->act_request.obj)) { - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_VERSION_ID_MISMATCH, - "Reapply failed because device changed in the meantime and the version-id mismatches"); - return FALSE; - } - - /************************************************************************** - * Update applied connection - *************************************************************************/ - - if (diffs) - nm_active_connection_version_id_bump((NMActiveConnection *) priv->act_request.obj); - - _LOGD(LOGD_DEVICE, - "reapply (version-id %llu%s)", - (unsigned long long) nm_active_connection_version_id_get( - ((NMActiveConnection *) priv->act_request.obj)), - diffs ? "" : " (unmodified)"); - - if (diffs) { - NMConnection * connection_clean = connection; - gs_unref_object NMConnection *connection_clean_free = NULL; - - { - NMSettingConnection *s_con_a, *s_con_n; - - /* we allow re-applying a connection with differing ID, UUID, STABLE_ID and AUTOCONNECT. - * This is for convenience but these values are not actually changeable. So, check - * if they changed, and if the did revert to the original values. */ - s_con_a = nm_connection_get_setting_connection(applied); - s_con_n = nm_connection_get_setting_connection(connection); - - if (!nm_streq(nm_setting_connection_get_id(s_con_a), - nm_setting_connection_get_id(s_con_n)) - || !nm_streq(nm_setting_connection_get_uuid(s_con_a), - nm_setting_connection_get_uuid(s_con_n)) - || nm_setting_connection_get_autoconnect(s_con_a) - != nm_setting_connection_get_autoconnect(s_con_n) - || !nm_streq0(nm_setting_connection_get_stable_id(s_con_a), - nm_setting_connection_get_stable_id(s_con_n))) { - connection_clean_free = nm_simple_connection_new_clone(connection); - connection_clean = connection_clean_free; - s_con_n = nm_connection_get_setting_connection(connection_clean); - g_object_set(s_con_n, - NM_SETTING_CONNECTION_ID, - nm_setting_connection_get_id(s_con_a), - NM_SETTING_CONNECTION_UUID, - nm_setting_connection_get_uuid(s_con_a), - NM_SETTING_CONNECTION_AUTOCONNECT, - nm_setting_connection_get_autoconnect(s_con_a), - NM_SETTING_CONNECTION_STABLE_ID, - nm_setting_connection_get_stable_id(s_con_a), - NULL); - } - } - - con_old = applied_clone = nm_simple_connection_new_clone(applied); - con_new = applied; - nm_connection_replace_settings_from_connection(applied, connection_clean); - nm_connection_clear_secrets(applied); - } else - con_old = con_new = applied; - - priv->v4_commit_first_time = TRUE; - priv->v6_commit_first_time = TRUE; - - priv->v4_route_table_initialized = FALSE; - priv->v6_route_table_initialized = FALSE; - - /************************************************************************** - * Reapply changes - * - * Note that reapply_connection() is called as very first. This is for example - * important for NMDeviceWireGuard, which implements coerce_route_table() - * and get_extra_rules(). - * That is because NMDeviceWireGuard caches settings, so during reapply that - * cache must be updated *first*. - *************************************************************************/ - klass->reapply_connection(self, con_old, con_new); - - if (priv->state >= NM_DEVICE_STATE_CONFIG) - lldp_init(self, FALSE); - - if (priv->state >= NM_DEVICE_STATE_IP_CONFIG) { - s_ip4_old = nm_connection_get_setting_ip4_config(con_old); - s_ip4_new = nm_connection_get_setting_ip4_config(con_new); - s_ip6_old = nm_connection_get_setting_ip6_config(con_old); - s_ip6_new = nm_connection_get_setting_ip6_config(con_new); - - /* Allow reapply of MTU */ - priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; - - nm_device_reactivate_ip4_config(self, s_ip4_old, s_ip4_new); - nm_device_reactivate_ip6_config(self, s_ip6_old, s_ip6_new); - - _routing_rules_sync(self, NM_TERNARY_TRUE); - - reactivate_proxy_config(self); - } - - if (priv->state >= NM_DEVICE_STATE_IP_CHECK) - nm_device_update_firewall_zone(self); - - if (priv->state >= NM_DEVICE_STATE_ACTIVATED) - nm_device_update_metered(self); - - return TRUE; -} - -gboolean -nm_device_reapply(NMDevice *self, NMConnection *connection, GError **error) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - return check_and_reapply_connection(self, connection, 0, NULL, error); -} - -typedef struct { - NMConnection *connection; - guint64 version_id; -} ReapplyData; - -static void -reapply_cb(NMDevice * self, - GDBusMethodInvocation *context, - NMAuthSubject * subject, - GError * error, - gpointer user_data) -{ - ReapplyData * reapply_data = user_data; - guint64 version_id = 0; - gs_unref_object NMConnection *connection = NULL; - GError * local = NULL; - gs_free char * audit_args = NULL; - - if (reapply_data) { - connection = reapply_data->connection; - version_id = reapply_data->version_id; - g_slice_free(ReapplyData, reapply_data); - } - - if (error) { - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, - self, - FALSE, - NULL, - subject, - error->message); - g_dbus_method_invocation_return_gerror(context, error); - return; - } - - if (nm_device_sys_iface_state_is_external(self)) - nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); - - if (!check_and_reapply_connection(self, - connection - ?: nm_device_get_settings_connection_get_connection(self), - version_id, - &audit_args, - &local)) { - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, - self, - FALSE, - audit_args, - subject, - local->message); - g_dbus_method_invocation_take_error(context, local); - local = NULL; - } else { - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, self, TRUE, audit_args, subject, NULL); - g_dbus_method_invocation_return_value(context, NULL); - } -} - -static void -impl_device_reapply(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * dbus_connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - NMDevice * self = NM_DEVICE(obj); - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingsConnection *settings_connection; - NMConnection * connection = NULL; - GError * error = NULL; - ReapplyData * reapply_data; - gs_unref_variant GVariant *settings = NULL; - guint64 version_id; - guint32 flags; - - g_variant_get(parameters, "(@a{sa{sv}}tu)", &settings, &version_id, &flags); - - /* No flags supported as of now. */ - if (flags != 0) { - error = - g_error_new_literal(NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "Invalid flags specified"); - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, - self, - FALSE, - NULL, - invocation, - error->message); - g_dbus_method_invocation_take_error(invocation, error); - return; - } - - if (priv->state < NM_DEVICE_STATE_PREPARE || priv->state > NM_DEVICE_STATE_ACTIVATED) { - error = g_error_new_literal(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not activated"); - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, - self, - FALSE, - NULL, - invocation, - error->message); - g_dbus_method_invocation_take_error(invocation, error); - return; - } - - settings_connection = nm_device_get_settings_connection(self); - g_return_if_fail(settings_connection); - - if (settings && g_variant_n_children(settings)) { - /* New settings specified inline. */ - connection = _nm_simple_connection_new_from_dbus(settings, - NM_SETTING_PARSE_FLAGS_STRICT - | NM_SETTING_PARSE_FLAGS_NORMALIZE, - &error); - if (!connection) { - g_prefix_error(&error, "The settings specified are invalid: "); - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_REAPPLY, - self, - FALSE, - NULL, - invocation, - error->message); - g_dbus_method_invocation_take_error(invocation, error); - return; - } - nm_connection_clear_secrets(connection); - } - - if (connection || version_id) { - reapply_data = g_slice_new(ReapplyData); - reapply_data->connection = connection; - reapply_data->version_id = version_id; - } else - reapply_data = NULL; - - nm_device_auth_request(self, - invocation, - nm_device_get_applied_connection(self), - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - NULL, - reapply_cb, - reapply_data); -} - -/*****************************************************************************/ - -static void -impl_device_get_applied_connection(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - NMDevice * self = NM_DEVICE(obj); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - NMConnection * applied_connection; - guint32 flags; - GVariant * var_settings; - - g_variant_get(parameters, "(u)", &flags); - - /* No flags supported as of now. */ - if (flags != 0) { - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "Invalid flags specified"); - return; - } - - applied_connection = nm_device_get_applied_connection(self); - if (!applied_connection) { - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not activated"); - return; - } - - if (!nm_auth_is_invocation_in_acl_set_error(applied_connection, - invocation, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - NULL, - &error)) { - g_dbus_method_invocation_take_error(invocation, g_steal_pointer(&error)); - return; - } - - var_settings = nm_connection_to_dbus(applied_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); - if (!var_settings) - var_settings = g_variant_new_array(G_VARIANT_TYPE("{sa{sv}}"), NULL, 0); - - g_dbus_method_invocation_return_value( - invocation, - g_variant_new( - "(@a{sa{sv}}t)", - var_settings, - nm_active_connection_version_id_get((NMActiveConnection *) priv->act_request.obj))); -} - -/*****************************************************************************/ - -typedef struct { - gint64 timestamp_ms; - bool dirty; -} IP6RoutesTemporaryNotAvailableData; - -static gboolean -_rt6_temporary_not_available_timeout(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->rt6_temporary_not_available_id = 0; - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - - return G_SOURCE_REMOVE; -} - -static gboolean -_rt6_temporary_not_available_set(NMDevice *self, GPtrArray *temporary_not_available) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - IP6RoutesTemporaryNotAvailableData *data; - GHashTableIter iter; - gint64 now_ms, oldest_ms; - const gint64 MAX_AGE_MS = 20000; - guint i; - gboolean success = TRUE; - - if (!temporary_not_available || !temporary_not_available->len) { - /* nothing outstanding. Clear tracking the routes. */ - nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source(&priv->rt6_temporary_not_available_id); - return success; - } - - if (priv->rt6_temporary_not_available) { - g_hash_table_iter_init(&iter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data)) - data->dirty = TRUE; - } else { - priv->rt6_temporary_not_available = - g_hash_table_new_full((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal, - (GDestroyNotify) nmp_object_unref, - nm_g_slice_free_fcn(IP6RoutesTemporaryNotAvailableData)); - } - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - oldest_ms = now_ms; - - for (i = 0; i < temporary_not_available->len; i++) { - const NMPObject *o = temporary_not_available->pdata[i]; - - data = g_hash_table_lookup(priv->rt6_temporary_not_available, o); - if (data) { - if (!data->dirty) - continue; - data->dirty = FALSE; - nm_assert(data->timestamp_ms > 0 && data->timestamp_ms <= now_ms); - if (now_ms > data->timestamp_ms + MAX_AGE_MS) { - /* timeout. Could not add this address. */ - _LOGW(LOGD_DEVICE, - "failure to add IPv6 route: %s", - nmp_object_to_string(o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - success = FALSE; - } else - oldest_ms = MIN(data->timestamp_ms, oldest_ms); - continue; - } - - data = g_slice_new0(IP6RoutesTemporaryNotAvailableData); - data->timestamp_ms = now_ms; - g_hash_table_insert(priv->rt6_temporary_not_available, (gpointer) nmp_object_ref(o), data); - } - - g_hash_table_iter_init(&iter, priv->rt6_temporary_not_available); - while (g_hash_table_iter_next(&iter, NULL, (gpointer *) &data)) { - if (data->dirty) - g_hash_table_iter_remove(&iter); - } - - nm_clear_g_source(&priv->rt6_temporary_not_available_id); - priv->rt6_temporary_not_available_id = - g_timeout_add(oldest_ms + MAX_AGE_MS - now_ms, _rt6_temporary_not_available_timeout, self); - - return success; -} - -/*****************************************************************************/ - -static void -disconnect_cb(NMDevice * self, - GDBusMethodInvocation *context, - NMAuthSubject * subject, - GError * error, - gpointer user_data) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - GError * local = NULL; - - if (error) { - g_dbus_method_invocation_return_gerror(context, error); - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DISCONNECT, - self, - FALSE, - NULL, - subject, - error->message); - return; - } - - /* Authorized */ - if (priv->state <= NM_DEVICE_STATE_DISCONNECTED) { - local = g_error_new_literal(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "Device is not active"); - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DISCONNECT, - self, - FALSE, - NULL, - subject, - local->message); - g_dbus_method_invocation_take_error(context, local); - } else { - nm_device_autoconnect_blocked_set(self, NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT); - - nm_device_state_changed(self, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - g_dbus_method_invocation_return_value(context, NULL); - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DISCONNECT, self, TRUE, NULL, subject, NULL); - } -} - -static void -_clear_queued_act_request(NMDevicePrivate *priv, NMActiveConnectionStateReason active_reason) -{ - if (priv->queued_act_request) { - gs_unref_object NMActRequest *ac = NULL; - - ac = g_steal_pointer(&priv->queued_act_request); - nm_active_connection_set_state_fail((NMActiveConnection *) ac, active_reason, NULL); - } -} - -static void -impl_device_disconnect(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * dbus_connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - NMDevice * self = NM_DEVICE(obj); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - - if (!priv->act_request.obj) { - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "This device is not active"); - return; - } - - connection = nm_device_get_applied_connection(self); - nm_assert(connection); - - nm_device_auth_request(self, - invocation, - connection, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - NULL, - disconnect_cb, - NULL); -} - -static void -delete_cb(NMDevice * self, - GDBusMethodInvocation *context, - NMAuthSubject * subject, - GError * error, - gpointer user_data) -{ - GError *local = NULL; - - if (error) { - g_dbus_method_invocation_return_gerror(context, error); - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DELETE, - self, - FALSE, - NULL, - subject, - error->message); - return; - } - - /* Authorized */ - nm_audit_log_device_op(NM_AUDIT_OP_DEVICE_DELETE, self, TRUE, NULL, subject, NULL); - if (nm_device_unrealize(self, TRUE, &local)) - g_dbus_method_invocation_return_value(context, NULL); - else - g_dbus_method_invocation_take_error(context, local); -} - -static void -impl_device_delete(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - NMDevice *self = NM_DEVICE(obj); - - if (!nm_device_is_software(self) || !nm_device_is_real(self)) { - g_dbus_method_invocation_return_error_literal( - invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_SOFTWARE, - "This device is not a software device or is not realized"); - return; - } - - nm_device_auth_request(self, - invocation, - NULL, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - TRUE, - NULL, - delete_cb, - NULL); -} - -static void -_device_activate(NMDevice *self, NMActRequest *req) -{ - NMConnection *connection; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - nm_assert(nm_device_is_real(self)); - - /* Ensure the activation request is still valid; the master may have - * already failed in which case activation of this device should not proceed. - */ - if (nm_active_connection_get_state(NM_ACTIVE_CONNECTION(req)) - >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) - return; - - if (!nm_device_get_managed(self, FALSE)) { - /* It's unclear why the device would be unmanaged at this point. - * Just to be sure, handle it and error out. */ - _LOGE(LOGD_DEVICE, - "Activation: failed activating connection '%s' because device is still unmanaged", - nm_active_connection_get_settings_connection_id((NMActiveConnection *) req)); - nm_active_connection_set_state_fail((NMActiveConnection *) req, - NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN, - NULL); - return; - } - - connection = nm_act_request_get_applied_connection(req); - nm_assert(connection); - - _LOGI(LOGD_DEVICE, - "Activation: starting connection '%s' (%s)", - nm_connection_get_id(connection), - nm_connection_get_uuid(connection)); - - delete_on_deactivate_unschedule(self); - - act_request_set(self, req); - - nm_device_activate_schedule_stage1_device_prepare(self, FALSE); -} - -static void -_carrier_wait_check_queued_act_request(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->queued_act_request || !priv->queued_act_request_is_waiting_for_carrier) - return; - - priv->queued_act_request_is_waiting_for_carrier = FALSE; - if (!priv->carrier) { - _LOGD(LOGD_DEVICE, "Cancel queued activation request as we have no carrier after timeout"); - _clear_queued_act_request(priv, NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); - } else if (priv->state == NM_DEVICE_STATE_DISCONNECTED) { - gs_unref_object NMActRequest *queued_req = NULL; - - _LOGD(LOGD_DEVICE, "Activate queued activation request as we now have carrier"); - queued_req = g_steal_pointer(&priv->queued_act_request); - _device_activate(self, queued_req); - } -} - -static gboolean -_carrier_wait_check_act_request_must_queue(NMDevice *self, NMActRequest *req) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - - /* If we have carrier or if we are not waiting for it, the activation - * request is not blocked waiting for carrier. */ - if (priv->carrier) - return FALSE; - if (priv->carrier_wait_id == 0) - return FALSE; - - connection = nm_act_request_get_applied_connection(req); - if (!connection_requires_carrier(connection)) - return FALSE; - - if (!nm_device_check_connection_available(self, - connection, - NM_DEVICE_CHECK_CON_AVAILABLE_ALL, - NULL, - NULL)) { - /* We passed all @flags we have, and no @specific_object. - * This equals maximal availability, if a connection is not available - * in this case, it is not waiting for carrier. - * - * Actually, why are we even trying to activate it? Strange, but whatever - * the reason, don't wait for carrier. - */ - return FALSE; - } - - if (nm_device_check_connection_available( - self, - connection, - NM_DEVICE_CHECK_CON_AVAILABLE_ALL - & ~_NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER, - NULL, - NULL)) { - /* The connection was available with flags ALL, and it is still available - * if we pretend not to wait for carrier. That means that the - * connection is available now, and does not wait for carrier. - * - * Since the flags increase the availability of a connection, when checking - * ALL&~WAITING_CARRIER, it means that we certainly would wait for carrier. */ - return FALSE; - } - - /* The activation request must wait for carrier. */ - return TRUE; -} - -void -nm_device_disconnect_active_connection(NMActiveConnection * active, - NMDeviceStateReason device_reason, - NMActiveConnectionStateReason active_reason) -{ - NMDevice * self; - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_ACTIVE_CONNECTION(active)); - - self = nm_active_connection_get_device(active); - if (!self) { - /* hm, no device? Just fail the active connection. */ - goto do_fail; - } - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (NM_ACTIVE_CONNECTION(priv->queued_act_request) == active) { - _clear_queued_act_request(priv, active_reason); - return; - } - - if (NM_ACTIVE_CONNECTION(priv->act_request.obj) == active) { - if (priv->state < NM_DEVICE_STATE_DEACTIVATING) { - nm_device_state_changed(self, NM_DEVICE_STATE_DEACTIVATING, device_reason); - } else { - /* @active is the current ac of @self, but it's going down already. - * Nothing to do. */ - } - return; - } - - /* the active connection references this device, but it's neither the - * queued_act_request nor the current act_request. Just set it to fail... */ -do_fail: - nm_active_connection_set_state_fail(active, active_reason, NULL); -} - -void -nm_device_queue_activation(NMDevice *self, NMActRequest *req) -{ - NMDevicePrivate *priv; - gboolean must_queue; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - nm_keep_alive_arm(nm_active_connection_get_keep_alive(NM_ACTIVE_CONNECTION(req))); - - if (nm_active_connection_get_state(NM_ACTIVE_CONNECTION(req)) - >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) { - /* it's already deactivating. Nothing to do. */ - nm_assert( - NM_IN_SET(nm_active_connection_get_device(NM_ACTIVE_CONNECTION(req)), NULL, self)); - return; - } - - nm_assert(self == nm_active_connection_get_device(NM_ACTIVE_CONNECTION(req))); - - priv = NM_DEVICE_GET_PRIVATE(self); - - must_queue = _carrier_wait_check_act_request_must_queue(self, req); - - if (!priv->act_request.obj && !must_queue && nm_device_is_real(self)) { - _device_activate(self, req); - return; - } - - /* supersede any already-queued request */ - _clear_queued_act_request(priv, NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); - priv->queued_act_request = g_object_ref(req); - priv->queued_act_request_is_waiting_for_carrier = must_queue; - - _LOGD(LOGD_DEVICE, - "queue activation request waiting for %s", - must_queue ? "carrier" : "currently active connection to disconnect"); - - /* Deactivate existing activation request first */ - if (priv->act_request.obj) { - _LOGI(LOGD_DEVICE, "disconnecting for new activation request."); - nm_device_state_changed(self, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_NEW_ACTIVATION); - } -} - -/* - * nm_device_is_activating - * - * Return whether or not the device is currently activating itself. - * - */ -gboolean -nm_device_is_activating(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceState state; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - state = nm_device_get_state(self); - if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_SECONDARIES) - return TRUE; - - /* There's a small race between the time when stage 1 is scheduled - * and when the device actually sets STATE_PREPARE when the activation - * handler is actually run. If there's an activation handler scheduled - * we're activating anyway. - */ - return priv->activation_source_id_4 != 0; -} - -NMProxyConfig * -nm_device_get_proxy_config(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->proxy_config; -} - -static void -nm_device_set_proxy_config(NMDevice *self, const char *pac_url) -{ - NMDevicePrivate *priv; - NMConnection * connection; - NMSettingProxy * s_proxy = NULL; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - g_clear_object(&priv->proxy_config); - priv->proxy_config = nm_proxy_config_new(); - - if (pac_url) { - nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_AUTO); - nm_proxy_config_set_pac_url(priv->proxy_config, pac_url); - _LOGD(LOGD_PROXY, "proxy: PAC url \"%s\"", pac_url); - } else - nm_proxy_config_set_method(priv->proxy_config, NM_PROXY_CONFIG_METHOD_NONE); - - connection = nm_device_get_applied_connection(self); - if (connection) - s_proxy = nm_connection_get_setting_proxy(connection); - - if (s_proxy) - nm_proxy_config_merge_setting(priv->proxy_config, s_proxy); -} - -/* IP Configuration stuff */ -NMDhcpConfig * -nm_device_get_dhcp_config(NMDevice *self, int addr_family) -{ - const gboolean IS_IPv4 = (addr_family == AF_INET); - - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - nm_assert_addr_family(addr_family); - - return NM_DEVICE_GET_PRIVATE(self)->dhcp_data_x[IS_IPv4].config; -} - -NMIP4Config * -nm_device_get_ip4_config(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->ip_config_4; -} - -static gboolean -nm_device_set_ip_config(NMDevice * self, - int addr_family, - NMIPConfig *new_config, - gboolean commit, - GPtrArray * ip4_dev_route_blacklist) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const gboolean IS_IPv4 = (addr_family == AF_INET); - NMIPConfig * old_config; - gboolean has_changes = FALSE; - gboolean success = TRUE; - NMSettingsConnection *settings_connection; - - nm_assert_addr_family(addr_family); - nm_assert(!new_config || nm_ip_config_get_addr_family(new_config) == addr_family); - nm_assert(!new_config - || (new_config && ({ - int ip_ifindex = nm_device_get_ip_ifindex(self); - - (ip_ifindex > 0 && ip_ifindex == nm_ip_config_get_ifindex(new_config)); - }))); - nm_assert(IS_IPv4 || !ip4_dev_route_blacklist); - - _LOGD(LOGD_IP_from_af(addr_family), - "ip%c-config: update (commit=%d, new-config=%p)", - nm_utils_addr_family_to_char(addr_family), - commit, - new_config); - - /* Always commit to nm-platform to update lifetimes */ - if (commit && new_config) { - _commit_mtu(self, IS_IPv4 ? NM_IP4_CONFIG(new_config) : priv->ip_config_4); - - if (IS_IPv4) { - success = nm_ip4_config_commit(NM_IP4_CONFIG(new_config), - nm_device_get_platform(self), - _get_route_table_sync_mode_stateful(self, AF_INET)); - nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), - nm_ip_config_get_ifindex(new_config), - ip4_dev_route_blacklist); - } else { - gs_unref_ptrarray GPtrArray *temporary_not_available = NULL; - - success = nm_ip6_config_commit(NM_IP6_CONFIG(new_config), - nm_device_get_platform(self), - _get_route_table_sync_mode_stateful(self, AF_INET6), - &temporary_not_available); - - if (!_rt6_temporary_not_available_set(self, temporary_not_available)) - success = FALSE; - } - } - - old_config = priv->ip_config_x[IS_IPv4]; - - if (new_config && old_config) { - /* has_changes is set only on relevant changes, because when the configuration changes, - * this causes a re-read and reset. This should only happen for relevant changes */ - nm_ip_config_replace(old_config, new_config, &has_changes); - if (has_changes) { - _LOGD(LOGD_IP_from_af(addr_family), - "ip%c-config: update IP Config instance (%s)", - nm_utils_addr_family_to_char(addr_family), - nm_dbus_object_get_path(NM_DBUS_OBJECT(old_config))); - } - } else if (new_config /*&& !old_config*/) { - has_changes = TRUE; - priv->ip_config_x[IS_IPv4] = g_object_ref(new_config); - if (!nm_dbus_object_is_exported(NM_DBUS_OBJECT(new_config))) - nm_dbus_object_export(NM_DBUS_OBJECT(new_config)); - - _LOGD(LOGD_IP_from_af(addr_family), - "ip%c-config: set IP Config instance (%s)", - nm_utils_addr_family_to_char(addr_family), - nm_dbus_object_get_path(NM_DBUS_OBJECT(new_config))); - } else if (old_config /*&& !new_config*/) { - has_changes = TRUE; - priv->ip_config_x[IS_IPv4] = NULL; - _LOGD(LOGD_IP_from_af(addr_family), - "ip%c-config: clear IP Config instance (%s)", - nm_utils_addr_family_to_char(addr_family), - nm_dbus_object_get_path(NM_DBUS_OBJECT(old_config))); - if (IS_IPv4) { - /* Device config is invalid if combined config is invalid */ - applied_config_clear(&priv->dev_ip_config_4); - } else - priv->needs_ip6_subnet = FALSE; - } - - if (has_changes) { - if (old_config != priv->ip_config_x[IS_IPv4]) - _notify(self, IS_IPv4 ? PROP_IP4_CONFIG : PROP_IP6_CONFIG); - - g_signal_emit(self, - signals[IS_IPv4 ? IP4_CONFIG_CHANGED : IP6_CONFIG_CHANGED], - 0, - priv->ip_config_x[IS_IPv4], - old_config); - - if (old_config != priv->ip_config_x[IS_IPv4]) - nm_dbus_object_clear_and_unexport(&old_config); - - if (nm_device_sys_iface_state_is_external(self) - && (settings_connection = nm_device_get_settings_connection(self)) - && NM_FLAGS_HAS(nm_settings_connection_get_flags(settings_connection), - NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL) - && nm_active_connection_get_activation_type(NM_ACTIVE_CONNECTION(priv->act_request.obj)) - == NM_ACTIVATION_TYPE_EXTERNAL) { - gs_unref_object NMConnection *new_connection = NULL; - - new_connection = nm_simple_connection_new_clone( - nm_settings_connection_get_connection(settings_connection)); - - nm_connection_add_setting( - new_connection, - IS_IPv4 ? nm_ip4_config_create_setting(priv->ip_config_4) - : nm_ip6_config_create_setting(priv->ip_config_6, - _get_maybe_ipv6_disabled(self))); - - nm_settings_connection_update(settings_connection, - new_connection, - NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, - NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, - "update-external", - NULL); - } - - nm_device_queue_recheck_assume(self); - - if (!IS_IPv4) { - if (priv->ndisc) - ndisc_set_router_config(priv->ndisc, self); - } - } - - nm_assert(!old_config || old_config == priv->ip_config_x[IS_IPv4]); - - return success; -} - -static gboolean -_replace_vpn_config_in_list(GSList **plist, GObject *old, GObject *new) -{ - GSList *old_link; - - /* Below, assert that @new is not yet tracked, but still behave - * correctly in any case. Don't complain for missing @old since - * it could have been removed when the parent device became - * unmanaged. */ - - if (old && (old_link = g_slist_find(*plist, old))) { - if (old != new) { - if (new) - old_link->data = g_object_ref(new); - else - *plist = g_slist_delete_link(*plist, old_link); - g_object_unref(old); - } - return TRUE; - } - - if (new) { - if (!g_slist_find(*plist, new)) - *plist = g_slist_append(*plist, g_object_ref(new)); - else - g_return_val_if_reached(TRUE); - return TRUE; - } - - return FALSE; -} - -void -nm_device_replace_vpn4_config(NMDevice *self, NMIP4Config *old, NMIP4Config *config) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert(!old || NM_IS_IP4_CONFIG(old)); - nm_assert(!config || NM_IS_IP4_CONFIG(config)); - nm_assert(!old || nm_ip4_config_get_ifindex(old) == nm_device_get_ip_ifindex(self)); - nm_assert(!config || nm_ip4_config_get_ifindex(config) == nm_device_get_ip_ifindex(self)); - - if (!_replace_vpn_config_in_list(&priv->vpn_configs_4, (GObject *) old, (GObject *) config)) - return; - - /* NULL to use existing configs */ - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "failed to set VPN routes for device"); -} - -void -nm_device_set_dev2_ip_config(NMDevice *self, int addr_family, NMIPConfig *config) -{ - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IN_SET(addr_family, AF_INET, AF_INET6)); - g_return_if_fail(!config || nm_ip_config_get_addr_family(config) == addr_family); - - priv = NM_DEVICE_GET_PRIVATE(self); - - applied_config_init(&priv->dev2_ip_config_x[IS_IPv4], config); - if (!ip_config_merge_and_apply(self, addr_family, TRUE)) { - _LOGW(LOGD_IP, - "failed to set extra device IPv%c configuration", - nm_utils_addr_family_to_char(addr_family)); - } -} - -void -nm_device_replace_vpn6_config(NMDevice *self, NMIP6Config *old, NMIP6Config *config) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert(!old || NM_IS_IP6_CONFIG(old)); - nm_assert(!config || NM_IS_IP6_CONFIG(config)); - nm_assert(!old || nm_ip6_config_get_ifindex(old) == nm_device_get_ip_ifindex(self)); - nm_assert(!config || nm_ip6_config_get_ifindex(config) == nm_device_get_ip_ifindex(self)); - - if (!_replace_vpn_config_in_list(&priv->vpn_configs_6, (GObject *) old, (GObject *) config)) - return; - - /* NULL to use existing configs */ - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "failed to set VPN routes for device"); -} - -NMIP6Config * -nm_device_get_ip6_config(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->ip_config_6; -} - -/*****************************************************************************/ - -static gboolean -dispatcher_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->dispatcher.call_id) - return FALSE; - - nm_dispatcher_call_cancel(g_steal_pointer(&priv->dispatcher.call_id)); - priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - return TRUE; -} - -static void -dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - g_return_if_fail(call_id == priv->dispatcher.call_id); - - priv->dispatcher.call_id = NULL; - nm_device_queue_state(self, priv->dispatcher.post_state, priv->dispatcher.post_state_reason); - priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; -} - -/*****************************************************************************/ - -static void -ip_check_pre_up(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (dispatcher_cleanup(self)) - nm_assert_not_reached(); - - priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - if (!nm_dispatcher_call_device(NM_DISPATCHER_ACTION_PRE_UP, - self, - NULL, - dispatcher_complete_proceed_state, - self, - &priv->dispatcher.call_id)) { - /* Just proceed on errors */ - dispatcher_complete_proceed_state(0, self); - } -} - -static void -ip_check_gw_ping_cleanup(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_clear_g_source(&priv->gw_ping.watch); - nm_clear_g_source(&priv->gw_ping.timeout); - - if (priv->gw_ping.pid) { - nm_utils_kill_child_async(priv->gw_ping.pid, - SIGTERM, - priv->gw_ping.log_domain, - "ping", - 1000, - NULL, - NULL); - priv->gw_ping.pid = 0; - } - - nm_clear_g_free(&priv->gw_ping.binary); - nm_clear_g_free(&priv->gw_ping.address); -} - -static gboolean -spawn_ping(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gs_free char * str_timeout = NULL; - gs_free char * tmp_str = NULL; - const char * args[] = {priv->gw_ping.binary, - "-I", - nm_device_get_ip_iface(self), - "-c", - "1", - "-w", - NULL, - priv->gw_ping.address, - NULL}; - gs_free_error GError *error = NULL; - gboolean ret; - - args[6] = str_timeout = g_strdup_printf("%u", priv->gw_ping.deadline); - tmp_str = g_strjoinv(" ", (char **) args); - _LOGD(priv->gw_ping.log_domain, "ping: running '%s'", tmp_str); - - ret = g_spawn_async("/", - (char **) args, - NULL, - G_SPAWN_DO_NOT_REAP_CHILD, - NULL, - NULL, - &priv->gw_ping.pid, - &error); - - if (!ret) { - _LOGW(priv->gw_ping.log_domain, - "ping: could not spawn %s: %s", - priv->gw_ping.binary, - error->message); - } - - return ret; -} - -static gboolean -respawn_ping_cb(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->gw_ping.watch = 0; - - if (spawn_ping(self)) { - priv->gw_ping.watch = g_child_watch_add(priv->gw_ping.pid, ip_check_ping_watch_cb, self); - } else { - ip_check_gw_ping_cleanup(self); - ip_check_pre_up(self); - } - - return FALSE; -} - -static void -ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMLogDomain log_domain = priv->gw_ping.log_domain; - gboolean success = FALSE; - - if (!priv->gw_ping.watch) - return; - priv->gw_ping.watch = 0; - priv->gw_ping.pid = 0; - - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) == 0) { - _LOGD(log_domain, "ping: gateway ping succeeded"); - success = TRUE; - } else { - _LOGW(log_domain, "ping: gateway ping failed with error code %d", WEXITSTATUS(status)); - } - } else - _LOGW(log_domain, "ping: stopped unexpectedly with status %d", status); - - if (success) { - /* We've got connectivity, proceed to pre_up */ - ip_check_gw_ping_cleanup(self); - ip_check_pre_up(self); - } else { - /* If ping exited with an error it may have returned early, - * wait 1 second and restart it */ - priv->gw_ping.watch = g_timeout_add_seconds(1, respawn_ping_cb, self); - } -} - -static gboolean -ip_check_ping_timeout_cb(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->gw_ping.timeout = 0; - - _LOGW(priv->gw_ping.log_domain, "ping: gateway ping timed out"); - - ip_check_gw_ping_cleanup(self); - ip_check_pre_up(self); - return FALSE; -} - -static gboolean -start_ping(NMDevice * self, - NMLogDomain log_domain, - const char *binary, - const char *address, - guint timeout) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - g_return_val_if_fail(priv->gw_ping.watch == 0, FALSE); - g_return_val_if_fail(priv->gw_ping.timeout == 0, FALSE); - - priv->gw_ping.log_domain = log_domain; - priv->gw_ping.address = g_strdup(address); - priv->gw_ping.binary = g_strdup(binary); - priv->gw_ping.deadline = timeout + 10; /* the proper termination is enforced by a timer */ - - if (spawn_ping(self)) { - priv->gw_ping.watch = g_child_watch_add(priv->gw_ping.pid, ip_check_ping_watch_cb, self); - priv->gw_ping.timeout = g_timeout_add_seconds(timeout, ip_check_ping_timeout_cb, self); - return TRUE; - } - - ip_check_gw_ping_cleanup(self); - return FALSE; -} - -static void -nm_device_start_ip_check(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMConnection * connection; - NMSettingConnection *s_con; - guint timeout = 0; - const char * ping_binary = NULL; - char buf[NM_UTILS_INET_ADDRSTRLEN]; - NMLogDomain log_domain = LOGD_IP4; - - /* Shouldn't be any active ping here, since IP_CHECK happens after the - * first IP method completes. Any subsequently completing IP method doesn't - * get checked. - */ - g_return_if_fail(!priv->gw_ping.watch); - g_return_if_fail(!priv->gw_ping.timeout); - g_return_if_fail(!priv->gw_ping.pid); - g_return_if_fail(priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - || priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE); - - connection = nm_device_get_applied_connection(self); - g_assert(connection); - - s_con = nm_connection_get_setting_connection(connection); - g_assert(s_con); - timeout = nm_setting_connection_get_gateway_ping_timeout(s_con); - - buf[0] = '\0'; - if (timeout) { - const NMPObject *gw; - - if (priv->ip_config_4 && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - gw = nm_ip4_config_best_default_route_get(priv->ip_config_4); - if (gw) { - _nm_utils_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf); - ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL); - log_domain = LOGD_IP4; - } - } else if (priv->ip_config_6 && priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { - gw = nm_ip6_config_best_default_route_get(priv->ip_config_6); - if (gw) { - _nm_utils_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf); - ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL); - log_domain = LOGD_IP6; - } - } - } - - if (buf[0]) - start_ping(self, log_domain, ping_binary, buf, timeout); - - /* If no ping was started, just advance to pre_up */ - if (!priv->gw_ping.pid) - ip_check_pre_up(self); -} - -/*****************************************************************************/ - -static gboolean -carrier_wait_timeout(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->carrier_wait_id = 0; - nm_device_remove_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); - if (!priv->carrier) - _carrier_wait_check_queued_act_request(self); - return G_SOURCE_REMOVE; -} - -static gboolean -nm_device_is_up(NMDevice *self) -{ - int ifindex; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - ifindex = nm_device_get_ip_ifindex(self); - return ifindex > 0 ? nm_platform_link_is_up(nm_device_get_platform(self), ifindex) : TRUE; -} - -static gint64 -_get_carrier_wait_ms(NMDevice *self) -{ - gs_free char *value = NULL; - - value = nm_config_data_get_device_config(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT, - self, - NULL); - return _nm_utils_ascii_str_to_int64(value, 10, 0, G_MAXINT32, CARRIER_WAIT_TIME_MS); -} - -gboolean -nm_device_bring_up(NMDevice *self, gboolean block, gboolean *no_firmware) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - gboolean device_is_up = FALSE; - NMDeviceCapabilities capabilities; - int ifindex; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - NM_SET_OUT(no_firmware, FALSE); - - if (!nm_device_get_enabled(self)) { - _LOGD(LOGD_PLATFORM, "bringing up device ignored due to disabled"); - return FALSE; - } - - ifindex = nm_device_get_ip_ifindex(self); - _LOGD(LOGD_PLATFORM, "bringing up device %d", ifindex); - if (ifindex <= 0) { - /* assume success. */ - } else { - if (!nm_platform_link_set_up(nm_device_get_platform(self), ifindex, no_firmware)) - return FALSE; - } - - /* Store carrier immediately. */ - nm_device_set_carrier_from_platform(self); - - device_is_up = nm_device_is_up(self); - if (block && !device_is_up) { - gint64 wait_until = nm_utils_get_monotonic_timestamp_usec() + 10000 /* microseconds */; - - do { - g_usleep(200); - if (!nm_platform_link_refresh(nm_device_get_platform(self), ifindex)) - return FALSE; - device_is_up = nm_device_is_up(self); - } while (!device_is_up && nm_utils_get_monotonic_timestamp_usec() < wait_until); - } - - if (!device_is_up) { - if (block) - _LOGW(LOGD_PLATFORM, "device not up after timeout!"); - else - _LOGD(LOGD_PLATFORM, "device not up immediately"); - return FALSE; - } - - /* some ethernet devices fail to report capabilities unless the device - * is up. Re-read the capabilities. */ - capabilities = 0; - if (NM_DEVICE_GET_CLASS(self)->get_generic_capabilities) - capabilities |= NM_DEVICE_GET_CLASS(self)->get_generic_capabilities(self); - _add_capabilities(self, capabilities); - - /* Devices that support carrier detect must be IFF_UP to report carrier - * changes; so after setting the device IFF_UP we must suppress startup - * complete (via a pending action) until either the carrier turns on, or - * a timeout is reached. - */ - if (nm_device_has_capability(self, NM_DEVICE_CAP_CARRIER_DETECT)) { - gint64 now_ms, until_ms; - - /* we start a grace period of 5 seconds during which we will schedule - * a pending action whenever we have no carrier. - * - * If during that time carrier goes away, we declare the interface - * as not ready. */ - nm_clear_g_source(&priv->carrier_wait_id); - if (!priv->carrier) - nm_device_add_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); - - now_ms = nm_utils_get_monotonic_timestamp_msec(); - until_ms = NM_MAX(now_ms + _get_carrier_wait_ms(self), priv->carrier_wait_until_ms); - priv->carrier_wait_id = g_timeout_add(until_ms - now_ms, carrier_wait_timeout, self); - } - - /* Can only get HW address of some devices when they are up */ - nm_device_update_hw_address(self); - - /* when the link comes up, we must restore IP configuration if necessary. */ - if (priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE) { - if (!ip_config_merge_and_apply(self, AF_INET, TRUE)) - _LOGW(LOGD_IP4, "failed applying IP4 config after bringing link up"); - } - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { - if (!ip_config_merge_and_apply(self, AF_INET6, TRUE)) - _LOGW(LOGD_IP6, "failed applying IP6 config after bringing link up"); - } - - return TRUE; -} - -void -nm_device_take_down(NMDevice *self, gboolean block) -{ - int ifindex; - gboolean device_is_up; - - g_return_if_fail(NM_IS_DEVICE(self)); - - ifindex = nm_device_get_ip_ifindex(self); - _LOGD(LOGD_PLATFORM, "taking down device %d", ifindex); - if (ifindex <= 0) { - /* devices without ifindex are always up. */ - return; - } - - if (!nm_platform_link_set_down(nm_device_get_platform(self), ifindex)) - return; - - device_is_up = nm_device_is_up(self); - if (block && device_is_up) { - gint64 wait_until = nm_utils_get_monotonic_timestamp_usec() + 10000 /* microseconds */; - - do { - g_usleep(200); - if (!nm_platform_link_refresh(nm_device_get_platform(self), ifindex)) - return; - device_is_up = nm_device_is_up(self); - } while (device_is_up && nm_utils_get_monotonic_timestamp_usec() < wait_until); - } - - if (device_is_up) { - if (block) - _LOGW(LOGD_PLATFORM, "device not down after timeout!"); - else - _LOGD(LOGD_PLATFORM, "device not down immediately"); - } -} - -void -nm_device_set_firmware_missing(NMDevice *self, gboolean new_missing) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->firmware_missing != new_missing) { - priv->firmware_missing = new_missing; - _notify(self, PROP_FIRMWARE_MISSING); - } -} - -gboolean -nm_device_get_firmware_missing(NMDevice *self) -{ - return NM_DEVICE_GET_PRIVATE(self)->firmware_missing; -} - -static void -intersect_ext_config(NMDevice * self, - AppliedConfig *config, - gboolean intersect_addresses, - gboolean intersect_routes) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMIPConfig * ext; - guint32 penalty; - int family; - - if (!config->orig) - return; - - family = nm_ip_config_get_addr_family(config->orig); - penalty = default_route_metric_penalty_get(self, family); - ext = family == AF_INET ? (NMIPConfig *) priv->ext_ip_config_4 - : (NMIPConfig *) priv->ext_ip_config_6; - - if (config->current) { - nm_ip_config_intersect(config->current, - ext, - intersect_addresses, - intersect_routes, - penalty); - } else { - config->current = nm_ip_config_intersect_alloc(config->orig, - ext, - intersect_addresses, - intersect_routes, - penalty); - } -} - -static gboolean -update_ext_ip_config(NMDevice *self, int addr_family, gboolean intersect_configs) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - int ifindex; - GSList * iter; - gboolean is_up; - - nm_assert_addr_family(addr_family); - - ifindex = nm_device_get_ip_ifindex(self); - if (!ifindex) - return FALSE; - - is_up = nm_platform_link_is_up(nm_device_get_platform(self), ifindex); - - if (addr_family == AF_INET) { - g_clear_object(&priv->ext_ip_config_4); - priv->ext_ip_config_4 = nm_ip4_config_capture(nm_device_get_multi_index(self), - nm_device_get_platform(self), - ifindex); - if (priv->ext_ip_config_4) { - if (intersect_configs) { - /* This function was called upon external changes. Remove the configuration - * (addresses,routes) that is no longer present externally from the internal - * config. This way, we don't re-add addresses that were manually removed - * by the user. */ - if (priv->con_ip_config_4) { - nm_ip4_config_intersect(priv->con_ip_config_4, - priv->ext_ip_config_4, - TRUE, - is_up, - default_route_metric_penalty_get(self, AF_INET)); - } - - intersect_ext_config(self, &priv->dev_ip_config_4, TRUE, is_up); - intersect_ext_config(self, &priv->dev2_ip_config_4, TRUE, is_up); - - for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_intersect(iter->data, priv->ext_ip_config_4, TRUE, is_up, 0); - } - - /* Remove parts from ext_ip_config_4 to only contain the information that - * was configured externally -- we already have the same configuration from - * internal origins. */ - if (priv->con_ip_config_4) { - nm_ip4_config_subtract(priv->ext_ip_config_4, - priv->con_ip_config_4, - default_route_metric_penalty_get(self, AF_INET)); - } - if (applied_config_get_current(&priv->dev_ip_config_4)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current(&priv->dev_ip_config_4), - default_route_metric_penalty_get(self, AF_INET)); - } - if (applied_config_get_current(&priv->dev2_ip_config_4)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_4, - applied_config_get_current(&priv->dev2_ip_config_4), - default_route_metric_penalty_get(self, AF_INET)); - } - for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_subtract(priv->ext_ip_config_4, iter->data, 0); - } - - } else { - nm_assert(addr_family == AF_INET6); - - g_clear_object(&priv->ext_ip_config_6); - g_clear_object(&priv->ext_ip6_config_captured); - priv->ext_ip6_config_captured = - nm_ip6_config_capture(nm_device_get_multi_index(self), - nm_device_get_platform(self), - ifindex, - NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); - if (priv->ext_ip6_config_captured) { - priv->ext_ip_config_6 = nm_ip6_config_new_cloned(priv->ext_ip6_config_captured); - - if (intersect_configs) { - /* This function was called upon external changes. Remove the configuration - * (addresses,routes) that is no longer present externally from the internal - * config. This way, we don't re-add addresses that were manually removed - * by the user. */ - if (priv->con_ip_config_6) { - nm_ip6_config_intersect(priv->con_ip_config_6, - priv->ext_ip_config_6, - is_up, - is_up, - default_route_metric_penalty_get(self, AF_INET6)); - } - - intersect_ext_config(self, &priv->ac_ip6_config, is_up, is_up); - intersect_ext_config(self, &priv->dhcp6.ip6_config, is_up, is_up); - intersect_ext_config(self, &priv->dev2_ip_config_6, is_up, is_up); - - for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_intersect(iter->data, priv->ext_ip_config_6, is_up, is_up, 0); - - if (is_up && priv->ipv6ll_has - && !nm_ip6_config_lookup_address(priv->ext_ip_config_6, &priv->ipv6ll_addr)) - priv->ipv6ll_has = FALSE; - } - - /* Remove parts from ext_ip_config_6 to only contain the information that - * was configured externally -- we already have the same configuration from - * internal origins. */ - if (priv->con_ip_config_6) { - nm_ip6_config_subtract(priv->ext_ip_config_6, - priv->con_ip_config_6, - default_route_metric_penalty_get(self, AF_INET6)); - } - if (applied_config_get_current(&priv->ac_ip6_config)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current(&priv->ac_ip6_config), - default_route_metric_penalty_get(self, AF_INET6)); - } - if (applied_config_get_current(&priv->dhcp6.ip6_config)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current(&priv->dhcp6.ip6_config), - default_route_metric_penalty_get(self, AF_INET6)); - } - if (applied_config_get_current(&priv->dev2_ip_config_6)) { - nm_ip_config_subtract((NMIPConfig *) priv->ext_ip_config_6, - applied_config_get_current(&priv->dev2_ip_config_6), - default_route_metric_penalty_get(self, AF_INET6)); - } - for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_subtract(priv->ext_ip_config_6, iter->data, 0); - } - } - - return TRUE; -} - -static void -update_ip_config(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert_addr_family(addr_family); - - if (addr_family == AF_INET) - priv->update_ip_config_completed_v4 = TRUE; - else - priv->update_ip_config_completed_v6 = TRUE; - - if (update_ext_ip_config(self, addr_family, TRUE)) { - if (addr_family == AF_INET) { - if (priv->ext_ip_config_4) - ip_config_merge_and_apply(self, AF_INET, FALSE); - } else { - if (priv->ext_ip6_config_captured) - ip_config_merge_and_apply(self, AF_INET6, FALSE); - } - } -} - -void -nm_device_capture_initial_config(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->update_ip_config_completed_v4) - update_ip_config(self, AF_INET); - if (!priv->update_ip_config_completed_v6) - update_ip_config(self, AF_INET6); -} - -static gboolean -queued_ip_config_change(NMDevice *self, int addr_family) -{ - NMDevicePrivate *priv; - const gboolean IS_IPv4 = (addr_family == AF_INET); - - g_return_val_if_fail(NM_IS_DEVICE(self), G_SOURCE_REMOVE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - /* Wait for any queued state changes */ - if (priv->queued_state.id) - return G_SOURCE_CONTINUE; - - /* If a commit is scheduled, this function would potentially interfere with - * it changing IP configurations before they are applied. Postpone the - * update in such case. - */ - if (priv->activation_source_id_x[IS_IPv4] != 0 - && priv->activation_source_func_x[IS_IPv4] == activate_stage5_ip_config_result_x[IS_IPv4]) - return G_SOURCE_CONTINUE; - - priv->queued_ip_config_id_x[IS_IPv4] = 0; - - update_ip_config(self, addr_family); - - if (!IS_IPv4) { - /* Check whether we need to complete waiting for link-local. - * We are also called from an idle handler, so no problem doing state transitions - * now. */ - linklocal6_check_complete(self); - } - - if (!IS_IPv4) { - NMPlatform * platform; - GSList * dad6_failed_addrs, *iter; - const NMPlatformLink *pllink; - - dad6_failed_addrs = g_steal_pointer(&priv->dad6_failed_addrs); - - if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state < NM_DEVICE_STATE_DEACTIVATING - && priv->ifindex > 0 && !nm_device_sys_iface_state_is_external(self) - && (platform = nm_device_get_platform(self)) - && (pllink = nm_platform_link_get(platform, priv->ifindex)) - && (pllink->n_ifi_flags & IFF_UP)) { - gboolean need_ipv6ll = FALSE; - NMNDiscConfigMap ndisc_config_changed = NM_NDISC_CONFIG_NONE; - - /* Handle DAD failures */ - for (iter = dad6_failed_addrs; iter; iter = iter->next) { - const NMPObject * obj = iter->data; - const NMPlatformIP6Address *addr; - - if (!nm_ndisc_dad_addr_is_fail_candidate(platform, obj)) - continue; - - addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj); - - _LOGI(LOGD_IP6, - "ipv6: duplicate address check failed for the %s address", - nm_platform_ip6_address_to_string(addr, NULL, 0)); - - if (IN6_IS_ADDR_LINKLOCAL(&addr->address)) - need_ipv6ll = TRUE; - else if (priv->ndisc) - ndisc_config_changed |= nm_ndisc_dad_failed(priv->ndisc, &addr->address, FALSE); - } - - if (ndisc_config_changed != NM_NDISC_CONFIG_NONE) - nm_ndisc_emit_config_change(priv->ndisc, ndisc_config_changed); - - /* If no IPv6 link-local address exists but other addresses do then we - * must add the LL address to remain conformant with RFC 3513 chapter 2.1 - * ("Addressing Model"): "All interfaces are required to have at least - * one link-local unicast address". - */ - if (priv->ip_config_6 && nm_ip6_config_get_num_addresses(priv->ip_config_6)) - need_ipv6ll = TRUE; - if (need_ipv6ll) - check_and_add_ipv6ll_addr(self); - } - - g_slist_free_full(dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - } - - if (!IS_IPv4) { - /* Check if DAD is still pending */ - if (priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF && priv->dad6_ip6_config - && priv->ext_ip6_config_captured - && !nm_ip6_config_has_any_dad_pending(priv->ext_ip6_config_captured, - priv->dad6_ip6_config)) { - _LOGD(LOGD_DEVICE | LOGD_IP6, "IPv6 DAD terminated"); - g_clear_object(&priv->dad6_ip6_config); - _set_ip_state(self, addr_family, NM_DEVICE_IP_STATE_DONE); - check_ip_state(self, FALSE, TRUE); - if (priv->rt6_temporary_not_available) - nm_device_activate_schedule_ip_config_result(self, AF_INET6, NULL); - } - } - - set_unmanaged_external_down(self, TRUE); - - return G_SOURCE_REMOVE; -} - -static gboolean -queued_ip4_config_change(gpointer user_data) -{ - return queued_ip_config_change(user_data, AF_INET); -} - -static gboolean -queued_ip6_config_change(gpointer user_data) -{ - return queued_ip_config_change(user_data, AF_INET6); -} - -static void -device_ipx_changed(NMPlatform * platform, - int obj_type_i, - int ifindex, - gconstpointer platform_object, - int change_type_i, - NMDevice * self) -{ - const NMPObjectType obj_type = obj_type_i; - const NMPlatformSignalChangeType change_type = change_type_i; - NMDevicePrivate * priv; - const NMPlatformIP6Address * addr; - - if (nm_device_get_ip_ifindex(self) != ifindex) - return; - - if (!nm_device_is_real(self)) - return; - - if (nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { - /* ignore all platform signals until the link is initialized in platform. */ - return; - } - - priv = NM_DEVICE_GET_PRIVATE(self); - - switch (obj_type) { - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP4_ROUTE: - if (!priv->queued_ip_config_id_4) { - priv->queued_ip_config_id_4 = g_idle_add(queued_ip4_config_change, self); - _LOGD(LOGD_DEVICE, "queued IP4 config change"); - } - break; - case NMP_OBJECT_TYPE_IP6_ADDRESS: - addr = platform_object; - - if (priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state < NM_DEVICE_STATE_DEACTIVATING - && nm_ndisc_dad_addr_is_fail_candidate_event(change_type, addr)) { - priv->dad6_failed_addrs = - g_slist_prepend(priv->dad6_failed_addrs, - (gpointer) nmp_object_ref(NMP_OBJECT_UP_CAST(addr))); - } - - /* fall-through */ - case NMP_OBJECT_TYPE_IP6_ROUTE: - if (!priv->queued_ip_config_id_6) { - priv->queued_ip_config_id_6 = g_idle_add(queued_ip6_config_change, self); - _LOGD(LOGD_DEVICE, "queued IP6 config change"); - } - break; - default: - g_return_if_reached(); - } -} - -/*****************************************************************************/ - -NM_UTILS_FLAGS2STR_DEFINE(nm_unmanaged_flags2str, - NMUnmanagedFlags, - NM_UTILS_FLAGS2STR(NM_UNMANAGED_SLEEPING, "sleeping"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_QUITTING, "quitting"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_PARENT, "parent"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_TYPE, "by-type"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_PLATFORM_INIT, "platform-init"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_EXPLICIT, "user-explicit"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_BY_DEFAULT, "by-default"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_SETTINGS, "user-settings"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_CONF, "user-conf"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_USER_UDEV, "user-udev"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_EXTERNAL_DOWN, "external-down"), - NM_UTILS_FLAGS2STR(NM_UNMANAGED_IS_SLAVE, "is-slave"), ); - -static const char * -_unmanaged_flags2str(NMUnmanagedFlags flags, NMUnmanagedFlags mask, char *buf, gsize len) -{ - char buf2[512]; - char *b; - char *tmp, *tmp2; - gsize l; - - nm_utils_to_string_buffer_init(&buf, &len); - if (!len) - return buf; - - b = buf; - - mask |= flags; - - nm_unmanaged_flags2str(flags, b, len); - l = strlen(b); - b += l; - len -= l; - - nm_unmanaged_flags2str(mask & ~flags, buf2, sizeof(buf2)); - if (buf2[0]) { - gboolean add_separator = l > 0; - - tmp = buf2; - while (TRUE) { - if (add_separator) - nm_utils_strbuf_append_c(&b, &len, ','); - add_separator = TRUE; - - tmp2 = strchr(tmp, ','); - if (tmp2) - tmp2[0] = '\0'; - - nm_utils_strbuf_append_c(&b, &len, '!'); - nm_utils_strbuf_append_str(&b, &len, tmp); - if (!tmp2) - break; - - tmp = &tmp2[1]; - } - } - - return buf; -} - -static gboolean -_get_managed_by_flags(NMUnmanagedFlags flags, NMUnmanagedFlags mask, gboolean for_user_request) -{ - /* Evaluate the managed state based on the unmanaged flags. - * - * Some flags are authoritative, meaning they always cause - * the device to be unmanaged (e.g. @NM_UNMANAGED_PLATFORM_INIT). - * - * OTOH, some flags can be overwritten. For example NM_UNMANAGED_USER_UDEV - * is ignored once NM_UNMANAGED_USER_EXPLICIT is set. The idea is that - * the flag from the configuration has no effect once the user explicitly - * touches the unmanaged flags. */ - - if (for_user_request) { - /* @for_user_request can make the result only ~more~ managed. - * If the flags already indicate a managed state for a non-user-request, - * then it is also managed for an explicit user-request. - * - * Effectively, this check is redundant, as the code below already - * already ensures that. Still, express this invariant explicitly here. */ - if (_get_managed_by_flags(flags, mask, FALSE)) - return TRUE; - - /* A for-user-request, is effectively the same as pretending - * that user-explicit flag is cleared. */ - mask |= NM_UNMANAGED_USER_EXPLICIT; - flags &= ~NM_UNMANAGED_USER_EXPLICIT; - } - - if (NM_FLAGS_ANY(mask, NM_UNMANAGED_USER_SETTINGS) - && !NM_FLAGS_ANY(flags, NM_UNMANAGED_USER_SETTINGS)) { - /* NM_UNMANAGED_USER_SETTINGS can only explicitly unmanage a device. It cannot - * *manage* it. Having NM_UNMANAGED_USER_SETTINGS explicitly not set, is the - * same as having it not set at all. */ - mask &= ~NM_UNMANAGED_USER_SETTINGS; - } - - if (NM_FLAGS_ANY(mask, NM_UNMANAGED_USER_UDEV)) { - /* configuration from udev or nm-config overwrites the by-default flag - * which is based on the device type. - * configuration from udev overwrites external-down */ - flags &= ~(NM_UNMANAGED_BY_DEFAULT | NM_UNMANAGED_EXTERNAL_DOWN); - } - - if (NM_FLAGS_ANY(mask, NM_UNMANAGED_USER_CONF)) { - /* configuration from NetworkManager.conf overwrites the by-default flag - * which is based on the device type. - * It also overwrites the udev configuration and external-down */ - flags &= ~(NM_UNMANAGED_BY_DEFAULT | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_EXTERNAL_DOWN); - } - - if (NM_FLAGS_HAS(mask, NM_UNMANAGED_IS_SLAVE) && !NM_FLAGS_HAS(flags, NM_UNMANAGED_IS_SLAVE)) { - /* for an enslaved device, by-default doesn't matter */ - flags &= ~NM_UNMANAGED_BY_DEFAULT; - } - - if (NM_FLAGS_HAS(mask, NM_UNMANAGED_USER_EXPLICIT)) { - /* if the device is managed by user-decision, certain other flags - * are ignored. */ - flags &= ~(NM_UNMANAGED_BY_DEFAULT | NM_UNMANAGED_USER_UDEV | NM_UNMANAGED_USER_CONF - | NM_UNMANAGED_EXTERNAL_DOWN); - } - - return flags == NM_UNMANAGED_NONE; -} - -/** - * nm_device_get_managed: - * @self: the #NMDevice - * @for_user_request: whether to check the flags for an explicit user-request - * Setting this to %TRUE has the same effect as if %NM_UNMANAGED_USER_EXPLICIT - * unmanaged flag would be unset (meaning: explicitly not-unmanaged). - * If this parameter is %TRUE, the device can only appear more managed. - * - * Whether the device is unmanaged according to the unmanaged flags. - * - * Returns: %TRUE if the device is unmanaged because of the flags. - */ -gboolean -nm_device_get_managed(NMDevice *self, gboolean for_user_request) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - if (!nm_device_is_real(self)) { - /* a unrealized device is always considered unmanaged. */ - return FALSE; - } - - priv = NM_DEVICE_GET_PRIVATE(self); - - return _get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, for_user_request); -} - -/** - * nm_device_get_unmanaged_mask: - * @self: the #NMDevice - * @flag: the unmanaged flags to check. - * - * Return the unmanaged flags mask set on this device. - * - * Returns: the flags of the device ( & @flag) - */ -NMUnmanagedFlags -nm_device_get_unmanaged_mask(NMDevice *self, NMUnmanagedFlags flag) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NM_UNMANAGED_NONE); - g_return_val_if_fail(flag != NM_UNMANAGED_NONE, NM_UNMANAGED_NONE); - - return NM_DEVICE_GET_PRIVATE(self)->unmanaged_mask & flag; -} - -/** - * nm_device_get_unmanaged_flags: - * @self: the #NMDevice - * @flag: the unmanaged flags to check. - * - * Return the unmanaged flags of the device. - * - * Returns: the flags of the device ( & @flag) - */ -NMUnmanagedFlags -nm_device_get_unmanaged_flags(NMDevice *self, NMUnmanagedFlags flag) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NM_UNMANAGED_NONE); - g_return_val_if_fail(flag != NM_UNMANAGED_NONE, NM_UNMANAGED_NONE); - - return NM_DEVICE_GET_PRIVATE(self)->unmanaged_flags & flag; -} - -/** - * _set_unmanaged_flags: - * @self: the #NMDevice instance - * @flags: which #NMUnmanagedFlags to set. - * @set_op: whether to set/clear/forget the flags. You can also pass - * boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED - * and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively. - * @allow_state_transition: if %FALSE, setting flags never triggers a device - * state change. If %TRUE, the device can change state, if it is real and - * switches from managed to unmanaged (or vice versa). - * @now: whether the state change should be immediate or delayed - * @reason: the device state reason passed to nm_device_state_changed() if - * the device becomes managed/unmanaged. This is only relevant if the - * device switches state and if @allow_state_transition is %TRUE. - * - * Set the unmanaged flags of the device. - **/ -static void -_set_unmanaged_flags(NMDevice * self, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op, - gboolean allow_state_transition, - gboolean now, - NMDeviceStateReason reason) -{ - NMDevicePrivate *priv; - gboolean was_managed, transition_state; - NMUnmanagedFlags old_flags, old_mask; - NMDeviceState new_state; - const char * operation = NULL; - char str1[512]; - char str2[512]; - gboolean do_notify_has_pending_actions = FALSE; - gboolean had_pending_actions = FALSE; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(flags); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->real) - allow_state_transition = FALSE; - was_managed = allow_state_transition && nm_device_get_managed(self, FALSE); - - if (NM_FLAGS_HAS(priv->unmanaged_flags, NM_UNMANAGED_PLATFORM_INIT) - && NM_FLAGS_HAS(flags, NM_UNMANAGED_PLATFORM_INIT) - && NM_IN_SET(set_op, NM_UNMAN_FLAG_OP_SET_MANAGED)) { - /* we are clearing the platform-init flags. This triggers additional actions. */ - if (!NM_FLAGS_HAS(flags, NM_UNMANAGED_USER_SETTINGS)) { - gboolean unmanaged; - - unmanaged = nm_device_spec_match_list( - self, - nm_settings_get_unmanaged_specs(NM_DEVICE_GET_PRIVATE(self)->settings)); - nm_device_set_unmanaged_flags(self, NM_UNMANAGED_USER_SETTINGS, !!unmanaged); - } - - /* trigger an initial update of IP configuration. */ - nm_assert_se(!nm_clear_g_source(&priv->queued_ip_config_id_4)); - nm_assert_se(!nm_clear_g_source(&priv->queued_ip_config_id_6)); - priv->queued_ip_config_id_4 = g_idle_add(queued_ip4_config_change, self); - priv->queued_ip_config_id_6 = g_idle_add(queued_ip6_config_change, self); - - if (!priv->pending_actions) { - do_notify_has_pending_actions = TRUE; - had_pending_actions = nm_device_has_pending_action(self); - } - } - - old_flags = priv->unmanaged_flags; - old_mask = priv->unmanaged_mask; - - switch (set_op) { - case NM_UNMAN_FLAG_OP_FORGET: - priv->unmanaged_mask &= ~flags; - priv->unmanaged_flags &= ~flags; - operation = "forget"; - break; - case NM_UNMAN_FLAG_OP_SET_UNMANAGED: - priv->unmanaged_mask |= flags; - priv->unmanaged_flags |= flags; - operation = "set-unmanaged"; - break; - case NM_UNMAN_FLAG_OP_SET_MANAGED: - priv->unmanaged_mask |= flags; - priv->unmanaged_flags &= ~flags; - operation = "set-managed"; - break; - default: - g_return_if_reached(); - } - - if (old_flags == priv->unmanaged_flags && old_mask == priv->unmanaged_mask) - return; - - transition_state = - allow_state_transition && was_managed != nm_device_get_managed(self, FALSE) - && (was_managed - || (!was_managed && nm_device_get_state(self) == NM_DEVICE_STATE_UNMANAGED)); - - _LOGD(LOGD_DEVICE, - "unmanaged: flags set to [%s%s0x%0x/0x%x/%s%s], %s [%s=0x%0x]%s%s%s)", - _unmanaged_flags2str(priv->unmanaged_flags, priv->unmanaged_mask, str1, sizeof(str1)), - (priv->unmanaged_flags | priv->unmanaged_mask) ? "=" : "", - (guint) priv->unmanaged_flags, - (guint) priv->unmanaged_mask, - (_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, FALSE) - ? "managed" - : (_get_managed_by_flags(priv->unmanaged_flags, priv->unmanaged_mask, TRUE) - ? "manageable" - : "unmanaged")), - priv->real ? "" : "/unrealized", - operation, - nm_unmanaged_flags2str(flags, str2, sizeof(str2)), - flags, - NM_PRINT_FMT_QUOTED(allow_state_transition, - ", reason ", - reason_to_string_a(reason), - transition_state ? ", transition-state" : "", - "")); - - if (do_notify_has_pending_actions && had_pending_actions != nm_device_has_pending_action(self)) - _notify(self, PROP_HAS_PENDING_ACTION); - - if (transition_state) { - new_state = was_managed ? NM_DEVICE_STATE_UNMANAGED : NM_DEVICE_STATE_UNAVAILABLE; - if (now) - nm_device_state_changed(self, new_state, reason); - else - nm_device_queue_state(self, new_state, reason); - } -} - -/** - * @self: the #NMDevice instance - * @flags: which #NMUnmanagedFlags to set. - * @set_op: whether to set/clear/forget the flags. You can also pass - * boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED - * and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively. - * - * Set the unmanaged flags of the device (does not trigger a state change). - **/ -void -nm_device_set_unmanaged_flags(NMDevice *self, NMUnmanagedFlags flags, NMUnmanFlagOp set_op) -{ - _set_unmanaged_flags(self, flags, set_op, FALSE, FALSE, NM_DEVICE_STATE_REASON_NONE); -} - -/** - * nm_device_set_unmanaged_by_flags: - * @self: the #NMDevice instance - * @flags: which #NMUnmanagedFlags to set. - * @set_op: whether to set/clear/forget the flags. You can also pass - * boolean values %TRUE and %FALSE, which mean %NM_UNMAN_FLAG_OP_SET_UNMANAGED - * and %NM_UNMAN_FLAG_OP_SET_MANAGED, respectively. - * @reason: the device state reason passed to nm_device_state_changed() if - * the device becomes managed/unmanaged. - * - * Set the unmanaged flags of the device and possibly trigger a state change. - **/ -void -nm_device_set_unmanaged_by_flags(NMDevice * self, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op, - NMDeviceStateReason reason) -{ - _set_unmanaged_flags(self, flags, set_op, TRUE, TRUE, reason); -} - -void -nm_device_set_unmanaged_by_flags_queue(NMDevice * self, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op, - NMDeviceStateReason reason) -{ - _set_unmanaged_flags(self, flags, set_op, TRUE, FALSE, reason); -} - -/** - * nm_device_check_unrealized_device_managed: - * - * Checks if a unrealized device is managed from user settings - * or user configuration. - */ -gboolean -nm_device_check_unrealized_device_managed(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert(!nm_device_is_real(self)); - - if (!nm_config_data_get_device_config_boolean(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, - self, - TRUE, - TRUE)) - return FALSE; - - if (nm_device_spec_match_list(self, nm_settings_get_unmanaged_specs(priv->settings))) - return FALSE; - - return TRUE; -} - -void -nm_device_set_unmanaged_by_user_settings(NMDevice *self) -{ - gboolean unmanaged; - - g_return_if_fail(NM_IS_DEVICE(self)); - - if (nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { - /* the device is already unmanaged due to platform-init. - * - * We want to delay evaluating the device spec, because it will freeze - * the permanent MAC address. That should not be done, before the platform - * link is fully initialized (via UDEV). - * - * Note that when clearing NM_UNMANAGED_PLATFORM_INIT, we will re-evaluate - * whether the device is unmanaged by user-settings. */ - return; - } - - unmanaged = nm_device_spec_match_list( - self, - nm_settings_get_unmanaged_specs(NM_DEVICE_GET_PRIVATE(self)->settings)); - - nm_device_set_unmanaged_by_flags(self, - NM_UNMANAGED_USER_SETTINGS, - !!unmanaged, - unmanaged ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED - : NM_DEVICE_STATE_REASON_NOW_MANAGED); -} - -void -nm_device_set_unmanaged_by_user_udev(NMDevice *self) -{ - int ifindex; - gboolean platform_unmanaged = FALSE; - - ifindex = self->_priv->ifindex; - - if (ifindex <= 0 - || !nm_platform_link_get_unmanaged(nm_device_get_platform(self), - ifindex, - &platform_unmanaged)) - return; - - nm_device_set_unmanaged_by_flags(self, - NM_UNMANAGED_USER_UDEV, - platform_unmanaged, - NM_DEVICE_STATE_REASON_USER_REQUESTED); -} - -void -nm_device_set_unmanaged_by_user_conf(NMDevice *self) -{ - gboolean value; - NMUnmanFlagOp set_op; - - value = nm_config_data_get_device_config_boolean(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED, - self, - -1, - TRUE); - switch (value) { - case TRUE: - set_op = NM_UNMAN_FLAG_OP_SET_MANAGED; - break; - case FALSE: - set_op = NM_UNMAN_FLAG_OP_SET_UNMANAGED; - break; - default: - set_op = NM_UNMAN_FLAG_OP_FORGET; - break; - } - - nm_device_set_unmanaged_by_flags(self, - NM_UNMANAGED_USER_CONF, - set_op, - NM_DEVICE_STATE_REASON_USER_REQUESTED); -} - -void -nm_device_set_unmanaged_by_quitting(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - gboolean need_deactivate = - nm_device_is_activating(self) || priv->state == NM_DEVICE_STATE_ACTIVATED; - - /* It's OK to block here because we're quitting */ - if (need_deactivate) - _set_state_full(self, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_NOW_UNMANAGED, - TRUE); - - nm_device_set_unmanaged_by_flags(self, - NM_UNMANAGED_QUITTING, - TRUE, - need_deactivate ? NM_DEVICE_STATE_REASON_REMOVED - : NM_DEVICE_STATE_REASON_NOW_UNMANAGED); -} - -/*****************************************************************************/ - -void -nm_device_set_dhcp_anycast_address(NMDevice *self, const char *addr) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(!addr || nm_utils_hwaddr_valid(addr, ETH_ALEN)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - g_free(priv->dhcp_anycast_address); - priv->dhcp_anycast_address = g_strdup(addr); -} - -void -nm_device_reapply_settings_immediately(NMDevice *self) -{ - NMConnection * applied_connection; - NMSettingsConnection *settings_connection; - NMDeviceState state; - NMSettingConnection * s_con_settings; - NMSettingConnection * s_con_applied; - const char * zone; - NMMetered metered; - guint64 version_id; - - g_return_if_fail(NM_IS_DEVICE(self)); - - state = nm_device_get_state(self); - if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_ACTIVATED) - return; - - applied_connection = nm_device_get_applied_connection(self); - settings_connection = nm_device_get_settings_connection(self); - - if (!nm_settings_connection_has_unmodified_applied_connection( - settings_connection, - applied_connection, - NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)) - return; - - s_con_settings = nm_connection_get_setting_connection( - nm_settings_connection_get_connection(settings_connection)); - s_con_applied = nm_connection_get_setting_connection(applied_connection); - - if (!nm_streq0((zone = nm_setting_connection_get_zone(s_con_settings)), - nm_setting_connection_get_zone(s_con_applied))) { - version_id = nm_active_connection_version_id_bump( - (NMActiveConnection *) self->_priv->act_request.obj); - _LOGD(LOGD_DEVICE, - "reapply setting: zone = %s%s%s (version-id %llu)", - NM_PRINT_FMT_QUOTE_STRING(zone), - (unsigned long long) version_id); - - g_object_set(G_OBJECT(s_con_applied), NM_SETTING_CONNECTION_ZONE, zone, NULL); - - nm_device_update_firewall_zone(self); - } - - if ((metered = nm_setting_connection_get_metered(s_con_settings)) - != nm_setting_connection_get_metered(s_con_applied)) { - version_id = nm_active_connection_version_id_bump( - (NMActiveConnection *) self->_priv->act_request.obj); - _LOGD(LOGD_DEVICE, - "reapply setting: metered = %d (version-id %llu)", - (int) metered, - (unsigned long long) version_id); - - g_object_set(G_OBJECT(s_con_applied), NM_SETTING_CONNECTION_METERED, metered, NULL); - - nm_device_update_metered(self); - } -} - -void -nm_device_update_firewall_zone(NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->fw_state >= FIREWALL_STATE_INITIALIZED - && !nm_device_sys_iface_state_is_external(self)) - fw_change_zone(self); -} - -void -nm_device_update_metered(NMDevice *self) -{ -#define NM_METERED_INVALID ((NMMetered) -1) - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingConnection *setting; - NMMetered conn_value, value = NM_METERED_INVALID; - NMConnection * connection = NULL; - NMDeviceState state; - - g_return_if_fail(NM_IS_DEVICE(self)); - - state = nm_device_get_state(self); - if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_ACTIVATED) - value = NM_METERED_UNKNOWN; - - if (value == NM_METERED_INVALID) { - connection = nm_device_get_applied_connection(self); - if (connection) { - setting = nm_connection_get_setting_connection(connection); - if (setting) { - conn_value = nm_setting_connection_get_metered(setting); - if (conn_value != NM_METERED_UNKNOWN) - value = conn_value; - } - } - } - - if (value == NM_METERED_INVALID && NM_DEVICE_GET_CLASS(self)->get_guessed_metered - && NM_DEVICE_GET_CLASS(self)->get_guessed_metered(self)) - value = NM_METERED_GUESS_YES; - - /* Try to guess a value using the metered flag in IP configuration */ - if (value == NM_METERED_INVALID) { - if (priv->ip_config_4 && priv->ip_state_4 == NM_DEVICE_IP_STATE_DONE - && nm_ip4_config_get_metered(priv->ip_config_4)) - value = NM_METERED_GUESS_YES; - } - - /* Otherwise, look at connection type. For Bluetooth, we look at the type of - * Bluetooth sharing: for PANU/DUN (where we are receiving internet from - * another device) we set GUESS_YES; for NAP (where we are sharing internet - * to another device) we set GUESS_NO. We ignore WiMAX here as it’s no - * longer supported by NetworkManager. */ - if (value == NM_METERED_INVALID - && nm_connection_is_type(connection, NM_SETTING_BLUETOOTH_SETTING_NAME)) { - if (_nm_connection_get_setting_bluetooth_for_nap(connection)) { - /* NAP types are not metered, but other types are. */ - value = NM_METERED_GUESS_NO; - } else - value = NM_METERED_GUESS_YES; - } - - if (value == NM_METERED_INVALID) { - if (nm_connection_is_type(connection, NM_SETTING_GSM_SETTING_NAME) - || nm_connection_is_type(connection, NM_SETTING_CDMA_SETTING_NAME)) - value = NM_METERED_GUESS_YES; - else - value = NM_METERED_GUESS_NO; - } - - if (value != priv->metered) { - _LOGD(LOGD_DEVICE, "set metered value %d", value); - priv->metered = value; - _notify(self, PROP_METERED); - } -} - -static NMDeviceCheckDevAvailableFlags -_device_check_dev_available_flags_from_con(NMDeviceCheckConAvailableFlags con_flags) -{ - NMDeviceCheckDevAvailableFlags dev_flags; - - dev_flags = NM_DEVICE_CHECK_DEV_AVAILABLE_NONE; - - if (NM_FLAGS_HAS(con_flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)) - dev_flags |= _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER; - - return dev_flags; -} - -static gboolean -_nm_device_check_connection_available(NMDevice * self, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDeviceState state; - GError * local = NULL; - - /* an unrealized software device is always available, hardware devices never. */ - if (!nm_device_is_real(self)) { - if (nm_device_is_software(self)) { - if (!nm_device_check_connection_compatible(self, connection, error ? &local : NULL)) { - if (error) { - g_return_val_if_fail(local, FALSE); - nm_utils_error_set(error, - local->domain == NM_UTILS_ERROR ? local->code - : NM_UTILS_ERROR_UNKNOWN, - "profile is not compatible with software device (%s)", - local->message); - g_error_free(local); - } - return FALSE; - } - return TRUE; - } - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "hardware device is not realized"); - return FALSE; - } - - state = nm_device_get_state(self); - if (state < NM_DEVICE_STATE_UNMANAGED) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "device is in unknown state"); - return FALSE; - } - if (state < NM_DEVICE_STATE_UNAVAILABLE) { - if (nm_device_get_managed(self, FALSE)) { - /* device is managed, both for user-requests and non-user-requests alike. */ - } else { - if (!nm_device_get_managed(self, TRUE)) { - /* device is strictly unmanaged by authoritative unmanaged reasons. */ - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "device is strictly unmanaged"); - return FALSE; - } - if (!NM_FLAGS_HAS(flags, - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED)) { - /* device could be managed for an explict user-request, but this is not such a request. */ - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_UNMANAGED_DEVICE, - "device is currently unmanaged"); - return FALSE; - } - } - } - if (state < NM_DEVICE_STATE_DISCONNECTED && !nm_device_is_software(self)) { - if (!nm_device_is_available(self, _device_check_dev_available_flags_from_con(flags))) { - if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device is not available"); - } else { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device is not available for internal request"); - } - return FALSE; - } - } - - if (!nm_device_check_connection_compatible(self, connection, error ? &local : NULL)) { - if (error) { - nm_utils_error_set(error, - local->domain == NM_UTILS_ERROR ? local->code - : NM_UTILS_ERROR_UNKNOWN, - "profile is not compatible with device (%s)", - local->message); - g_error_free(local); - } - return FALSE; - } - - return NM_DEVICE_GET_CLASS(self)->check_connection_available(self, - connection, - flags, - specific_object, - error); -} - -/** - * nm_device_check_connection_available(): - * @self: the #NMDevice - * @connection: the #NMConnection to check for availability - * @flags: flags to affect the decision making of whether a connection - * is available. Adding a flag can only make a connection more available, - * not less. - * @specific_object: a device type dependent argument to further - * filter the result. Passing a non %NULL specific object can only reduce - * the availability of a connection. - * @error: optionally give reason why not available. - * - * Check if @connection is available to be activated on @self. - * - * Returns: %TRUE if @connection can be activated on @self - */ -gboolean -nm_device_check_connection_available(NMDevice * self, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - gboolean available; - - available = - _nm_device_check_connection_available(self, connection, flags, specific_object, error); - -#if NM_MORE_ASSERTS >= 2 - { - /* The meaning of the flags is so that *adding* a flag relaxes a condition, thus making - * the device *more* available. Assert against that requirement by testing all the flags. */ - NMDeviceCheckConAvailableFlags i, j, k; - gboolean available_all[NM_DEVICE_CHECK_CON_AVAILABLE_ALL + 1] = {FALSE}; - - for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) - available_all[i] = - _nm_device_check_connection_available(self, connection, i, specific_object, NULL); - - for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) { - for (j = 1; j <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; j <<= 1) { - if (NM_FLAGS_ANY(i, j)) { - k = i & ~j; - nm_assert(available_all[i] == available_all[k] || available_all[i]); - } - } - } - } -#endif - - return available; -} - -static gboolean -available_connections_del_all(NMDevice *self) -{ - if (g_hash_table_size(self->_priv->available_connections) == 0) - return FALSE; - g_hash_table_remove_all(self->_priv->available_connections); - return TRUE; -} - -static gboolean -available_connections_add(NMDevice *self, NMSettingsConnection *sett_conn) -{ - return g_hash_table_add(self->_priv->available_connections, g_object_ref(sett_conn)); -} - -static gboolean -available_connections_del(NMDevice *self, NMSettingsConnection *sett_conn) -{ - return g_hash_table_remove(self->_priv->available_connections, sett_conn); -} - -static gboolean -check_connection_available(NMDevice * self, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - /* Connections which require a network connection are not available when - * the device has no carrier, even with ignore-carrer=TRUE. - */ - if (priv->carrier || !connection_requires_carrier(connection)) - return TRUE; - - if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) - && priv->carrier_wait_id != 0) { - /* The device has no carrier though the connection requires it. - * - * If we are still waiting for carrier, the connection is available - * for an explicit user-request. */ - return TRUE; - } - - /* master types are always available even without carrier. - * Making connection non-available would un-enslave slaves which - * is not desired. */ - if (nm_device_is_master(self)) - return TRUE; - - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has no carrier"); - return FALSE; -} - -void -nm_device_recheck_available_connections(NMDevice *self) -{ - NMDevicePrivate * priv; - NMSettingsConnection *const *connections; - gboolean changed = FALSE; - GHashTableIter h_iter; - NMSettingsConnection * sett_conn; - guint i; - gs_unref_hashtable GHashTable *prune_list = NULL; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (g_hash_table_size(priv->available_connections) > 0) { - prune_list = g_hash_table_new(nm_direct_hash, NULL); - g_hash_table_iter_init(&h_iter, priv->available_connections); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &sett_conn, NULL)) - g_hash_table_add(prune_list, sett_conn); - } - - connections = nm_settings_get_connections(priv->settings, NULL); - for (i = 0; connections[i]; i++) { - sett_conn = connections[i]; - - if (nm_device_check_connection_available(self, - nm_settings_connection_get_connection(sett_conn), - NM_DEVICE_CHECK_CON_AVAILABLE_NONE, - NULL, - NULL)) { - if (available_connections_add(self, sett_conn)) - changed = TRUE; - if (prune_list) - g_hash_table_remove(prune_list, sett_conn); - } - } - - if (prune_list) { - g_hash_table_iter_init(&h_iter, prune_list); - while (g_hash_table_iter_next(&h_iter, (gpointer *) &sett_conn, NULL)) { - if (available_connections_del(self, sett_conn)) - changed = TRUE; - } - } - - if (changed) - _notify(self, PROP_AVAILABLE_CONNECTIONS); - available_connections_check_delete_unrealized(self); -} - -/** - * nm_device_get_best_connection: - * @self: the #NMDevice - * @specific_object: a specific object path if any - * @error: reason why no connection was returned - * - * Returns a connection that's most suitable for user-initiated activation - * of a device, optionally with a given specific object. - * - * Returns: the #NMSettingsConnection or %NULL (setting an @error) - */ -NMSettingsConnection * -nm_device_get_best_connection(NMDevice *self, const char *specific_object, GError **error) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMSettingsConnection *sett_conn = NULL; - NMSettingsConnection *candidate; - guint64 best_timestamp = 0; - GHashTableIter iter; - - g_hash_table_iter_init(&iter, priv->available_connections); - while (g_hash_table_iter_next(&iter, (gpointer) &candidate, NULL)) { - guint64 candidate_timestamp = 0; - - /* If a specific object is given, only include connections that are - * compatible with it. - */ - if (specific_object /* << Optimization: we know that the connection is available without @specific_object. */ - && !nm_device_check_connection_available( - self, - nm_settings_connection_get_connection(candidate), - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, - specific_object, - NULL)) - continue; - - nm_settings_connection_get_timestamp(candidate, &candidate_timestamp); - if (!sett_conn || (candidate_timestamp > best_timestamp)) { - sett_conn = candidate; - best_timestamp = candidate_timestamp; - } - } - - if (!sett_conn) { - g_set_error(error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_CONNECTION, - "The device '%s' has no connections available for activation.", - nm_device_get_iface(self)); - } - - return sett_conn; -} - -static void -cp_connection_added_or_updated(NMDevice *self, NMSettingsConnection *sett_conn) -{ - gboolean changed; - - g_return_if_fail(NM_IS_DEVICE(self)); - g_return_if_fail(NM_IS_SETTINGS_CONNECTION(sett_conn)); - - if (nm_device_check_connection_available(self, - nm_settings_connection_get_connection(sett_conn), - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, - NULL, - NULL)) - changed = available_connections_add(self, sett_conn); - else - changed = available_connections_del(self, sett_conn); - - if (changed) { - _notify(self, PROP_AVAILABLE_CONNECTIONS); - available_connections_check_delete_unrealized(self); - } -} - -static void -cp_connection_added(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) -{ - cp_connection_added_or_updated(user_data, sett_conn); -} - -static void -cp_connection_updated(NMSettings * settings, - NMSettingsConnection *sett_conn, - guint update_reason_u, - gpointer user_data) -{ - cp_connection_added_or_updated(user_data, sett_conn); -} - -static void -cp_connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) -{ - NMDevice *self = user_data; - - g_return_if_fail(NM_IS_DEVICE(self)); - - if (available_connections_del(self, sett_conn)) { - _notify(self, PROP_AVAILABLE_CONNECTIONS); - available_connections_check_delete_unrealized(self); - } -} - -gboolean -nm_device_supports_vlans(NMDevice *self) -{ - return nm_platform_link_supports_vlans(nm_device_get_platform(self), - nm_device_get_ifindex(self)); -} - -/** - * nm_device_add_pending_action(): - * @self: the #NMDevice to add the pending action to - * @action: a static string that identifies the action. The string instance must - * stay valid until the pending action is removed (that is, the string is - * not cloned, but ownership stays with the caller). - * @assert_not_yet_pending: if %TRUE, assert that the @action is currently not yet pending. - * Otherwise, ignore duplicate scheduling of the same action silently. - * - * Adds a pending action to the device. - * - * Returns: %TRUE if the action was added (and not already added before). %FALSE - * if the same action is already scheduled. In the latter case, the action was not scheduled - * a second time. - */ -gboolean -nm_device_add_pending_action(NMDevice *self, const char *action, gboolean assert_not_yet_pending) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - GSList * iter; - guint count = 0; - - g_return_val_if_fail(action, FALSE); - - /* Check if the action is already pending. Cannot add duplicate actions */ - for (iter = priv->pending_actions; iter; iter = iter->next) { - if (nm_streq(action, iter->data)) { - if (assert_not_yet_pending) { - _LOGW(LOGD_DEVICE, - "add_pending_action (%d): '%s' already pending", - count + g_slist_length(iter), - action); - g_return_val_if_reached(FALSE); - } else { - _LOGT(LOGD_DEVICE, - "add_pending_action (%d): '%s' already pending (expected)", - count + g_slist_length(iter), - action); - } - return FALSE; - } - count++; - } - - priv->pending_actions = g_slist_prepend(priv->pending_actions, (char *) action); - count++; - - _LOGD(LOGD_DEVICE, "add_pending_action (%d): '%s'", count, action); - - if (count == 1) - _notify(self, PROP_HAS_PENDING_ACTION); - - return TRUE; -} - -/** - * nm_device_remove_pending_action(): - * @self: the #NMDevice to remove the pending action from - * @action: a string that identifies the action. - * @assert_is_pending: if %TRUE, assert that the @action is pending. - * If %FALSE, don't do anything if the current action is not pending and - * return %FALSE. - * - * Removes a pending action previously added by nm_device_add_pending_action(). - * - * Returns: whether the @action was pending and is now removed. - */ -gboolean -nm_device_remove_pending_action(NMDevice *self, const char *action, gboolean assert_is_pending) -{ - NMDevicePrivate *priv; - GSList * iter, *next; - guint count = 0; - - g_return_val_if_fail(self, FALSE); - g_return_val_if_fail(action, FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - for (iter = priv->pending_actions; iter; iter = next) { - next = iter->next; - if (nm_streq(action, iter->data)) { - _LOGD(LOGD_DEVICE, - "remove_pending_action (%d): '%s'", - count + g_slist_length(iter->next), /* length excluding 'iter' */ - action); - priv->pending_actions = g_slist_delete_link(priv->pending_actions, iter); - if (priv->pending_actions == NULL) - _notify(self, PROP_HAS_PENDING_ACTION); - return TRUE; - } - count++; - } - - if (assert_is_pending) { - _LOGW(LOGD_DEVICE, "remove_pending_action (%d): '%s' not pending", count, action); - g_return_val_if_reached(FALSE); - } else - _LOGT(LOGD_DEVICE, - "remove_pending_action (%d): '%s' not pending (expected)", - count, - action); - - return FALSE; -} - -const char * -nm_device_has_pending_action_reason(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->pending_actions) { - if (!priv->pending_actions->next && nm_device_get_state(self) == NM_DEVICE_STATE_ACTIVATED - && nm_streq(priv->pending_actions->data, NM_PENDING_ACTION_CARRIER_WAIT)) { - /* if the device is already in activated state, and the only reason - * why it appears still busy is "carrier-wait", then we are already complete. */ - return NULL; - } - - return priv->pending_actions->data; - } - - if (nm_device_is_real(self) - && nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT)) { - /* as long as the platform link is not yet initialized, we have a pending - * action. */ - return NM_PENDING_ACTION_LINK_INIT; - } - - return NULL; -} - -/*****************************************************************************/ - -static void -_cancel_activation(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->fw_call) { - nm_firewall_manager_cancel_call(priv->fw_call); - nm_assert(!priv->fw_call); - priv->fw_call = NULL; - priv->fw_state = FIREWALL_STATE_INITIALIZED; - } - - ip_check_gw_ping_cleanup(self); - - /* Break the activation chain */ - activation_source_clear(self, AF_INET); - activation_source_clear(self, AF_INET6); -} - -static void -_cleanup_generic_pre(NMDevice *self, CleanupType cleanup_type) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - _cancel_activation(self); - - priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_INIT; - - if (cleanup_type != CLEANUP_TYPE_KEEP) { - nm_manager_device_route_metric_clear(NM_MANAGER_GET, nm_device_get_ip_ifindex(self)); - } - - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE && priv->fw_state >= FIREWALL_STATE_INITIALIZED - && priv->fw_mgr && !nm_device_sys_iface_state_is_external(self)) { - nm_firewall_manager_remove_from_zone(priv->fw_mgr, - nm_device_get_ip_iface(self), - NULL, - NULL, - NULL); - } - priv->fw_state = FIREWALL_STATE_UNMANAGED; - g_clear_object(&priv->fw_mgr); - - queued_state_clear(self); - - nm_clear_pointer(&priv->shared_ip_handle, nm_netns_shared_ip_release); - - _cleanup_ip_pre(self, AF_INET, cleanup_type); - _cleanup_ip_pre(self, AF_INET6, cleanup_type); -} - -static void -_cleanup_generic_post(NMDevice *self, CleanupType cleanup_type) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - priv->v4_commit_first_time = TRUE; - priv->v6_commit_first_time = TRUE; - - priv->v4_route_table_initialized = FALSE; - priv->v6_route_table_initialized = FALSE; - - priv->v4_route_table_all_sync_before = FALSE; - priv->v6_route_table_all_sync_before = FALSE; - - priv->default_route_metric_penalty_ip4_has = FALSE; - priv->default_route_metric_penalty_ip6_has = FALSE; - - priv->linklocal6_dad_counter = 0; - - priv->mtu_force_set_done = FALSE; - - /* Clean up IP configs; this does not actually deconfigure the - * interface; the caller must flush routes and addresses explicitly. - */ - nm_device_set_ip_config(self, AF_INET, NULL, TRUE, NULL); - nm_device_set_ip_config(self, AF_INET6, NULL, TRUE, NULL); - g_clear_object(&priv->proxy_config); - g_clear_object(&priv->con_ip_config_4); - applied_config_clear(&priv->dev_ip_config_4); - applied_config_clear(&priv->dev2_ip_config_4); - g_clear_object(&priv->ext_ip_config_4); - g_clear_object(&priv->ip_config_4); - g_clear_object(&priv->con_ip_config_6); - applied_config_clear(&priv->ac_ip6_config); - g_clear_object(&priv->ext_ip_config_6); - g_clear_object(&priv->ext_ip6_config_captured); - applied_config_clear(&priv->dev2_ip_config_6); - g_clear_object(&priv->ip_config_6); - g_clear_object(&priv->dad6_ip6_config); - priv->ipv6ll_has = FALSE; - memset(&priv->ipv6ll_addr, 0, sizeof(priv->ipv6ll_addr)); - - nm_clear_pointer(&priv->rt6_temporary_not_available, g_hash_table_unref); - nm_clear_g_source(&priv->rt6_temporary_not_available_id); - - g_slist_free_full(priv->vpn_configs_4, g_object_unref); - priv->vpn_configs_4 = NULL; - g_slist_free_full(priv->vpn_configs_6, g_object_unref); - priv->vpn_configs_6 = NULL; - - /* We no longer accept the delegations. nm_device_set_ip_config(NULL) - * above disables them. */ - nm_assert(priv->needs_ip6_subnet == FALSE); - - if (priv->act_request.obj) { - nm_active_connection_set_default(NM_ACTIVE_CONNECTION(priv->act_request.obj), - AF_INET, - FALSE); - nm_clear_g_signal_handler(priv->act_request.obj, &priv->master_ready_id); - act_request_set(self, NULL); - } - - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { - /* Check if the device was deactivated, and if so, delete_link. - * Don't call delete_link synchronously because we are currently - * handling a state change -- which is not reentrant. */ - delete_on_deactivate_check_and_schedule(self, nm_device_get_ip_ifindex(self)); - } - - /* ip_iface should be cleared after flushing all routes and addresses, since - * those are identified by ip_iface, not by iface (which might be a tty - * or ATM device). - */ - _set_ip_ifindex(self, 0, NULL); -} - -/* - * nm_device_cleanup - * - * Remove a device's routing table entries and IP addresses. - * - */ -static void -nm_device_cleanup(NMDevice *self, NMDeviceStateReason reason, CleanupType cleanup_type) -{ - NMDevicePrivate *priv; - int ifindex; - - g_return_if_fail(NM_IS_DEVICE(self)); - - if (reason == NM_DEVICE_STATE_REASON_NOW_MANAGED) - _LOGD(LOGD_DEVICE, "preparing device"); - else - _LOGD(LOGD_DEVICE, - "deactivating device (reason '%s') [%d]", - reason_to_string_a(reason), - reason); - - /* Save whether or not we tried IPv6 for later */ - priv = NM_DEVICE_GET_PRIVATE(self); - - _cleanup_generic_pre(self, cleanup_type); - - /* Turn off kernel IPv6 */ - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { - set_disable_ipv6(self, "1"); - nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", "0"); - } - - /* Call device type-specific deactivation */ - if (NM_DEVICE_GET_CLASS(self)->deactivate) - NM_DEVICE_GET_CLASS(self)->deactivate(self); - - ifindex = nm_device_get_ip_ifindex(self); - - if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) { - /* master: release slaves */ - nm_device_master_release_slaves(self); - - /* Take out any entries in the routing table and any IP address the device had. */ - if (ifindex > 0) { - NMPlatform * platform = nm_device_get_platform(self); - NMUtilsIPv6IfaceId iid = {}; - - nm_platform_ip_route_flush(platform, AF_UNSPEC, ifindex); - nm_platform_ip_address_flush(platform, AF_UNSPEC, ifindex); - nm_platform_tfilter_sync(platform, ifindex, NULL); - nm_platform_qdisc_sync(platform, ifindex, NULL); - set_ipv6_token(self, iid, "::"); - } - } - - _routing_rules_sync(self, - cleanup_type == CLEANUP_TYPE_KEEP ? NM_TERNARY_DEFAULT : NM_TERNARY_FALSE); - - if (ifindex > 0) - nm_platform_ip4_dev_route_blacklist_set(nm_device_get_platform(self), ifindex, NULL); - - /* slave: mark no longer enslaved */ - if (priv->master && priv->ifindex > 0 - && nm_platform_link_get_master(nm_device_get_platform(self), priv->ifindex) <= 0) - nm_device_master_release_one_slave(priv->master, - self, - FALSE, - FALSE, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); - - if (priv->lldp_listener) - nm_lldp_listener_stop(priv->lldp_listener); - - nm_device_update_metered(self); - - if (ifindex > 0) { - /* during device cleanup, we want to reset the MAC address of the device - * to the initial state. - * - * We certainly want to do that when reaching the UNMANAGED state... */ - if (nm_device_get_state(self) <= NM_DEVICE_STATE_UNMANAGED) - nm_device_hw_addr_reset(self, "unmanage"); - else { - /* for other device states (UNAVAILABLE, DISCONNECTED), allow the - * device to overwrite the reset behavior, so that Wi-Fi can set - * a randomized MAC address used during scanning. */ - NM_DEVICE_GET_CLASS(self)->deactivate_reset_hw_addr(self); - } - } - - priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE; - priv->ip6_mtu = 0; - if (priv->mtu_initial || priv->ip6_mtu_initial) { - ifindex = nm_device_get_ip_ifindex(self); - - if (ifindex > 0 && cleanup_type == CLEANUP_TYPE_DECONFIGURE) { - _LOGT(LOGD_DEVICE, - "mtu: reset device-mtu: %u, ipv6-mtu: %u, ifindex: %d", - (guint) priv->mtu_initial, - (guint) priv->ip6_mtu_initial, - ifindex); - if (priv->mtu_initial) { - nm_platform_link_set_mtu(nm_device_get_platform(self), ifindex, priv->mtu_initial); - priv->carrier_wait_until_ms = - nm_utils_get_monotonic_timestamp_msec() + CARRIER_WAIT_TIME_AFTER_MTU_MS; - } - if (priv->ip6_mtu_initial) { - char sbuf[64]; - - nm_device_sysctl_ip_conf_set( - self, - AF_INET6, - "mtu", - nm_sprintf_buf(sbuf, "%u", (unsigned) priv->ip6_mtu_initial)); - } - } - priv->mtu_initial = 0; - priv->ip6_mtu_initial = 0; - } - - _ethtool_state_reset(self); - - _cleanup_generic_post(self, cleanup_type); -} - -static void -deactivate_reset_hw_addr(NMDevice *self) -{ - nm_device_hw_addr_reset(self, "deactivate"); -} - -static char * -find_dhcp4_address(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - const NMPlatformIP4Address *a; - NMDedupMultiIter ipconf_iter; - - if (!priv->ip_config_4) - return NULL; - - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, priv->ip_config_4, &a) { - if (a->addr_source == NM_IP_CONFIG_SOURCE_DHCP) - return nm_utils_inet4_ntop_dup(a->address); - } - return NULL; -} - -void -nm_device_spawn_iface_helper(NMDevice *self) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - gboolean configured = FALSE; - NMConnection * connection; - GError * error = NULL; - const char * method; - GPtrArray * argv; - gs_free char * dhcp4_address = NULL; - char * logging_backend; - NMUtilsStableType stable_type; - const char * stable_id; - - if (priv->state != NM_DEVICE_STATE_ACTIVATED) - return; - if (!nm_device_can_assume_connections(self)) - return; - - connection = nm_device_get_applied_connection(self); - - g_return_if_fail(connection); - - argv = g_ptr_array_sized_new(10); - g_ptr_array_set_free_func(argv, g_free); - - g_ptr_array_add(argv, g_strdup(LIBEXECDIR "/nm-iface-helper")); - g_ptr_array_add(argv, g_strdup("--ifname")); - g_ptr_array_add(argv, g_strdup(nm_device_get_ip_iface(self))); - g_ptr_array_add(argv, g_strdup("--uuid")); - g_ptr_array_add(argv, g_strdup(nm_connection_get_uuid(connection))); - - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); - if (stable_type != NM_UTILS_STABLE_TYPE_UUID) { - g_ptr_array_add(argv, g_strdup("--stable-id")); - g_ptr_array_add(argv, g_strdup_printf("%d %s", (int) stable_type, stable_id)); - } - - logging_backend = - nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG, - NM_CONFIG_KEYFILE_GROUP_LOGGING, - NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND, - NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); - if (logging_backend) { - g_ptr_array_add(argv, g_strdup("--logging-backend")); - g_ptr_array_add(argv, logging_backend); - } - - g_ptr_array_add(argv, g_strdup("--log-level")); - g_ptr_array_add(argv, g_strdup(nm_logging_level_to_string())); - - g_ptr_array_add(argv, g_strdup("--log-domains")); - g_ptr_array_add(argv, g_strdup(nm_logging_domains_to_string())); - - dhcp4_address = find_dhcp4_address(self); - - method = nm_device_get_effective_ip_config_method(self, AF_INET); - if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - NMSettingIPConfig *s_ip4; - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - nm_assert(s_ip4); - - g_ptr_array_add(argv, g_strdup("--priority4")); - g_ptr_array_add(argv, g_strdup_printf("%u", nm_device_get_route_metric(self, AF_INET))); - - g_ptr_array_add(argv, g_strdup("--dhcp4")); - g_ptr_array_add(argv, g_strdup(dhcp4_address)); - if (nm_setting_ip_config_get_may_fail(s_ip4) == FALSE) - g_ptr_array_add(argv, g_strdup("--dhcp4-required")); - - if (priv->dhcp_data_4.client) { - const char *hostname; - GBytes * client_id; - - client_id = nm_dhcp_client_get_client_id(priv->dhcp_data_4.client); - if (client_id) { - g_ptr_array_add(argv, g_strdup("--dhcp4-clientid")); - g_ptr_array_add(argv, - nm_utils_bin2hexstr_full(g_bytes_get_data(client_id, NULL), - g_bytes_get_size(client_id), - ':', - FALSE, - NULL)); - } - - hostname = nm_dhcp_client_get_hostname(priv->dhcp_data_4.client); - if (hostname) { - if (nm_dhcp_client_get_use_fqdn(priv->dhcp_data_4.client)) - g_ptr_array_add(argv, g_strdup("--dhcp4-fqdn")); - else - g_ptr_array_add(argv, g_strdup("--dhcp4-hostname")); - g_ptr_array_add(argv, g_strdup(hostname)); - } - } - - configured = TRUE; - } - - method = nm_utils_get_ip_config_method(connection, AF_INET6); - if (nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - NMSettingIPConfig *s_ip6; - NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - g_assert(s_ip6); - - g_ptr_array_add(argv, g_strdup("--priority6")); - g_ptr_array_add(argv, g_strdup_printf("%u", nm_device_get_route_metric(self, AF_INET6))); - - g_ptr_array_add(argv, g_strdup("--slaac")); - - if (nm_setting_ip_config_get_may_fail(s_ip6) == FALSE) - g_ptr_array_add(argv, g_strdup("--slaac-required")); - - g_ptr_array_add(argv, g_strdup("--slaac-tempaddr")); - g_ptr_array_add(argv, g_strdup_printf("%d", priv->ndisc_use_tempaddr)); - - if (nm_device_get_ip_iface_identifier(self, &iid, FALSE)) { - g_ptr_array_add(argv, g_strdup("--iid")); - g_ptr_array_add( - argv, - nm_utils_bin2hexstr_full(iid.id_u8, sizeof(NMUtilsIPv6IfaceId), ':', FALSE, NULL)); - } - - g_ptr_array_add(argv, g_strdup("--addr-gen-mode")); - g_ptr_array_add( - argv, - g_strdup_printf("%d", - nm_setting_ip6_config_get_addr_gen_mode(NM_SETTING_IP6_CONFIG(s_ip6)))); - - configured = TRUE; - } - - if (configured) { - GPid pid; - - g_ptr_array_add(argv, NULL); - - if (nm_logging_enabled(LOGL_DEBUG, LOGD_DEVICE)) { - char *tmp; - - tmp = g_strjoinv(" ", (char **) argv->pdata); - _LOGD(LOGD_DEVICE, "running '%s'", tmp); - g_free(tmp); - } - - if (g_spawn_async(NULL, - (char **) argv->pdata, - NULL, - G_SPAWN_DO_NOT_REAP_CHILD, - NULL, - NULL, - &pid, - &error)) { - _LOGI(LOGD_DEVICE, "spawned helper PID %u", (guint) pid); - } else { - _LOGW(LOGD_DEVICE, "failed to spawn helper: %s", error->message); - g_error_free(error); - } - } - - g_ptr_array_unref(argv); -} - -/*****************************************************************************/ - -static gboolean -ip_config_valid(NMDeviceState state) -{ - return (state == NM_DEVICE_STATE_UNMANAGED) - || (state >= NM_DEVICE_STATE_IP_CHECK && state <= NM_DEVICE_STATE_DEACTIVATING); -} - -static void -notify_ip_properties(NMDevice *self) -{ - _notify(self, PROP_IP_IFACE); - _notify(self, PROP_IP4_CONFIG); - _notify(self, PROP_DHCP4_CONFIG); - _notify(self, PROP_IP6_CONFIG); - _notify(self, PROP_DHCP6_CONFIG); -} - -static void -ip6_managed_setup(NMDevice *self) -{ - set_nm_ipv6ll(self, TRUE); - set_disable_ipv6(self, "1"); - nm_device_sysctl_ip_conf_set(self, AF_INET6, "accept_ra", "0"); - nm_device_sysctl_ip_conf_set(self, AF_INET6, "use_tempaddr", "0"); - nm_device_sysctl_ip_conf_set(self, AF_INET6, "forwarding", "0"); -} - -static void -deactivate_ready(NMDevice *self, NMDeviceStateReason reason) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->dispatcher.call_id) - return; - - if (priv->sriov_reset_pending > 0) - return; - - if (priv->state == NM_DEVICE_STATE_DEACTIVATING) - nm_device_queue_state(self, NM_DEVICE_STATE_DISCONNECTED, reason); -} - -static void -sriov_reset_on_deactivate_cb(GError *error, gpointer user_data) -{ - NMDevice * self; - NMDevicePrivate *priv; - gpointer reason; - - nm_utils_user_data_unpack(user_data, &self, &reason); - priv = NM_DEVICE_GET_PRIVATE(self); - nm_assert(priv->sriov_reset_pending > 0); - priv->sriov_reset_pending--; - - if (nm_utils_error_is_cancelled(error)) - return; - - deactivate_ready(self, GPOINTER_TO_INT(reason)); -} - -static void -sriov_reset_on_failure_cb(GError *error, gpointer user_data) -{ - NMDevice * self = user_data; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert(priv->sriov_reset_pending > 0); - priv->sriov_reset_pending--; - - if (nm_utils_error_is_cancelled(error)) - return; - - if (priv->state == NM_DEVICE_STATE_FAILED) { - nm_device_queue_state(self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); - } -} - -static void -deactivate_async_ready(NMDevice *self, GError *error, gpointer user_data) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceStateReason reason = GPOINTER_TO_UINT(user_data); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - _LOGD(LOGD_DEVICE, "Deactivation cancelled"); - return; - } - - g_clear_object(&priv->deactivating_cancellable); - - /* In every other case, transition to the DISCONNECTED state */ - if (error) { - _LOGW(LOGD_DEVICE, "Deactivation failed: %s", error->message); - } - - deactivate_ready(self, reason); -} - -static void -deactivate_dispatcher_complete(NMDispatcherCallId *call_id, gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceStateReason reason; - - g_return_if_fail(call_id == priv->dispatcher.call_id); - g_return_if_fail(priv->dispatcher.post_state == NM_DEVICE_STATE_DISCONNECTED); - - reason = priv->state_reason; - - priv->dispatcher.call_id = NULL; - priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN; - priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; - - if (nm_clear_g_cancellable(&priv->deactivating_cancellable)) - nm_assert_not_reached(); - - if (NM_DEVICE_GET_CLASS(self)->deactivate_async) { - /* FIXME: the virtual function deactivate_async() has only this caller here. - * And the NMDevice subtypes are well aware of the circumstances when they - * are called. We shall make the function less generic and thus (as the scope - * is narrower) more convenient. - * - * - Drop the callback argument. Instead, when deactivate_async() completes, the - * subtype shall call a method _nm_device_deactivate_async_done(). Because as - * it is currently, subtypes need to pretend this callback and the user-data - * would be opaque, and carry it around. When it's in fact very clear what this - * is. - * - * - Also drop the GCancellable argument. Upon cancellation, NMDevice shall - * call another virtual function deactivate_async_abort(). As it is currently, - * callers need to register to the cancelled signal of the cancellable. It - * seems simpler to just implement the deactivate_async_abort() function. - * On the other hand, some implementations actually use the GCancellable. - * So, NMDevice shall do both: it shall both pass a cancellable, but also - * invoke deactivate_async_abort(). It allow the implementation to honor - * whatever is simpler for their purpose. - * - * - sometimes, the subclass can complete right away. Scheduling the completion - * in an idle handler is cumbersome. Allow the function to return FALSE to - * indicate that the device is already deactivated and the callback (or - * _nm_device_deactivate_async_done()) won't be invoked. - */ - priv->deactivating_cancellable = g_cancellable_new(); - NM_DEVICE_GET_CLASS(self)->deactivate_async(self, - priv->deactivating_cancellable, - deactivate_async_ready, - GUINT_TO_POINTER(reason)); - } else - deactivate_ready(self, reason); -} - -static void -_set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting) -{ - NMDevicePrivate *priv; - NMDeviceState old_state; - gs_unref_object NMActRequest *req = NULL; - gboolean no_firmware = FALSE; - NMSettingsConnection * sett_conn; - NMSettingSriov * s_sriov; - gboolean concheck_now; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - /* Track re-entry */ - g_warn_if_fail(priv->in_state_changed == FALSE); - - old_state = priv->state; - - if (state == NM_DEVICE_STATE_FAILED && nm_device_sys_iface_state_is_external_or_assume(self)) { - /* Avoid tearing down assumed connection, assume it's connected */ - state = NM_DEVICE_STATE_ACTIVATED; - reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; - } - - /* Do nothing if state isn't changing, but as a special case allow - * re-setting UNAVAILABLE if the device is missing firmware so that we - * can retry device initialization. - */ - if ((priv->state == state) - && (state != NM_DEVICE_STATE_UNAVAILABLE || !priv->firmware_missing)) { - _LOGD(LOGD_DEVICE, - "state change: %s -> %s (reason '%s', sys-iface-state: '%s'%s)", - nm_device_state_to_str(old_state), - nm_device_state_to_str(state), - reason_to_string_a(reason), - _sys_iface_state_to_str(priv->sys_iface_state), - priv->firmware_missing ? ", missing firmware" : ""); - return; - } - - _LOGI(LOGD_DEVICE, - "state change: %s -> %s (reason '%s', sys-iface-state: '%s')", - nm_device_state_to_str(old_state), - nm_device_state_to_str(state), - reason_to_string_a(reason), - _sys_iface_state_to_str(priv->sys_iface_state)); - - /* in order to prevent triggering any callback caused - * by the device not having any pending action anymore - * we add one here that gets removed at the end of the function */ - nm_device_add_pending_action(self, NM_PENDING_ACTION_IN_STATE_CHANGE, TRUE); - priv->in_state_changed = TRUE; - - priv->state = state; - priv->state_reason = reason; - - queued_state_clear(self); - - dispatcher_cleanup(self); - - nm_clear_g_cancellable(&priv->deactivating_cancellable); - - /* Cache the activation request for the dispatcher */ - req = nm_g_object_ref(priv->act_request.obj); - - if (state > NM_DEVICE_STATE_UNMANAGED && state <= NM_DEVICE_STATE_ACTIVATED - && nm_device_state_reason_check(reason) == NM_DEVICE_STATE_REASON_NOW_MANAGED - && NM_IN_SET_TYPED(NMDeviceSysIfaceState, - priv->sys_iface_state, - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME)) - nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_MANAGED); - - if (state <= NM_DEVICE_STATE_DISCONNECTED || state >= NM_DEVICE_STATE_ACTIVATED) - priv->auth_retries = NM_DEVICE_AUTH_RETRIES_UNSET; - - if (state > NM_DEVICE_STATE_DISCONNECTED) - nm_device_assume_state_reset(self); - - if (state <= NM_DEVICE_STATE_UNAVAILABLE) { - if (available_connections_del_all(self)) - _notify(self, PROP_AVAILABLE_CONNECTIONS); - if (old_state > NM_DEVICE_STATE_UNAVAILABLE) { - _clear_queued_act_request(priv, NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); - } - } - - /* Update the available connections list when a device first becomes available */ - if (state >= NM_DEVICE_STATE_DISCONNECTED && old_state < NM_DEVICE_STATE_DISCONNECTED) - nm_device_recheck_available_connections(self); - - if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_DEACTIVATING) { - if (nm_clear_g_free(&priv->current_stable_id)) - _LOGT(LOGD_DEVICE, "stable-id: clear"); - } - - /* Handle the new state here; but anything that could trigger - * another state change should be done below. - */ - switch (state) { - case NM_DEVICE_STATE_UNMANAGED: - nm_device_set_firmware_missing(self, FALSE); - if (old_state > NM_DEVICE_STATE_UNMANAGED) { - if (priv->sys_iface_state != NM_DEVICE_SYS_IFACE_STATE_MANAGED) { - nm_device_cleanup(self, - reason, - priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_REMOVED - ? CLEANUP_TYPE_REMOVED - : CLEANUP_TYPE_KEEP); - } else { - /* Clean up if the device is now unmanaged but was activated */ - if (nm_device_get_act_request(self)) - nm_device_cleanup(self, reason, CLEANUP_TYPE_DECONFIGURE); - nm_device_take_down(self, TRUE); - nm_device_hw_addr_reset(self, "unmanage"); - set_nm_ipv6ll(self, FALSE); - restore_ip6_properties(self); - break; - } - } - break; - case NM_DEVICE_STATE_UNAVAILABLE: - if (old_state == NM_DEVICE_STATE_UNMANAGED) { - save_ip6_properties(self); - if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) - ip6_managed_setup(self); - device_init_static_sriov_num_vfs(self); - } - - if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) { - if (old_state == NM_DEVICE_STATE_UNMANAGED || priv->firmware_missing) { - if (!nm_device_bring_up(self, TRUE, &no_firmware) && no_firmware) - _LOGW(LOGD_PLATFORM, "firmware may be missing."); - nm_device_set_firmware_missing(self, no_firmware ? TRUE : FALSE); - } - - /* Ensure the device gets deactivated in response to stuff like - * carrier changes or rfkill. But don't deactivate devices that are - * about to assume a connection since that defeats the purpose of - * assuming the device's existing connection. - * - * Note that we "deactivate" the device even when coming from - * UNMANAGED, to ensure that it's in a clean state. - */ - nm_device_cleanup(self, reason, CLEANUP_TYPE_DECONFIGURE); - } - break; - case NM_DEVICE_STATE_DISCONNECTED: - if (old_state > NM_DEVICE_STATE_DISCONNECTED) { - /* Ensure devices that previously assumed a connection now have - * userspace IPv6LL enabled. - */ - set_nm_ipv6ll(self, TRUE); - - nm_device_cleanup(self, reason, CLEANUP_TYPE_DECONFIGURE); - } else if (old_state < NM_DEVICE_STATE_DISCONNECTED) { - if (priv->sys_iface_state == NM_DEVICE_SYS_IFACE_STATE_MANAGED) { - /* Ensure IPv6 is set up as it may not have been done when - * entering the UNAVAILABLE state depending on the reason. - */ - ip6_managed_setup(self); - } - } - break; - case NM_DEVICE_STATE_PREPARE: - nm_device_update_initial_hw_address(self); - break; - case NM_DEVICE_STATE_NEED_AUTH: - if (old_state > NM_DEVICE_STATE_NEED_AUTH) { - /* Clean up any half-done IP operations if the device's layer2 - * finds out it needs authentication during IP config. - */ - _cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_DECONFIGURE); - _cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_DECONFIGURE); - } - break; - default: - break; - } - - /* Reset intern autoconnect flags when the device is activating or connected. */ - if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) - nm_device_autoconnect_blocked_unset(self, NM_DEVICE_AUTOCONNECT_BLOCKED_INTERNAL); - - _notify(self, PROP_STATE); - _notify(self, PROP_STATE_REASON); - nm_dbus_object_emit_signal(NM_DBUS_OBJECT(self), - &interface_info_device, - &signal_info_state_changed, - "(uuu)", - (guint32) state, - (guint32) old_state, - (guint32) reason); - g_signal_emit(self, - signals[STATE_CHANGED], - 0, - (guint) state, - (guint) old_state, - (guint) reason); - - /* Post-process the event after internal notification */ - - switch (state) { - case NM_DEVICE_STATE_UNAVAILABLE: - /* If the device can activate now (ie, it's got a carrier, the supplicant - * is active, or whatever) schedule a delayed transition to DISCONNECTED - * to get things rolling. The device can't transition immediately because - * we can't change states again from the state handler for a variety of - * reasons. - */ - if (nm_device_is_available(self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) { - nm_device_queue_recheck_available(self, - NM_DEVICE_STATE_REASON_NONE, - NM_DEVICE_STATE_REASON_NONE); - } else { - _LOGD(LOGD_DEVICE, "device not yet available for transition to DISCONNECTED"); - } - break; - case NM_DEVICE_STATE_DEACTIVATING: - _cancel_activation(self); - - /* We cache the ignore_carrier state to not react on config-reloads while the connection - * is active. But on deactivating, reset the ignore-carrier flag to the current state. */ - priv->ignore_carrier = nm_config_data_get_ignore_carrier(NM_CONFIG_GET_DATA, self); - - if (quitting) { - nm_dispatcher_call_device_sync(NM_DISPATCHER_ACTION_PRE_DOWN, self, req); - } else { - priv->dispatcher.post_state = NM_DEVICE_STATE_DISCONNECTED; - priv->dispatcher.post_state_reason = reason; - if (!nm_dispatcher_call_device(NM_DISPATCHER_ACTION_PRE_DOWN, - self, - req, - deactivate_dispatcher_complete, - self, - &priv->dispatcher.call_id)) { - /* Just proceed on errors */ - deactivate_dispatcher_complete(0, self); - } - - if (priv->ifindex > 0 - && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { - priv->sriov_reset_pending++; - sriov_op_queue(self, - 0, - NM_TERNARY_TRUE, - sriov_reset_on_deactivate_cb, - nm_utils_user_data_pack(self, GINT_TO_POINTER(reason))); - } - } - - nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); - break; - case NM_DEVICE_STATE_DISCONNECTED: - if (priv->queued_act_request && !priv->queued_act_request_is_waiting_for_carrier) { - gs_unref_object NMActRequest *queued_req = NULL; - - queued_req = g_steal_pointer(&priv->queued_act_request); - _device_activate(self, queued_req); - } - break; - case NM_DEVICE_STATE_ACTIVATED: - _LOGI(LOGD_DEVICE, "Activation: successful, device activated."); - nm_device_update_metered(self); - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_UP, self, req, NULL, NULL, NULL); - - if (priv->proxy_config) - _pacrunner_manager_add(self); - break; - case NM_DEVICE_STATE_FAILED: - /* Usually upon failure the activation chain is interrupted in - * one of the stages; but in some cases the device fails for - * external events (as a failure of master connection) while - * the activation sequence is running and so we need to ensure - * that the chain is terminated here. - */ - _cancel_activation(self); - - sett_conn = nm_device_get_settings_connection(self); - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "Activation: failed for connection '%s'", - sett_conn ? nm_settings_connection_get_id(sett_conn) : "<unknown>"); - - /* Notify any slaves of the unexpected failure */ - nm_device_master_release_slaves(self); - - /* If the connection doesn't yet have a timestamp, set it to zero so that - * we can distinguish between connections we've tried to activate and have - * failed (zero timestamp), connections that succeeded (non-zero timestamp), - * and those we haven't tried yet (no timestamp). - */ - if (sett_conn && !nm_settings_connection_get_timestamp(sett_conn, NULL)) - nm_settings_connection_update_timestamp(sett_conn, (guint64) 0); - - if (priv->ifindex > 0 - && (s_sriov = nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))) { - priv->sriov_reset_pending++; - sriov_op_queue(self, 0, NM_TERNARY_TRUE, sriov_reset_on_failure_cb, self); - break; - } - /* Schedule the transition to DISCONNECTED. The device can't transition - * immediately because we can't change states again from the state - * handler for a variety of reasons. - */ - nm_device_queue_state(self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); - break; - case NM_DEVICE_STATE_IP_CHECK: - if (priv->fw_state >= FIREWALL_STATE_INITIALIZED && priv->ip_iface - && !nm_device_sys_iface_state_is_external(self)) { - priv->fw_state = FIREWALL_STATE_WAIT_IP_CONFIG; - fw_change_zone(self); - } else - nm_device_start_ip_check(self); - - /* IP-related properties are only valid when the device has IP configuration; - * now that it does, ensure their change notifications are emitted. - */ - notify_ip_properties(self); - break; - case NM_DEVICE_STATE_SECONDARIES: - ip_check_gw_ping_cleanup(self); - _LOGD(LOGD_DEVICE, "device entered SECONDARIES state"); - break; - default: - break; - } - - if (state > NM_DEVICE_STATE_DISCONNECTED) - delete_on_deactivate_unschedule(self); - - if ((old_state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_DEACTIVATING) - && (state != NM_DEVICE_STATE_DEACTIVATING)) { - if (quitting) { - nm_dispatcher_call_device_sync(NM_DISPATCHER_ACTION_DOWN, self, req); - } else { - nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DOWN, self, req, NULL, NULL, NULL); - } - } - - /* IP-related properties are only valid when the device has IP configuration. - * If it no longer does, ensure their change notifications are emitted. - */ - if (ip_config_valid(old_state) && !ip_config_valid(state)) - notify_ip_properties(self); - - concheck_now = NM_IN_SET(state, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_DISCONNECTED) - || old_state >= NM_DEVICE_STATE_ACTIVATED; - concheck_update_interval(self, AF_INET, concheck_now); - concheck_update_interval(self, AF_INET6, concheck_now); - - priv->in_state_changed = FALSE; - nm_device_remove_pending_action(self, NM_PENDING_ACTION_IN_STATE_CHANGE, TRUE); - - if ((old_state > NM_DEVICE_STATE_UNMANAGED) != (state > NM_DEVICE_STATE_UNMANAGED)) - _notify(self, PROP_MANAGED); -} - -void -nm_device_state_changed(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason) -{ - _set_state_full(self, state, reason, FALSE); -} - -static gboolean -queued_state_set(gpointer user_data) -{ - NMDevice * self = NM_DEVICE(user_data); - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMDeviceState new_state; - NMDeviceStateReason new_reason; - - nm_assert(priv->queued_state.id); - - _LOGD(LOGD_DEVICE, - "queue-state[%s, reason:%s, id:%u]: %s", - nm_device_state_to_str(priv->queued_state.state), - reason_to_string_a(priv->queued_state.reason), - priv->queued_state.id, - "change state"); - - /* Clear queued state struct before triggering state change, since - * the state change may queue another state. - */ - priv->queued_state.id = 0; - new_state = priv->queued_state.state; - new_reason = priv->queued_state.reason; - - nm_device_state_changed(self, new_state, new_reason); - nm_device_remove_pending_action(self, queued_state_to_string(new_state), TRUE); - - return G_SOURCE_REMOVE; -} - -void -nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason) -{ - NMDevicePrivate *priv; - - g_return_if_fail(NM_IS_DEVICE(self)); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->queued_state.id && priv->queued_state.state == state) { - _LOGD(LOGD_DEVICE, - "queue-state[%s, reason:%s, id:%u]: %s%s%s%s", - nm_device_state_to_str(priv->queued_state.state), - reason_to_string_a(priv->queued_state.reason), - priv->queued_state.id, - "ignore queuing same state change", - NM_PRINT_FMT_QUOTED(priv->queued_state.reason != reason, - " (reason differs: ", - reason_to_string_a(reason), - ")", - "")); - return; - } - - /* Add pending action for the new state before clearing the queued states, so - * that we don't accidentally pop all pending states and reach 'startup complete' */ - nm_device_add_pending_action(self, queued_state_to_string(state), TRUE); - - /* We should only ever have one delayed state transition at a time */ - if (priv->queued_state.id) { - _LOGW(LOGD_DEVICE, - "queue-state[%s, reason:%s, id:%u]: %s", - nm_device_state_to_str(priv->queued_state.state), - reason_to_string_a(priv->queued_state.reason), - priv->queued_state.id, - "replace previously queued state change"); - nm_clear_g_source(&priv->queued_state.id); - nm_device_remove_pending_action(self, - queued_state_to_string(priv->queued_state.state), - TRUE); - } - - priv->queued_state.state = state; - priv->queued_state.reason = reason; - priv->queued_state.id = g_idle_add(queued_state_set, self); - - _LOGD(LOGD_DEVICE, - "queue-state[%s, reason:%s, id:%u]: %s", - nm_device_state_to_str(state), - reason_to_string_a(reason), - priv->queued_state.id, - "queue state change"); -} - -static void -queued_state_clear(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->queued_state.id) - return; - - _LOGD(LOGD_DEVICE, - "queue-state[%s, reason:%s, id:%u]: %s", - nm_device_state_to_str(priv->queued_state.state), - reason_to_string_a(priv->queued_state.reason), - priv->queued_state.id, - "clear queued state change"); - nm_clear_g_source(&priv->queued_state.id); - nm_device_remove_pending_action(self, queued_state_to_string(priv->queued_state.state), TRUE); -} - -NMDeviceState -nm_device_get_state(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NM_DEVICE_STATE_UNKNOWN); - - return NM_DEVICE_GET_PRIVATE(self)->state; -} - -/*****************************************************************************/ -/* NMConfigDevice interface related stuff */ - -const char * -nm_device_get_hw_address(NMDevice *self) -{ - NMDevicePrivate *priv; - char buf[NM_UTILS_HWADDR_LEN_MAX]; - gsize l; - - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - priv = NM_DEVICE_GET_PRIVATE(self); - - nm_assert((!priv->hw_addr && priv->hw_addr_len == 0) - || (priv->hw_addr && _nm_utils_hwaddr_aton(priv->hw_addr, buf, sizeof(buf), &l) - && l == priv->hw_addr_len)); - - return priv->hw_addr; -} - -gboolean -nm_device_update_hw_address(NMDevice *self) -{ - NMDevicePrivate *priv; - const guint8 * hwaddr; - gsize hwaddrlen = 0; - - priv = NM_DEVICE_GET_PRIVATE(self); - if (priv->ifindex <= 0) - return FALSE; - - hwaddr = nm_platform_link_get_address(nm_device_get_platform(self), priv->ifindex, &hwaddrlen); - - if (priv->type == NM_DEVICE_TYPE_ETHERNET && hwaddr - && nm_utils_hwaddr_matches(hwaddr, - hwaddrlen, - &nm_ether_addr_zero, - sizeof(nm_ether_addr_zero))) - hwaddrlen = 0; - - if (!hwaddrlen) - return FALSE; - - if (priv->hw_addr_len && priv->hw_addr_len != hwaddrlen) { - char s_buf[NM_UTILS_HWADDR_LEN_MAX_STR]; - - /* we cannot change the address length of a device once it is set (except - * unrealizing the device). - * - * The reason is that the permanent and initial MAC addresses also must have the - * same address length, so it's unclear what it would mean that the length changes. */ - _LOGD(LOGD_PLATFORM | LOGD_DEVICE, - "hw-addr: read a MAC address with differing length (%s vs. %s)", - priv->hw_addr, - _nm_utils_hwaddr_ntoa(hwaddr, hwaddrlen, TRUE, s_buf, sizeof(s_buf))); - return FALSE; - } - - if (priv->hw_addr && nm_utils_hwaddr_matches(priv->hw_addr, -1, hwaddr, hwaddrlen)) - return FALSE; - - g_free(priv->hw_addr); - priv->hw_addr_len_ = hwaddrlen; - priv->hw_addr = nm_utils_hwaddr_ntoa(hwaddr, hwaddrlen); - - _LOGD(LOGD_PLATFORM | LOGD_DEVICE, "hw-addr: hardware address now %s", priv->hw_addr); - _notify(self, PROP_HW_ADDRESS); - - if (!priv->hw_addr_initial - || (priv->hw_addr_type == HW_ADDR_TYPE_UNSET && priv->state < NM_DEVICE_STATE_PREPARE - && !nm_device_is_activating(self))) { - /* when we get a hw_addr the first time or while the device - * is not activated (with no explicit hw address set), always - * update our initial hw-address as well. */ - nm_device_update_initial_hw_address(self); - } - return TRUE; -} - -void -nm_device_update_initial_hw_address(NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->hw_addr && !nm_streq0(priv->hw_addr_initial, priv->hw_addr)) { - if (priv->hw_addr_initial && priv->hw_addr_type != HW_ADDR_TYPE_UNSET) { - /* once we have the initial hw address set, we only allow - * update if the currently type is "unset". */ - return; - } - g_free(priv->hw_addr_initial); - priv->hw_addr_initial = g_strdup(priv->hw_addr); - _LOGD(LOGD_DEVICE, "hw-addr: update initial MAC address %s", priv->hw_addr_initial); - } -} - -void -nm_device_update_permanent_hw_address(NMDevice *self, gboolean force_freeze) -{ - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; - size_t len = 0; - gboolean success_read; - int ifindex; - const NMPlatformLink * pllink; - const NMConfigDeviceStateData *dev_state; - - if (priv->hw_addr_perm) { - /* the permanent hardware address is only read once and not - * re-read later. - * - * Except during unrealize/realize cycles, where we clear the permanent - * hardware address during unrealization. */ - return; - } - - ifindex = priv->ifindex; - if (ifindex <= 0) - return; - - /* the user is advised to configure stable MAC addresses for software devices via - * UDEV. Thus, check whether the link is fully initialized. */ - pllink = nm_platform_link_get(nm_device_get_platform(self), ifindex); - if (!pllink || !pllink->initialized) { - if (!force_freeze) { - /* we can afford to wait. Back off and leave the permanent MAC address - * undecided for now. */ - return; - } - /* try to refresh the link just to give UDEV a bit more time... */ - nm_platform_link_refresh(nm_device_get_platform(self), ifindex); - /* maybe the MAC address changed... */ - nm_device_update_hw_address(self); - } else if (!priv->hw_addr_len) - nm_device_update_hw_address(self); - - if (!priv->hw_addr_len) { - /* we need the current MAC address because we require the permanent MAC address - * to have the same length as the current address. - * - * Abort if there is no current MAC address. */ - return; - } - - success_read = - nm_platform_link_get_permanent_address(nm_device_get_platform(self), ifindex, buf, &len); - if (success_read && priv->hw_addr_len == len) { - priv->hw_addr_perm_fake = FALSE; - priv->hw_addr_perm = nm_utils_hwaddr_ntoa(buf, len); - _LOGD(LOGD_DEVICE, "hw-addr: read permanent MAC address '%s'", priv->hw_addr_perm); - goto notify_and_out; - } - - /* we failed to read a permanent MAC address, thus we use a fake address, - * that is the current MAC address of the device. - * - * Note that the permanet MAC address of a NMDevice instance does not change - * after being set once. Thus, we use now a fake address and stick to that - * (until we unrealize the device). */ - priv->hw_addr_perm_fake = TRUE; - - /* We also persist our choice of the fake address to the device state - * file to use the same address on restart of NetworkManager. - * First, try to reload the address from the state file. */ - dev_state = nm_config_device_state_get(nm_config_get(), ifindex); - if (dev_state && dev_state->perm_hw_addr_fake - && nm_utils_hwaddr_aton(dev_state->perm_hw_addr_fake, buf, priv->hw_addr_len) - && !nm_utils_hwaddr_matches(buf, priv->hw_addr_len, priv->hw_addr, -1)) { - _LOGD(LOGD_PLATFORM | LOGD_ETHER, - "hw-addr: %s (use from statefile: %s, current: %s)", - success_read ? "read HW addr length of permanent MAC address differs" - : "unable to read permanent MAC address", - dev_state->perm_hw_addr_fake, - priv->hw_addr); - priv->hw_addr_perm = nm_utils_hwaddr_ntoa(buf, priv->hw_addr_len); - goto notify_and_out; - } - - _LOGD(LOGD_PLATFORM | LOGD_ETHER, - "hw-addr: %s (use current: %s)", - success_read ? "read HW addr length of permanent MAC address differs" - : "unable to read permanent MAC address", - priv->hw_addr); - priv->hw_addr_perm = g_strdup(priv->hw_addr); - -notify_and_out: - _notify(self, PROP_PERM_HW_ADDRESS); -} - -gboolean -nm_device_hw_addr_is_explict(NMDevice *self) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - return !NM_IN_SET((HwAddrType) priv->hw_addr_type, HW_ADDR_TYPE_PERMANENT, HW_ADDR_TYPE_UNSET); -} - -static gboolean -_hw_addr_matches(NMDevice *self, const guint8 *addr, gsize addr_len) -{ - const char *cur_addr; - - cur_addr = nm_device_get_hw_address(self); - return cur_addr && nm_utils_hwaddr_matches(addr, addr_len, cur_addr, -1); -} - -static gboolean -_hw_addr_set(NMDevice * self, - const char *const addr, - const char *const operation, - const char *const detail) -{ - NMDevicePrivate *priv; - gboolean success = FALSE; - int r; - guint8 addr_bytes[NM_UTILS_HWADDR_LEN_MAX]; - gsize addr_len; - gboolean was_taken_down = FALSE; - gboolean retry_down; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(addr); - nm_assert(operation); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (!_nm_utils_hwaddr_aton(addr, addr_bytes, sizeof(addr_bytes), &addr_len)) - g_return_val_if_reached(FALSE); - - /* Do nothing if current MAC is same */ - if (_hw_addr_matches(self, addr_bytes, addr_len)) { - _LOGT(LOGD_DEVICE, "set-hw-addr: no MAC address change needed (%s)", addr); - return TRUE; - } - - if (priv->hw_addr_len && priv->hw_addr_len != addr_len) { - _LOGT(LOGD_DEVICE, - "set-hw-addr: setting MAC address to '%s' (%s, %s) failed because of wrong address " - "length (should be %u bytes)", - addr, - operation, - detail, - priv->hw_addr_len); - return FALSE; - } - - _LOGT(LOGD_DEVICE, - "set-hw-addr: setting MAC address to '%s' (%s, %s)...", - addr, - operation, - detail); - - if (nm_device_get_device_type(self) == NM_DEVICE_TYPE_WIFI) { - /* Always take the device down for Wi-Fi because - * wpa_supplicant needs it to properly detect the MAC - * change. */ - retry_down = FALSE; - was_taken_down = TRUE; - nm_device_take_down(self, FALSE); - } - -again: - r = nm_platform_link_set_address(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self), - addr_bytes, - addr_len); - success = (r >= 0); - if (!success) { - retry_down = - !was_taken_down && r != -NME_PL_NOT_FOUND - && nm_platform_link_is_up(nm_device_get_platform(self), nm_device_get_ip_ifindex(self)); - _NMLOG((retry_down || r == -NME_PL_NOT_FOUND) ? LOGL_DEBUG : LOGL_WARN, - LOGD_DEVICE, - "set-hw-addr: failed to %s MAC address to %s (%s) (%s)%s", - operation, - addr, - detail, - nm_strerror(r), - retry_down ? " (retry with taking down)" : ""); - } else { - /* MAC address successfully changed; update the current MAC to match */ - nm_device_update_hw_address(self); - - if (!_hw_addr_matches(self, addr_bytes, addr_len)) { - gint64 poll_end, now; - - _LOGD(LOGD_DEVICE, - "set-hw-addr: new MAC address %s not successfully %s (%s) (refresh link)", - addr, - operation, - detail); - - /* The platform call indicated success, however the address is not - * as expected. That is either due to a driver issue (brcmfmac, bgo#770456, - * rh#1374023) or a race where externally the MAC address was reset. - * The race is rather unlikely. - * - * The alternative would be to postpone the activation in case the - * MAC address is not yet ready and poll without blocking. However, - * that is rather complicated and it is not expected that this case - * happens for regular drivers. - * Note that brcmfmac can block NetworkManager for 500 msec while - * taking down the device. Let's add another 100 msec to that. - * - * wait/poll up to 100 msec until it changes. */ - - poll_end = nm_utils_get_monotonic_timestamp_usec() + (100 * 1000); - for (;;) { - if (!nm_platform_link_refresh(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self))) - goto handle_fail; - if (!nm_device_update_hw_address(self)) - goto handle_wait; - if (!_hw_addr_matches(self, addr_bytes, addr_len)) - goto handle_fail; - - break; -handle_wait: - now = nm_utils_get_monotonic_timestamp_usec(); - if (now < poll_end) { - g_usleep(NM_MIN(poll_end - now, 500)); - continue; - } -handle_fail: - success = FALSE; - break; - } - } - - if (success) { - retry_down = FALSE; - _LOGI(LOGD_DEVICE, "set-hw-addr: %s MAC address to %s (%s)", operation, addr, detail); - } else { - retry_down = !was_taken_down - && nm_platform_link_is_up(nm_device_get_platform(self), - nm_device_get_ip_ifindex(self)); - - _NMLOG(retry_down ? LOGL_DEBUG : LOGL_WARN, - LOGD_DEVICE, - "set-hw-addr: new MAC address %s not successfully %s (%s)%s", - addr, - operation, - detail, - retry_down ? " (retry with taking down)" : ""); - } - } - - if (retry_down) { - /* changing the MAC address failed, but also the device was up (and we did not yet try to take - * it down). Optimally, we change the MAC address without taking the device down, but some - * devices don't like that. So, retry with taking the device down. */ - retry_down = FALSE; - was_taken_down = TRUE; - nm_device_take_down(self, FALSE); - goto again; - } - - if (was_taken_down) { - if (!nm_device_bring_up(self, TRUE, NULL)) - return FALSE; - } - - return success; -} - -gboolean -nm_device_hw_addr_set(NMDevice *self, const char *addr, const char *detail, gboolean set_permanent) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (!addr) - g_return_val_if_reached(FALSE); - - if (set_permanent) { - /* The type is set to PERMANENT by NMDeviceVlan when taking the MAC - * address from the parent and by NMDeviceWifi when setting a random MAC - * address during scanning. - */ - priv->hw_addr_type = HW_ADDR_TYPE_PERMANENT; - } - - return _hw_addr_set(self, addr, "set", detail); -} - -/* - * _hw_addr_get_cloned: - * @self: a #NMDevice - * @connection: a #NMConnection - * @is_wifi: whether the device is Wi-Fi - * @preserve: (out): whether the address must be reset to initial one - * @hwaddr: (out): the cloned MAC address to set on interface - * @hwaddr_type: (out): the type of address to set - * @hwaddr_detail: (out): the detail (origin) of address to set - * @error: (out): on return, an error or %NULL - * - * Computes the MAC to be set on a interface. On success, one of the - * following exclusive conditions are verified: - * - * - @preserve is %TRUE: the address must be reset to the initial one - * - @hwaddr is not %NULL: the given address must be set on the device - * - @hwaddr is %NULL and @preserve is %FALSE: no action needed - * - * Returns: %FALSE in case of error in determining the cloned MAC address, - * %TRUE otherwise - */ -static gboolean -_hw_addr_get_cloned(NMDevice * self, - NMConnection *connection, - gboolean is_wifi, - gboolean * preserve, - char ** hwaddr, - HwAddrType * hwaddr_type, - char ** hwaddr_detail, - GError ** error) -{ - NMDevicePrivate *priv; - gs_free char * addr_setting_free = NULL; - gs_free char * hw_addr_generated = NULL; - gs_free char * generate_mac_address_mask_tmp = NULL; - const char * addr, *addr_setting; - char * addr_out; - HwAddrType type_out; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (!connection) - g_return_val_if_reached(FALSE); - - addr = addr_setting = - _prop_get_x_cloned_mac_address(self, connection, is_wifi, &addr_setting_free); - - if (nm_streq(addr, NM_CLONED_MAC_PRESERVE)) { - /* "preserve" means to reset the initial MAC address. */ - NM_SET_OUT(preserve, TRUE); - NM_SET_OUT(hwaddr, NULL); - NM_SET_OUT(hwaddr_type, HW_ADDR_TYPE_UNSET); - NM_SET_OUT(hwaddr_detail, g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); - return TRUE; - } - - if (nm_streq(addr, NM_CLONED_MAC_PERMANENT)) { - gboolean is_fake; - - addr = nm_device_get_permanent_hw_address_full(self, TRUE, &is_fake); - if (is_fake) { - /* Preserve the current address if the permanent address if fake */ - NM_SET_OUT(preserve, TRUE); - NM_SET_OUT(hwaddr, NULL); - NM_SET_OUT(hwaddr_type, HW_ADDR_TYPE_UNSET); - NM_SET_OUT(hwaddr_detail, - g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); - return TRUE; - } else if (!addr) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed to retrieve permanent address"); - return FALSE; - } - addr_out = g_strdup(addr); - type_out = HW_ADDR_TYPE_PERMANENT; - } else if (NM_IN_STRSET(addr, NM_CLONED_MAC_RANDOM)) { - if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { - /* hm, we already use a generate MAC address. Most certainly, that is from the same - * activation request, so we should not create a new random address, instead keep - * the current. */ - goto out_no_action; - } - hw_addr_generated = nm_utils_hw_addr_gen_random_eth( - nm_device_get_initial_hw_address(self), - _prop_get_x_generate_mac_address_mask(self, - connection, - is_wifi, - &generate_mac_address_mask_tmp)); - if (!hw_addr_generated) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed to generate %s MAC address", - "random"); - return FALSE; - } - - addr_out = g_steal_pointer(&hw_addr_generated); - type_out = HW_ADDR_TYPE_GENERATED; - } else if (NM_IN_STRSET(addr, NM_CLONED_MAC_STABLE)) { - NMUtilsStableType stable_type; - const char * stable_id; - - if (priv->hw_addr_type == HW_ADDR_TYPE_GENERATED) { - /* hm, we already use a generate MAC address. Most certainly, that is from the same - * activation request, so let's skip creating the stable address anew. */ - goto out_no_action; - } - - stable_id = _prop_get_connection_stable_id(self, connection, &stable_type); - hw_addr_generated = nm_utils_hw_addr_gen_stable_eth( - stable_type, - stable_id, - nm_device_get_ip_iface(self), - nm_device_get_initial_hw_address(self), - _prop_get_x_generate_mac_address_mask(self, - connection, - is_wifi, - &generate_mac_address_mask_tmp)); - if (!hw_addr_generated) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed to generate %s MAC address", - "stable"); - return FALSE; - } - - addr_out = g_steal_pointer(&hw_addr_generated); - type_out = HW_ADDR_TYPE_GENERATED; - } else { - /* this must be a valid address. Otherwise, we shouldn't come here. */ - if (!nm_utils_hwaddr_valid(addr, -1)) - g_return_val_if_reached(FALSE); - - addr_out = g_strdup(addr); - type_out = HW_ADDR_TYPE_EXPLICIT; - } - - NM_SET_OUT(preserve, FALSE); - NM_SET_OUT(hwaddr, addr_out); - NM_SET_OUT(hwaddr_type, type_out); - NM_SET_OUT(hwaddr_detail, g_steal_pointer(&addr_setting_free) ?: g_strdup(addr_setting)); - return TRUE; -out_no_action: - NM_SET_OUT(preserve, FALSE); - NM_SET_OUT(hwaddr, NULL); - NM_SET_OUT(hwaddr_type, HW_ADDR_TYPE_UNSET); - NM_SET_OUT(hwaddr_detail, NULL); - return TRUE; -} - -gboolean -nm_device_hw_addr_get_cloned(NMDevice * self, - NMConnection *connection, - gboolean is_wifi, - char ** hwaddr, - gboolean * preserve, - GError ** error) -{ - if (!_hw_addr_get_cloned(self, connection, is_wifi, preserve, hwaddr, NULL, NULL, error)) - return FALSE; - - return TRUE; -} - -gboolean -nm_device_hw_addr_set_cloned(NMDevice *self, NMConnection *connection, gboolean is_wifi) -{ - NMDevicePrivate *priv; - gboolean preserve = FALSE; - gs_free char * hwaddr = NULL; - gs_free char * detail = NULL; - HwAddrType type = HW_ADDR_TYPE_UNSET; - gs_free_error GError *error = NULL; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - priv = NM_DEVICE_GET_PRIVATE(self); - - if (!_hw_addr_get_cloned(self, - connection, - is_wifi, - &preserve, - &hwaddr, - &type, - &detail, - &error)) { - _LOGW(LOGD_DEVICE, "set-hw-addr: %s", error->message); - return FALSE; - } - - if (preserve) - return nm_device_hw_addr_reset(self, detail); - - if (hwaddr) { - priv->hw_addr_type = type; - return _hw_addr_set(self, hwaddr, "set-cloned", detail); - } - - return TRUE; -} - -gboolean -nm_device_hw_addr_reset(NMDevice *self, const char *detail) -{ - NMDevicePrivate *priv; - const char * addr; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->hw_addr_type == HW_ADDR_TYPE_UNSET) - return TRUE; - - priv->hw_addr_type = HW_ADDR_TYPE_UNSET; - addr = nm_device_get_initial_hw_address(self); - if (!addr) { - /* as hw_addr_type is not UNSET, we expect that we can get an - * initial address to which to reset. */ - g_return_val_if_reached(FALSE); - } - - return _hw_addr_set(self, addr, "reset", detail); -} - -const char * -nm_device_get_permanent_hw_address_full(NMDevice *self, - gboolean force_freeze, - gboolean *out_is_fake) -{ - NMDevicePrivate *priv; - - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - priv = NM_DEVICE_GET_PRIVATE(self); - - if (!priv->hw_addr_perm && force_freeze) { - /* somebody requests a permanent MAC address, but we don't have it set - * yet. We cannot delay it any longer and try to get it without waiting - * for UDEV. */ - nm_device_update_permanent_hw_address(self, TRUE); - } - - NM_SET_OUT(out_is_fake, priv->hw_addr_perm && priv->hw_addr_perm_fake); - return priv->hw_addr_perm; -} - -const char * -nm_device_get_permanent_hw_address(NMDevice *self) -{ - return nm_device_get_permanent_hw_address_full(self, TRUE, NULL); -} - -const char * -nm_device_get_initial_hw_address(NMDevice *self) -{ - g_return_val_if_fail(NM_IS_DEVICE(self), NULL); - - return NM_DEVICE_GET_PRIVATE(self)->hw_addr_initial; -} - -/** - * nm_device_spec_match_list: - * @self: an #NMDevice - * @specs: (element-type utf8): a list of device specs - * - * Checks if @self matches any of the specifications in @specs. The - * currently-supported spec types are: - * - * "mac:00:11:22:33:44:55" - matches a device with the given - * hardware address - * - * "interface-name:foo0" - matches a device with the given - * interface name - * - * "s390-subchannels:00.11.22" - matches a device with the given - * z/VM / s390 subchannels. - * - * "*" - matches any device - * - * Returns: #TRUE if @self matches one of the specs in @specs - */ -gboolean -nm_device_spec_match_list(NMDevice *self, const GSList *specs) -{ - return nm_device_spec_match_list_full(self, specs, FALSE); -} - -int -nm_device_spec_match_list_full(NMDevice *self, const GSList *specs, int no_match_value) -{ - NMDeviceClass * klass; - NMMatchSpecMatchType m; - const char * hw_address = NULL; - gboolean is_fake; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - klass = NM_DEVICE_GET_CLASS(self); - hw_address = nm_device_get_permanent_hw_address_full( - self, - !nm_device_get_unmanaged_flags(self, NM_UNMANAGED_PLATFORM_INIT), - &is_fake); - - m = nm_match_spec_device(specs, - nm_device_get_iface(self), - nm_device_get_type_description(self), - nm_device_get_driver(self), - nm_device_get_driver_version(self), - is_fake ? NULL : hw_address, - klass->get_s390_subchannels ? klass->get_s390_subchannels(self) : NULL, - nm_dhcp_manager_get_config(nm_dhcp_manager_get())); - - switch (m) { - case NM_MATCH_SPEC_MATCH: - return TRUE; - case NM_MATCH_SPEC_NEG_MATCH: - return FALSE; - case NM_MATCH_SPEC_NO_MATCH: - return no_match_value; - } - nm_assert_not_reached(); - return no_match_value; -} - -guint -nm_device_get_supplicant_timeout(NMDevice *self) -{ - NMConnection * connection; - NMSetting8021x *s_8021x; - int timeout; -#define SUPPLICANT_DEFAULT_TIMEOUT 25 - - g_return_val_if_fail(NM_IS_DEVICE(self), SUPPLICANT_DEFAULT_TIMEOUT); - - connection = nm_device_get_applied_connection(self); - - g_return_val_if_fail(connection, SUPPLICANT_DEFAULT_TIMEOUT); - - s_8021x = nm_connection_get_setting_802_1x(connection); - if (s_8021x) { - timeout = nm_setting_802_1x_get_auth_timeout(s_8021x); - if (timeout > 0) - return timeout; - } - - return nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("802-1x.auth-timeout"), - self, - 1, - G_MAXINT32, - SUPPLICANT_DEFAULT_TIMEOUT); -} - -gboolean -nm_device_auth_retries_try_next(NMDevice *self) -{ - NMDevicePrivate * priv; - NMSettingConnection *s_con; - int auth_retries; - - g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); - - priv = NM_DEVICE_GET_PRIVATE(self); - auth_retries = priv->auth_retries; - - if (G_UNLIKELY(auth_retries == NM_DEVICE_AUTH_RETRIES_UNSET)) { - auth_retries = -1; - - s_con = nm_device_get_applied_setting(self, NM_TYPE_SETTING_CONNECTION); - if (s_con) - auth_retries = nm_setting_connection_get_auth_retries(s_con); - - if (auth_retries == -1) { - auth_retries = nm_config_data_get_connection_default_int64( - NM_CONFIG_GET_DATA, - NM_CON_DEFAULT("connection.auth-retries"), - self, - -1, - G_MAXINT32, - -1); - } - - if (auth_retries == 0) - auth_retries = NM_DEVICE_AUTH_RETRIES_INFINITY; - else if (auth_retries == -1) - auth_retries = NM_DEVICE_AUTH_RETRIES_DEFAULT; - else - nm_assert(auth_retries > 0); - - priv->auth_retries = auth_retries; - } - - if (auth_retries == NM_DEVICE_AUTH_RETRIES_INFINITY) - return TRUE; - if (auth_retries <= 0) { - nm_assert(auth_retries == 0); - return FALSE; - } - priv->auth_retries--; - return TRUE; -} - -/*****************************************************************************/ - -static const char * -_activation_func_to_string(ActivationHandleFunc func) -{ -#define FUNC_TO_STRING_CHECK_AND_RETURN(func, f) \ - G_STMT_START \ - { \ - if ((func) == (f)) \ - return #f; \ - } \ - G_STMT_END - FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage1_device_prepare); - FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage2_device_config); - FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage3_ip_config_start); - FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage4_ip_config_timeout_4); - FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage4_ip_config_timeout_6); - FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage5_ip_config_result_4); - FUNC_TO_STRING_CHECK_AND_RETURN(func, activate_stage5_ip_config_result_6); - g_return_val_if_reached("unknown"); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDevice * self = NM_DEVICE(object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - GVariantBuilder array_builder; - - switch (prop_id) { - case PROP_UDI: - /* UDI is (depending on the device type) a path to sysfs and can contain - * non-UTF-8. - * ip link add name $'d\xccf\\c' type dummy */ - g_value_take_string( - value, - nm_utils_str_utf8safe_escape_cp(priv->udi, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE)); - break; - case PROP_PATH: - g_value_take_string( - value, - nm_utils_str_utf8safe_escape_cp(priv->path, NM_UTILS_STR_UTF8_SAFE_FLAG_NONE)); - break; - case PROP_IFACE: - g_value_take_string( - value, - nm_utils_str_utf8safe_escape_cp(priv->iface, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); - break; - case PROP_IP_IFACE: - if (ip_config_valid(priv->state)) { - g_value_take_string( - value, - nm_utils_str_utf8safe_escape_cp(nm_device_get_ip_iface(self), - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); - } else - g_value_set_string(value, NULL); - break; - case PROP_IFINDEX: - g_value_set_int(value, priv->ifindex); - break; - case PROP_DRIVER: - g_value_take_string( - value, - nm_utils_str_utf8safe_escape_cp(priv->driver, NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); - break; - case PROP_DRIVER_VERSION: - g_value_take_string( - value, - nm_utils_str_utf8safe_escape_cp(priv->driver_version, - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); - break; - case PROP_FIRMWARE_VERSION: - g_value_take_string( - value, - nm_utils_str_utf8safe_escape_cp(priv->firmware_version, - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL)); - break; - case PROP_CAPABILITIES: - g_value_set_uint(value, (priv->capabilities & ~NM_DEVICE_CAP_INTERNAL_MASK)); - break; - case PROP_IP4_ADDRESS: - g_value_set_variant(value, nm_g_variant_singleton_u_0()); - break; - case PROP_CARRIER: - g_value_set_boolean(value, priv->carrier); - break; - case PROP_MTU: - g_value_set_uint(value, priv->mtu); - break; - case PROP_IP4_CONFIG: - nm_dbus_utils_g_value_set_object_path(value, - ip_config_valid(priv->state) ? priv->ip_config_4 - : NULL); - break; - case PROP_DHCP4_CONFIG: - nm_dbus_utils_g_value_set_object_path( - value, - ip_config_valid(priv->state) ? priv->dhcp_data_4.config : NULL); - break; - case PROP_IP6_CONFIG: - nm_dbus_utils_g_value_set_object_path(value, - ip_config_valid(priv->state) ? priv->ip_config_6 - : NULL); - break; - case PROP_DHCP6_CONFIG: - nm_dbus_utils_g_value_set_object_path( - value, - ip_config_valid(priv->state) ? priv->dhcp_data_6.config : NULL); - break; - case PROP_STATE: - g_value_set_uint(value, priv->state); - break; - case PROP_STATE_REASON: - g_value_take_variant(value, g_variant_new("(uu)", priv->state, priv->state_reason)); - break; - case PROP_ACTIVE_CONNECTION: - g_value_set_string(value, nm_dbus_track_obj_path_get(&priv->act_request)); - break; - case PROP_DEVICE_TYPE: - g_value_set_uint(value, priv->type); - break; - case PROP_LINK_TYPE: - g_value_set_uint(value, priv->link_type); - break; - case PROP_MANAGED: - /* The managed state exposed on D-Bus only depends on the current device state alone. */ - g_value_set_boolean(value, nm_device_get_state(self) > NM_DEVICE_STATE_UNMANAGED); - break; - case PROP_AUTOCONNECT: - g_value_set_boolean( - value, - nm_device_autoconnect_blocked_get(self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL) ? FALSE - : TRUE); - break; - case PROP_FIRMWARE_MISSING: - g_value_set_boolean(value, priv->firmware_missing); - break; - case PROP_NM_PLUGIN_MISSING: - g_value_set_boolean(value, priv->nm_plugin_missing); - break; - case PROP_TYPE_DESC: - g_value_set_string(value, priv->type_desc); - break; - case PROP_RFKILL_TYPE: - g_value_set_uint(value, priv->rfkill_type); - break; - case PROP_AVAILABLE_CONNECTIONS: - nm_dbus_utils_g_value_set_object_path_from_hash(value, priv->available_connections, TRUE); - break; - case PROP_PHYSICAL_PORT_ID: - g_value_set_string(value, priv->physical_port_id); - break; - case PROP_MASTER: - g_value_set_object(value, nm_device_get_master(self)); - break; - case PROP_PARENT: - g_value_set_string(value, nm_dbus_track_obj_path_get(&priv->parent_device)); - break; - case PROP_HW_ADDRESS: - g_value_set_string(value, priv->hw_addr); - break; - case PROP_PERM_HW_ADDRESS: - { - const char *perm_hw_addr; - gboolean perm_hw_addr_is_fake; - - perm_hw_addr = nm_device_get_permanent_hw_address_full(self, FALSE, &perm_hw_addr_is_fake); - /* this property is exposed on D-Bus for NMDeviceEthernet and NMDeviceWifi. */ - g_value_set_string(value, perm_hw_addr && !perm_hw_addr_is_fake ? perm_hw_addr : NULL); - break; - } - case PROP_HAS_PENDING_ACTION: - g_value_set_boolean(value, nm_device_has_pending_action(self)); - break; - case PROP_METERED: - g_value_set_uint(value, priv->metered); - break; - case PROP_LLDP_NEIGHBORS: - if (priv->lldp_listener) - g_value_set_variant(value, nm_lldp_listener_get_neighbors(priv->lldp_listener)); - else { - g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aa{sv}")); - g_value_take_variant(value, g_variant_builder_end(&array_builder)); - } - break; - case PROP_REAL: - g_value_set_boolean(value, nm_device_is_real(self)); - break; - case PROP_SLAVES: - { - CList *slave_iter; - char **slave_list; - gsize i, n; - - n = c_list_length(&priv->slaves); - slave_list = g_new(char *, n + 1); - i = 0; - c_list_for_each (slave_iter, &priv->slaves) { - SlaveInfo * info = c_list_entry(slave_iter, SlaveInfo, lst_slave); - const char *path; - - if (!NM_DEVICE_GET_PRIVATE(info->slave)->is_enslaved) - continue; - path = nm_dbus_object_get_path(NM_DBUS_OBJECT(info->slave)); - if (path) - slave_list[i++] = g_strdup(path); - } - nm_assert(i <= n); - slave_list[i] = NULL; - g_value_take_boxed(value, slave_list); - break; - } - case PROP_STATISTICS_REFRESH_RATE_MS: - g_value_set_uint(value, priv->stats.refresh_rate_ms); - break; - case PROP_STATISTICS_TX_BYTES: - g_value_set_uint64(value, priv->stats.tx_bytes); - break; - case PROP_STATISTICS_RX_BYTES: - g_value_set_uint64(value, priv->stats.rx_bytes); - break; - case PROP_IP4_CONNECTIVITY: - g_value_set_uint(value, priv->concheck_x[1].state); - break; - case PROP_IP6_CONNECTIVITY: - g_value_set_uint(value, priv->concheck_x[0].state); - break; - case PROP_INTERFACE_FLAGS: - g_value_set_uint(value, priv->interface_flags); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMDevice * self = (NMDevice *) object; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_UDI: - /* construct-only */ - priv->udi = g_value_dup_string(value); - break; - case PROP_IFACE: - /* construct-only */ - priv->iface_ = g_value_dup_string(value); - break; - case PROP_DRIVER: - /* construct-only */ - priv->driver = g_value_dup_string(value); - break; - case PROP_MANAGED: - /* via D-Bus */ - if (nm_device_is_real(self)) { - gboolean managed; - NMDeviceStateReason reason; - - managed = g_value_get_boolean(value); - if (managed) { - reason = NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED; - if (NM_IN_SET_TYPED(NMDeviceSysIfaceState, - priv->sys_iface_state, - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_REMOVED)) - nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_ASSUME); - } else { - reason = NM_DEVICE_STATE_REASON_REMOVED; - nm_device_sys_iface_state_set(self, NM_DEVICE_SYS_IFACE_STATE_REMOVED); - } - nm_device_set_unmanaged_by_flags(self, NM_UNMANAGED_USER_EXPLICIT, !managed, reason); - } - break; - case PROP_AUTOCONNECT: - /* via D-Bus */ - if (g_value_get_boolean(value)) - nm_device_autoconnect_blocked_unset(self, NM_DEVICE_AUTOCONNECT_BLOCKED_ALL); - else - nm_device_autoconnect_blocked_set(self, NM_DEVICE_AUTOCONNECT_BLOCKED_USER); - break; - case PROP_NM_PLUGIN_MISSING: - /* construct-only */ - priv->nm_plugin_missing = g_value_get_boolean(value); - break; - case PROP_DEVICE_TYPE: - /* construct-only */ - nm_assert(priv->type == NM_DEVICE_TYPE_UNKNOWN); - priv->type = g_value_get_uint(value); - nm_assert(priv->type > NM_DEVICE_TYPE_UNKNOWN); - nm_assert(priv->type <= NM_DEVICE_TYPE_VRF); - break; - case PROP_LINK_TYPE: - /* construct-only */ - nm_assert(priv->link_type == NM_LINK_TYPE_NONE); - priv->link_type = g_value_get_uint(value); - break; - case PROP_TYPE_DESC: - /* construct-only */ - priv->type_desc = g_value_dup_string(value); - break; - case PROP_RFKILL_TYPE: - /* construct-only */ - priv->rfkill_type = g_value_get_uint(value); - break; - case PROP_PERM_HW_ADDRESS: - /* construct-only */ - priv->hw_addr_perm = g_value_dup_string(value); - break; - case PROP_STATISTICS_REFRESH_RATE_MS: - /* via D-Bus */ - _stats_set_refresh_rate(self, g_value_get_uint(value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_init(NMDevice *self) -{ - NMDevicePrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_DEVICE, NMDevicePrivate); - - self->_priv = priv; - - c_list_init(&priv->concheck_lst_head); - c_list_init(&self->devices_lst); - c_list_init(&priv->slaves); - - priv->concheck_x[0].state = NM_CONNECTIVITY_UNKNOWN; - priv->concheck_x[1].state = NM_CONNECTIVITY_UNKNOWN; - - nm_dbus_track_obj_path_init(&priv->parent_device, G_OBJECT(self), obj_properties[PROP_PARENT]); - nm_dbus_track_obj_path_init(&priv->act_request, - G_OBJECT(self), - obj_properties[PROP_ACTIVE_CONNECTION]); - - priv->netns = g_object_ref(NM_NETNS_GET); - - priv->autoconnect_blocked_flags = DEFAULT_AUTOCONNECT ? NM_DEVICE_AUTOCONNECT_BLOCKED_NONE - : NM_DEVICE_AUTOCONNECT_BLOCKED_USER; - - priv->auth_retries = NM_DEVICE_AUTH_RETRIES_UNSET; - priv->type = NM_DEVICE_TYPE_UNKNOWN; - priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; - priv->state = NM_DEVICE_STATE_UNMANAGED; - priv->state_reason = NM_DEVICE_STATE_REASON_NONE; - priv->rfkill_type = RFKILL_TYPE_UNKNOWN; - priv->unmanaged_flags = NM_UNMANAGED_PLATFORM_INIT; - priv->unmanaged_mask = priv->unmanaged_flags; - priv->available_connections = g_hash_table_new_full(nm_direct_hash, NULL, g_object_unref, NULL); - priv->ip6_saved_properties = g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, g_free); - priv->sys_iface_state_ = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL; - - priv->v4_commit_first_time = TRUE; - priv->v6_commit_first_time = TRUE; -} - -static GObject * -constructor(GType type, guint n_construct_params, GObjectConstructParam *construct_params) -{ - GObject * object; - GObjectClass * klass; - NMDevice * self; - NMDevicePrivate * priv; - const NMPlatformLink *pllink; - - klass = G_OBJECT_CLASS(nm_device_parent_class); - object = klass->constructor(type, n_construct_params, construct_params); - if (!object) - return NULL; - - self = NM_DEVICE(object); - priv = NM_DEVICE_GET_PRIVATE(self); - - if (priv->iface && G_LIKELY(!nm_utils_get_testing())) { - pllink = nm_platform_link_get_by_ifname(nm_device_get_platform(self), priv->iface); - - if (pllink && link_type_compatible(self, pllink->type, NULL, NULL)) { - _set_ifindex(self, pllink->ifindex, FALSE); - priv->up = NM_FLAGS_HAS(pllink->n_ifi_flags, IFF_UP); - } - } - - if (priv->hw_addr_perm) { - guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; - gsize l; - - if (!_nm_utils_hwaddr_aton(priv->hw_addr_perm, buf, sizeof(buf), &l)) { - nm_clear_g_free(&priv->hw_addr_perm); - g_return_val_if_reached(object); - } - - priv->hw_addr_len_ = l; - priv->hw_addr = nm_utils_hwaddr_ntoa(buf, l); - _LOGT(LOGD_DEVICE, "hw-addr: has permanent hw-address '%s'", priv->hw_addr_perm); - } - - return object; -} - -static void -constructed(GObject *object) -{ - NMDevice * self = NM_DEVICE(object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - NMPlatform * platform; - - if (NM_DEVICE_GET_CLASS(self)->get_generic_capabilities) - priv->capabilities |= NM_DEVICE_GET_CLASS(self)->get_generic_capabilities(self); - - /* Watch for external IP config changes */ - platform = nm_device_get_platform(self); - g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, - G_CALLBACK(device_ipx_changed), - self); - g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, - G_CALLBACK(device_ipx_changed), - self); - g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, - G_CALLBACK(device_ipx_changed), - self); - g_signal_connect(platform, - NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, - G_CALLBACK(device_ipx_changed), - self); - g_signal_connect(platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK(link_changed_cb), self); - - priv->manager = g_object_ref(NM_MANAGER_GET); - priv->settings = g_object_ref(NM_SETTINGS_GET); - - g_signal_connect(priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_ADDED, - G_CALLBACK(cp_connection_added), - self); - g_signal_connect(priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, - G_CALLBACK(cp_connection_updated), - self); - g_signal_connect(priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK(cp_connection_removed), - self); - - G_OBJECT_CLASS(nm_device_parent_class)->constructed(object); - - _LOGD(LOGD_DEVICE, "constructed (%s)", G_OBJECT_TYPE_NAME(self)); -} - -static void -dispose(GObject *object) -{ - NMDevice * self = NM_DEVICE(object); - NMDevicePrivate * priv = NM_DEVICE_GET_PRIVATE(self); - NMPlatform * platform; - NMDeviceConnectivityHandle *con_handle; - gs_free_error GError *cancelled_error = NULL; - - _LOGD(LOGD_DEVICE, "disposing"); - - nm_assert(c_list_is_empty(&self->devices_lst)); - - while ((con_handle = c_list_first_entry(&priv->concheck_lst_head, - NMDeviceConnectivityHandle, - concheck_lst))) { - if (!cancelled_error) - nm_utils_error_set_cancelled(&cancelled_error, FALSE, "NMDevice"); - concheck_handle_complete(con_handle, cancelled_error); - } - - nm_clear_g_cancellable(&priv->deactivating_cancellable); - - nm_device_assume_state_reset(self); - - _parent_set_ifindex(self, 0, FALSE); - - platform = nm_device_get_platform(self); - g_signal_handlers_disconnect_by_func(platform, G_CALLBACK(device_ipx_changed), self); - g_signal_handlers_disconnect_by_func(platform, G_CALLBACK(link_changed_cb), self); - - arp_cleanup(self); - - nm_clear_g_signal_handler(nm_config_get(), &priv->config_changed_id); - - dispatcher_cleanup(self); - - nm_pacrunner_manager_remove_clear(&priv->pacrunner_conf_id); - - _cleanup_generic_pre(self, CLEANUP_TYPE_KEEP); - - nm_assert(c_list_is_empty(&priv->slaves)); - - /* Let the kernel manage IPv6LL again */ - set_nm_ipv6ll(self, FALSE); - - _cleanup_generic_post(self, CLEANUP_TYPE_KEEP); - - nm_assert(priv->master_ready_id == 0); - - g_hash_table_remove_all(priv->ip6_saved_properties); - - nm_clear_g_source(&priv->recheck_assume_id); - nm_clear_g_source(&priv->recheck_available.call_id); - - nm_clear_g_source(&priv->check_delete_unrealized_id); - - nm_clear_g_source(&priv->stats.timeout_id); - - carrier_disconnected_action_cancel(self); - - _set_ifindex(self, 0, FALSE); - _set_ifindex(self, 0, TRUE); - - if (priv->settings) { - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_added, self); - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_updated, self); - g_signal_handlers_disconnect_by_func(priv->settings, cp_connection_removed, self); - } - - available_connections_del_all(self); - - if (nm_clear_g_source(&priv->carrier_wait_id)) - nm_device_remove_pending_action(self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); - - _clear_queued_act_request(priv, NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); - - nm_clear_g_source(&priv->device_link_changed_id); - nm_clear_g_source(&priv->device_ip_link_changed_id); - - if (priv->lldp_listener) { - g_signal_handlers_disconnect_by_func(priv->lldp_listener, - G_CALLBACK(lldp_neighbors_changed), - self); - nm_lldp_listener_stop(priv->lldp_listener); - g_clear_object(&priv->lldp_listener); - } - - nm_clear_g_source(&priv->concheck_x[0].p_cur_id); - nm_clear_g_source(&priv->concheck_x[1].p_cur_id); - - nm_assert(!priv->sriov.pending); - if (priv->sriov.next) { - nm_g_slice_free(priv->sriov.next); - priv->sriov.next = NULL; - } - - G_OBJECT_CLASS(nm_device_parent_class)->dispose(object); - - if (nm_clear_g_source(&priv->queued_state.id)) { - /* FIXME: we'd expect the queud_state to be already cleared and this statement - * not being necessary. Add this check here to hopefully investigate crash - * rh#1270247. */ - g_return_if_reached(); - } -} - -static void -finalize(GObject *object) -{ - NMDevice * self = NM_DEVICE(object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); - - _LOGD(LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME(self)); - - g_free(priv->hw_addr); - g_free(priv->hw_addr_perm); - g_free(priv->hw_addr_initial); - g_slist_free(priv->pending_actions); - g_slist_free_full(priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - nm_clear_g_free(&priv->physical_port_id); - g_free(priv->udi); - g_free(priv->path); - g_free(priv->iface_); - g_free(priv->ip_iface_); - g_free(priv->driver); - g_free(priv->driver_version); - g_free(priv->firmware_version); - g_free(priv->type_desc); - g_free(priv->dhcp_anycast_address); - g_free(priv->current_stable_id); - - g_hash_table_unref(priv->ip6_saved_properties); - g_hash_table_unref(priv->available_connections); - - nm_dbus_track_obj_path_deinit(&priv->parent_device); - nm_dbus_track_obj_path_deinit(&priv->act_request); - - G_OBJECT_CLASS(nm_device_parent_class)->finalize(object); - - /* for testing, NMDeviceTest does not invoke NMDevice::constructed, - * and thus @settings might be unset. */ - nm_g_object_unref(priv->settings); - nm_g_object_unref(priv->manager); - - nm_g_object_unref(priv->concheck_mgr); - - g_object_unref(priv->netns); -} - -/*****************************************************************************/ - -static const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( - "StateChanged", - .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("new_state", "u"), - NM_DEFINE_GDBUS_ARG_INFO("old_state", "u"), - NM_DEFINE_GDBUS_ARG_INFO("reason", "u"), ), ); - -static const NMDBusInterfaceInfoExtended interface_info_device = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( - NM_DEFINE_GDBUS_METHOD_INFO_INIT( - "Reapply", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO("version_id", "t"), - NM_DEFINE_GDBUS_ARG_INFO("flags", "u"), ), ), - .handle = impl_device_reapply, ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( - NM_DEFINE_GDBUS_METHOD_INFO_INIT( - "GetAppliedConnection", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("flags", "u"), ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("connection", "a{sa{sv}}"), - NM_DEFINE_GDBUS_ARG_INFO("version_id", "t"), ), ), - .handle = impl_device_get_applied_connection, ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(NM_DEFINE_GDBUS_METHOD_INFO_INIT("Disconnect", ), - .handle = impl_device_disconnect, ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(NM_DEFINE_GDBUS_METHOD_INFO_INIT("Delete", ), - .handle = impl_device_delete, ), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_state_changed, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Udi", "s", NM_DEVICE_UDI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Path", "s", NM_DEVICE_PATH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Interface", "s", NM_DEVICE_IFACE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("IpInterface", - "s", - NM_DEVICE_IP_IFACE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Driver", "s", NM_DEVICE_DRIVER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DriverVersion", - "s", - NM_DEVICE_DRIVER_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("FirmwareVersion", - "s", - NM_DEVICE_FIRMWARE_VERSION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Capabilities", - "u", - NM_DEVICE_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip4Address", - "u", - NM_DEVICE_IP4_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("State", "u", NM_DEVICE_STATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("StateReason", - "(uu)", - NM_DEVICE_STATE_REASON), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ActiveConnection", - "o", - NM_DEVICE_ACTIVE_CONNECTION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip4Config", - "o", - NM_DEVICE_IP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Dhcp4Config", - "o", - NM_DEVICE_DHCP4_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ip6Config", - "o", - NM_DEVICE_IP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Dhcp6Config", - "o", - NM_DEVICE_DHCP6_CONFIG), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L("Managed", - "b", - NM_DEVICE_MANAGED, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - NM_AUDIT_OP_DEVICE_MANAGED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE_L("Autoconnect", - "b", - NM_DEVICE_AUTOCONNECT, - NM_AUTH_PERMISSION_NETWORK_CONTROL, - NM_AUDIT_OP_DEVICE_AUTOCONNECT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("FirmwareMissing", - "b", - NM_DEVICE_FIRMWARE_MISSING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("NmPluginMissing", - "b", - NM_DEVICE_NM_PLUGIN_MISSING), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("DeviceType", - "u", - NM_DEVICE_DEVICE_TYPE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AvailableConnections", - "ao", - NM_DEVICE_AVAILABLE_CONNECTIONS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PhysicalPortId", - "s", - NM_DEVICE_PHYSICAL_PORT_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mtu", "u", NM_DEVICE_MTU), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Metered", "u", NM_DEVICE_METERED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("LldpNeighbors", - "aa{sv}", - NM_DEVICE_LLDP_NEIGHBORS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Real", "b", NM_DEVICE_REAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip4Connectivity", - "u", - NM_DEVICE_IP4_CONNECTIVITY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Ip6Connectivity", - "u", - NM_DEVICE_IP6_CONNECTIVITY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("InterfaceFlags", - "u", - NM_DEVICE_INTERFACE_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), ), ), -}; - -const NMDBusInterfaceInfoExtended nm_interface_info_device_statistics = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_STATISTICS, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READWRITABLE( - "RefreshRateMs", - "u", - NM_DEVICE_STATISTICS_REFRESH_RATE_MS, - NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS, - NM_AUDIT_OP_STATISTICS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("TxBytes", - "t", - NM_DEVICE_STATISTICS_TX_BYTES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("RxBytes", - "t", - NM_DEVICE_STATISTICS_RX_BYTES), ), ), -}; - -static void -nm_device_class_init(NMDeviceClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - - g_type_class_add_private(object_class, sizeof(NMDevicePrivate)); - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/Devices"); - dbus_object_class->interface_infos = - NM_DBUS_INTERFACE_INFOS(&interface_info_device, &nm_interface_info_device_statistics); - - object_class->dispose = dispose; - object_class->finalize = finalize; - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->constructor = constructor; - object_class->constructed = constructed; - - klass->link_changed = link_changed; - - klass->is_available = is_available; - klass->act_stage2_config = act_stage2_config; - klass->act_stage3_ip_config_start = act_stage3_ip_config_start; - klass->act_stage4_ip_config_timeout = act_stage4_ip_config_timeout; - - klass->get_type_description = get_type_description; - klass->can_auto_connect = can_auto_connect; - klass->can_update_from_platform_link = can_update_from_platform_link; - klass->check_connection_compatible = check_connection_compatible; - klass->check_connection_available = check_connection_available; - klass->can_unmanaged_external_down = can_unmanaged_external_down; - klass->realize_start_notify = realize_start_notify; - klass->unrealize_notify = unrealize_notify; - klass->carrier_changed_notify = carrier_changed_notify; - klass->get_ip_iface_identifier = get_ip_iface_identifier; - klass->unmanaged_on_quit = unmanaged_on_quit; - klass->deactivate_reset_hw_addr = deactivate_reset_hw_addr; - klass->parent_changed_notify = parent_changed_notify; - klass->can_reapply_change = can_reapply_change; - klass->reapply_connection = reapply_connection; - klass->set_platform_mtu = set_platform_mtu; - - obj_properties[PROP_UDI] = - g_param_spec_string(NM_DEVICE_UDI, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PATH] = g_param_spec_string(NM_DEVICE_PATH, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFACE] = - g_param_spec_string(NM_DEVICE_IFACE, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP_IFACE] = g_param_spec_string(NM_DEVICE_IP_IFACE, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DRIVER] = - g_param_spec_string(NM_DEVICE_DRIVER, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DRIVER_VERSION] = - g_param_spec_string(NM_DEVICE_DRIVER_VERSION, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FIRMWARE_VERSION] = - g_param_spec_string(NM_DEVICE_FIRMWARE_VERSION, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_CAPABILITIES] = - g_param_spec_uint(NM_DEVICE_CAPABILITIES, - "", - "", - 0, - G_MAXUINT32, - NM_DEVICE_CAP_NONE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_CARRIER] = g_param_spec_boolean(NM_DEVICE_CARRIER, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_MTU] = g_param_spec_uint(NM_DEVICE_MTU, - "", - "", - 0, - G_MAXUINT32, - 1500, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP4_ADDRESS] = - g_param_spec_variant(NM_DEVICE_IP4_ADDRESS, - "", - "", - G_VARIANT_TYPE_UINT32, - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP4_CONFIG] = - g_param_spec_string(NM_DEVICE_IP4_CONFIG, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DHCP4_CONFIG] = - g_param_spec_string(NM_DEVICE_DHCP4_CONFIG, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP6_CONFIG] = - g_param_spec_string(NM_DEVICE_IP6_CONFIG, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DHCP6_CONFIG] = - g_param_spec_string(NM_DEVICE_DHCP6_CONFIG, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STATE] = g_param_spec_uint(NM_DEVICE_STATE, - "", - "", - 0, - G_MAXUINT32, - NM_DEVICE_STATE_UNKNOWN, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STATE_REASON] = - g_param_spec_variant(NM_DEVICE_STATE_REASON, - "", - "", - G_VARIANT_TYPE("(uu)"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_ACTIVE_CONNECTION] = - g_param_spec_string(NM_DEVICE_ACTIVE_CONNECTION, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DEVICE_TYPE] = - g_param_spec_uint(NM_DEVICE_DEVICE_TYPE, - "", - "", - 0, - G_MAXUINT32, - NM_DEVICE_TYPE_UNKNOWN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_LINK_TYPE] = - g_param_spec_uint(NM_DEVICE_LINK_TYPE, - "", - "", - 0, - G_MAXUINT32, - NM_LINK_TYPE_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_MANAGED] = g_param_spec_boolean(NM_DEVICE_MANAGED, - "", - "", - FALSE, - G_PARAM_READWRITE | /* via D-Bus */ - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_AUTOCONNECT] = g_param_spec_boolean(NM_DEVICE_AUTOCONNECT, - "", - "", - DEFAULT_AUTOCONNECT, - G_PARAM_READWRITE | /* via D-Bus */ - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FIRMWARE_MISSING] = - g_param_spec_boolean(NM_DEVICE_FIRMWARE_MISSING, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_NM_PLUGIN_MISSING] = - g_param_spec_boolean(NM_DEVICE_NM_PLUGIN_MISSING, - "", - "", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_TYPE_DESC] = - g_param_spec_string(NM_DEVICE_TYPE_DESC, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_RFKILL_TYPE] = - g_param_spec_uint(NM_DEVICE_RFKILL_TYPE, - "", - "", - RFKILL_TYPE_WLAN, - RFKILL_TYPE_MAX, - RFKILL_TYPE_UNKNOWN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFINDEX] = g_param_spec_int(NM_DEVICE_IFINDEX, - "", - "", - 0, - G_MAXINT, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_AVAILABLE_CONNECTIONS] = - g_param_spec_boxed(NM_DEVICE_AVAILABLE_CONNECTIONS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PHYSICAL_PORT_ID] = - g_param_spec_string(NM_DEVICE_PHYSICAL_PORT_ID, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_MASTER] = g_param_spec_object(NM_DEVICE_MASTER, - "", - "", - NM_TYPE_DEVICE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PARENT] = g_param_spec_string(NM_DEVICE_PARENT, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_HW_ADDRESS] = - g_param_spec_string(NM_DEVICE_HW_ADDRESS, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PERM_HW_ADDRESS] = - g_param_spec_string(NM_DEVICE_PERM_HW_ADDRESS, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_HAS_PENDING_ACTION] = - g_param_spec_boolean(NM_DEVICE_HAS_PENDING_ACTION, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_METERED] = g_param_spec_uint(NM_DEVICE_METERED, - "", - "", - 0, - G_MAXUINT32, - NM_METERED_UNKNOWN, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_LLDP_NEIGHBORS] = - g_param_spec_variant(NM_DEVICE_LLDP_NEIGHBORS, - "", - "", - G_VARIANT_TYPE("aa{sv}"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_REAL] = g_param_spec_boolean(NM_DEVICE_REAL, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_SLAVES] = g_param_spec_boxed(NM_DEVICE_SLAVES, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_STATISTICS_REFRESH_RATE_MS] = - g_param_spec_uint(NM_DEVICE_STATISTICS_REFRESH_RATE_MS, - "", - "", - 0, - UINT32_MAX, - 0, - G_PARAM_READWRITE | /* via D-Bus */ - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STATISTICS_TX_BYTES] = - g_param_spec_uint64(NM_DEVICE_STATISTICS_TX_BYTES, - "", - "", - 0, - UINT64_MAX, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_STATISTICS_RX_BYTES] = - g_param_spec_uint64(NM_DEVICE_STATISTICS_RX_BYTES, - "", - "", - 0, - UINT64_MAX, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IP4_CONNECTIVITY] = - g_param_spec_uint(NM_DEVICE_IP4_CONNECTIVITY, - "", - "", - NM_CONNECTIVITY_UNKNOWN, - NM_CONNECTIVITY_FULL, - NM_CONNECTIVITY_UNKNOWN, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IP6_CONNECTIVITY] = - g_param_spec_uint(NM_DEVICE_IP6_CONNECTIVITY, - "", - "", - NM_CONNECTIVITY_UNKNOWN, - NM_CONNECTIVITY_FULL, - NM_CONNECTIVITY_UNKNOWN, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_INTERFACE_FLAGS] = - g_param_spec_uint(NM_DEVICE_INTERFACE_FLAGS, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[STATE_CHANGED] = g_signal_new(NM_DEVICE_STATE_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(NMDeviceClass, state_changed), - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_UINT, - G_TYPE_UINT, - G_TYPE_UINT); - - signals[AUTOCONNECT_ALLOWED] = g_signal_new(NM_DEVICE_AUTOCONNECT_ALLOWED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - autoconnect_allowed_accumulator, - NULL, - NULL, - G_TYPE_BOOLEAN, - 0); - - signals[IP4_CONFIG_CHANGED] = g_signal_new(NM_DEVICE_IP4_CONFIG_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_OBJECT); - - signals[IP6_CONFIG_CHANGED] = g_signal_new(NM_DEVICE_IP6_CONFIG_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_OBJECT); - - signals[IP6_PREFIX_DELEGATED] = g_signal_new(NM_DEVICE_IP6_PREFIX_DELEGATED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - signals[IP6_SUBNET_NEEDED] = g_signal_new(NM_DEVICE_IP6_SUBNET_NEEDED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); - - signals[REMOVED] = g_signal_new(NM_DEVICE_REMOVED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); - - signals[RECHECK_AUTO_ACTIVATE] = g_signal_new(NM_DEVICE_RECHECK_AUTO_ACTIVATE, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); - - signals[RECHECK_ASSUME] = g_signal_new(NM_DEVICE_RECHECK_ASSUME, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); -} - -/* Connection defaults from plugins */ -NM_CON_DEFAULT_NOP("cdma.mtu"); -NM_CON_DEFAULT_NOP("gsm.mtu"); -NM_CON_DEFAULT_NOP("wifi.ap-isolation"); -NM_CON_DEFAULT_NOP("wifi.powersave"); -NM_CON_DEFAULT_NOP("wifi.wake-on-wlan"); -NM_CON_DEFAULT_NOP("wifi-sec.pmf"); -NM_CON_DEFAULT_NOP("wifi-sec.fils"); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h deleted file mode 100644 index 3eae9318..00000000 --- a/src/devices/nm-device.h +++ /dev/null @@ -1,868 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2017 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_H__ -#define __NETWORKMANAGER_DEVICE_H__ - -#include <netinet/in.h> - -#include "nm-setting-connection.h" -#include "nm-dbus-object.h" -#include "nm-dbus-interface.h" -#include "nm-connection.h" -#include "nm-rfkill-manager.h" -#include "NetworkManagerUtils.h" - -typedef enum _nm_packed { - NM_DEVICE_SYS_IFACE_STATE_EXTERNAL, - NM_DEVICE_SYS_IFACE_STATE_ASSUME, - NM_DEVICE_SYS_IFACE_STATE_MANAGED, - - /* the REMOVED state applies when the device is manually set to unmanaged - * or the link was externally removed. In both cases, we move the device - * to UNMANAGED state, without touching the link -- be it, because the link - * is already gone or because we want to release it (give it up). - */ - NM_DEVICE_SYS_IFACE_STATE_REMOVED, -} NMDeviceSysIfaceState; - -typedef enum { - NM_DEVICE_MTU_SOURCE_NONE, - NM_DEVICE_MTU_SOURCE_PARENT, - NM_DEVICE_MTU_SOURCE_IP_CONFIG, - NM_DEVICE_MTU_SOURCE_CONNECTION, -} NMDeviceMtuSource; - -static inline NMDeviceStateReason -nm_device_state_reason_check(NMDeviceStateReason reason) -{ - /* the device-state-reason serves mostly informational purpose during a state - * change. In some cases however, decisions are made based on the reason. - * I tend to think that interpreting the state reason to derive some behaviors - * is confusing, because the cause and effect are so far apart. - * - * This function is here to mark source that inspects the reason to make - * a decision -- contrary to places that set the reason. Thus, by grepping - * for nm_device_state_reason_check() you can find the "effect" to a certain - * reason. - */ - return reason; -} - -#define NM_PENDING_ACTION_AUTOACTIVATE "autoactivate" -#define NM_PENDING_ACTION_IN_STATE_CHANGE "in-state-change" -#define NM_PENDING_ACTION_RECHECK_AVAILABLE "recheck-available" -#define NM_PENDING_ACTION_CARRIER_WAIT "carrier-wait" -#define NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT "waiting-for-supplicant" -#define NM_PENDING_ACTION_WIFI_SCAN "wifi-scan" -#define NM_PENDING_ACTION_WAITING_FOR_COMPANION "waiting-for-companion" -#define NM_PENDING_ACTION_LINK_INIT "link-init" - -#define NM_PENDING_ACTIONPREFIX_QUEUED_STATE_CHANGE "queued-state-change-" -#define NM_PENDING_ACTIONPREFIX_ACTIVATION "activation-" - -/* Properties */ -#define NM_DEVICE_UDI "udi" -#define NM_DEVICE_PATH "path" -#define NM_DEVICE_IFACE "interface" -#define NM_DEVICE_IP_IFACE "ip-interface" -#define NM_DEVICE_DRIVER "driver" -#define NM_DEVICE_DRIVER_VERSION "driver-version" -#define NM_DEVICE_FIRMWARE_VERSION "firmware-version" -#define NM_DEVICE_CAPABILITIES "capabilities" -#define NM_DEVICE_CARRIER "carrier" -#define NM_DEVICE_IP4_ADDRESS "ip4-address" -#define NM_DEVICE_IP4_CONFIG "ip4-config" -#define NM_DEVICE_DHCP4_CONFIG "dhcp4-config" -#define NM_DEVICE_IP6_CONFIG "ip6-config" -#define NM_DEVICE_DHCP6_CONFIG "dhcp6-config" -#define NM_DEVICE_STATE "state" -#define NM_DEVICE_STATE_REASON "state-reason" -#define NM_DEVICE_ACTIVE_CONNECTION "active-connection" -#define NM_DEVICE_DEVICE_TYPE "device-type" /* ugh */ -#define NM_DEVICE_LINK_TYPE "link-type" -#define NM_DEVICE_MANAGED "managed" -#define NM_DEVICE_AUTOCONNECT "autoconnect" -#define NM_DEVICE_FIRMWARE_MISSING "firmware-missing" -#define NM_DEVICE_NM_PLUGIN_MISSING "nm-plugin-missing" -#define NM_DEVICE_AVAILABLE_CONNECTIONS "available-connections" -#define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id" -#define NM_DEVICE_MTU "mtu" -#define NM_DEVICE_HW_ADDRESS "hw-address" - -/* "perm-hw-address" is exposed on D-Bus both for NMDeviceEthernet - * and NMDeviceWifi. */ -#define NM_DEVICE_PERM_HW_ADDRESS "perm-hw-address" - -#define NM_DEVICE_METERED "metered" -#define NM_DEVICE_LLDP_NEIGHBORS "lldp-neighbors" -#define NM_DEVICE_REAL "real" - -/* "parent" is exposed on D-Bus by subclasses like NMDeviceIPTunnel */ -#define NM_DEVICE_PARENT "parent" - -/* the "slaves" property is internal in the parent class, but exposed - * by the derived classes NMDeviceBond, NMDeviceBridge, NMDeviceTeam, - * NMDeviceOvsBridge and NMDeviceOvsPort. */ -#define NM_DEVICE_SLAVES "slaves" /* partially internal */ - -#define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */ -#define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */ -#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */ -#define NM_DEVICE_MASTER "master" /* Internal only */ -#define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */ - -/* Internal signals */ -#define NM_DEVICE_IP4_CONFIG_CHANGED "ip4-config-changed" -#define NM_DEVICE_IP6_CONFIG_CHANGED "ip6-config-changed" -#define NM_DEVICE_IP6_PREFIX_DELEGATED "ip6-prefix-delegated" -#define NM_DEVICE_IP6_SUBNET_NEEDED "ip6-subnet-needed" -#define NM_DEVICE_REMOVED "removed" -#define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate" -#define NM_DEVICE_RECHECK_ASSUME "recheck-assume" -#define NM_DEVICE_STATE_CHANGED "state-changed" -#define NM_DEVICE_LINK_INITIALIZED "link-initialized" -#define NM_DEVICE_AUTOCONNECT_ALLOWED "autoconnect-allowed" - -#define NM_DEVICE_STATISTICS_REFRESH_RATE_MS "refresh-rate-ms" -#define NM_DEVICE_STATISTICS_TX_BYTES "tx-bytes" -#define NM_DEVICE_STATISTICS_RX_BYTES "rx-bytes" - -#define NM_DEVICE_IP4_CONNECTIVITY "ip4-connectivity" -#define NM_DEVICE_IP6_CONNECTIVITY "ip6-connectivity" -#define NM_DEVICE_INTERFACE_FLAGS "interface-flags" - -#define NM_TYPE_DEVICE (nm_device_get_type()) -#define NM_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE, NMDevice)) -#define NM_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE, NMDeviceClass)) -#define NM_IS_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE)) -#define NM_IS_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE)) -#define NM_DEVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE, NMDeviceClass)) - -typedef enum NMActStageReturn NMActStageReturn; - -/* These flags affect whether a connection is considered available on a device - * (check_connection_available()). The flags should have the meaning of relaxing - * a condition, so that adding a flag might make a connection available that would - * not be available otherwise. Adding a flag should never make a connection - * not available if it would be available otherwise. */ -typedef enum { /*< skip >*/ - NM_DEVICE_CHECK_CON_AVAILABLE_NONE = 0, - - /* since NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST is a collection of flags with more fine grained - * parts, this flag in general indicates that this is a user-request. */ - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = (1L << 0), - - /* we also consider devices which have no carrier but are still waiting for the driver - * to detect carrier. Usually, such devices are not yet available, however for a user-request - * they are. They might fail later if carrier doesn't come. */ - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER = (1L << 1), - - /* usually, a profile is only available if the Wi-Fi AP is in range. For an - * explicit user request, we also consider profiles for APs that are not (yet) - * visible. */ - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP = (1L << 2), - - /* a device can be marked as unmanaged for various reasons. Some of these reasons - * are authoritative, others not. Non-authoritative reasons can be overruled by - * `nmcli device set $DEVICE managed yes`. Also, for an explicit user activation - * request we may want to consider the device as managed. This flag makes devices - * that are unmanaged appear available. */ - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED = (1L << 3), - - /* a collection of flags, that are commonly set for an explicit user-request. */ - NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = - _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST - | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER - | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP - | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_OVERRULE_UNMANAGED, - - NM_DEVICE_CHECK_CON_AVAILABLE_ALL = (1L << 4) - 1, -} NMDeviceCheckConAvailableFlags; - -struct _NMDevicePrivate; - -struct _NMDevice { - NMDBusObject parent; - struct _NMDevicePrivate *_priv; - CList devices_lst; -}; - -/* The flags have an relaxing meaning, that means, specifying more flags, can make - * a device appear more available. It can never make a device less available. */ -typedef enum { /*< skip >*/ - NM_DEVICE_CHECK_DEV_AVAILABLE_NONE = 0, - - /* the device is considered available, even if it has no carrier. - * - * For various device types (software devices) we ignore carrier based - * on the type. So, for them, this flag has no effect anyway. */ - _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER = (1L << 0), - - NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST = - _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER, - - NM_DEVICE_CHECK_DEV_AVAILABLE_ALL = (1L << 1) - 1, -} NMDeviceCheckDevAvailableFlags; - -typedef void (*NMDeviceDeactivateCallback)(NMDevice *self, GError *error, gpointer user_data); - -typedef struct _NMDeviceClass { - NMDBusObjectClass parent; - - struct _NMDeviceClass *default_type_description_klass; - const char * default_type_description; - - const char *connection_type_supported; - - /* most device types, can only handle profiles of a particular type. This - * is the connection.type setting, as checked by nm_device_check_connection_compatible() */ - const char *connection_type_check_compatible; - - const NMLinkType *link_types; - - /* if the device MTU is set based on parent's one, this specifies - * a delta in the MTU allowed value due the encapsulation overhead */ - guint16 mtu_parent_delta; - - /* Whether the device type is a master-type. This depends purely on the - * type (NMDeviceClass), not the actual device instance. */ - bool is_master : 1; - - /* Force setting the MTU actually means first setting the MTU - * to (desired_MTU-1) and then setting the desired_MTU - * so that kernel actually applies the MTU, otherwise - * kernel will ignore the request if the link's MTU is the - * same as the desired one. - * - * This is just a workaround made for bridges (ATM) that employ - * a auto-MTU adjust mechanism if no MTU is manually set. - */ - bool mtu_force_set : 1; - - void (*state_changed)(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason); - - void (*link_changed)(NMDevice *self, const NMPlatformLink *pllink); - - /** - * create_and_realize(): - * @self: the #NMDevice - * @connection: the #NMConnection being activated - * @parent: the parent #NMDevice, if any - * @out_plink: on success, a backing kernel network device if one exists. - * The returned pointer is owned by platform and only valid until the - * next platform operation. - * @error: location to store error, or %NULL - * - * Create any backing resources (kernel devices, etc) required for this - * device to activate @connection. If the device is backed by a kernel - * network device, that device should be returned in @out_plink after - * being created. - * - * Returns: %TRUE on success, %FALSE on error - */ - gboolean (*create_and_realize)(NMDevice * self, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error); - - /** - * realize_start_notify(): - * @self: the #NMDevice - * @pllink: the #NMPlatformLink if backed by a kernel netdevice - * - * Hook for derived classes to be notfied during realize_start_setup() - * and perform additional setup. - * - * The default implementation of NMDevice calls link_changed(). - */ - void (*realize_start_notify)(NMDevice *self, const NMPlatformLink *pllink); - - /** - * unrealize(): - * @self: the #NMDevice - * - * Remove the device backing resources. - */ - gboolean (*unrealize)(NMDevice *self, GError **error); - - /** - * unrealize_notify(): - * @self: the #NMDevice - * - * Hook for derived classes to clear any properties that depend on backing resources - * (kernel devices, etc). This is called by nm_device_unrealize() during unrealization. - */ - void (*unrealize_notify)(NMDevice *self); - - /* Hardware state (IFF_UP) */ - gboolean (*can_unmanaged_external_down)(NMDevice *self); - - /* Carrier state (IFF_LOWER_UP) */ - void (*carrier_changed_notify)(NMDevice *, gboolean carrier); - - gboolean (*get_ip_iface_identifier)(NMDevice *self, NMUtilsIPv6IfaceId *out_iid); - - NMDeviceCapabilities (*get_generic_capabilities)(NMDevice *self); - - gboolean (*is_available)(NMDevice *self, NMDeviceCheckDevAvailableFlags flags); - - gboolean (*get_enabled)(NMDevice *self); - - void (*set_enabled)(NMDevice *self, gboolean enabled); - - /* let the subclass return additional NMPlatformRoutingRule (in form of NMPObject - * pointers) that shall be added to the rules provided by this device. - * The returned GPtrArray will be g_ptr_array_unref()'ed. The subclass may or - * may not keep an additional reference and return this array again and again. */ - GPtrArray *(*get_extra_rules)(NMDevice *self); - - /* allow derived classes to override the result of nm_device_autoconnect_allowed(). - * If the value changes, the class should call nm_device_emit_recheck_auto_activate(), - * which emits NM_DEVICE_RECHECK_AUTO_ACTIVATE signal. */ - gboolean (*get_autoconnect_allowed)(NMDevice *self); - - gboolean (*can_auto_connect)(NMDevice * self, - NMSettingsConnection *sett_conn, - char ** specific_object); - - guint32 (*get_configured_mtu)(NMDevice * self, - NMDeviceMtuSource *out_source, - gboolean * out_force); - - /* allow the subclass to overwrite the routing table. This is mainly useful - * to change from partial mode (route-table=0) to full-sync mode (route-table=254). */ - guint32 (*coerce_route_table)(NMDevice *self, - int addr_family, - guint32 route_table, - gboolean is_user_config); - - const char *(*get_auto_ip_config_method)(NMDevice *self, int addr_family); - - /* Checks whether the connection is compatible with the device using - * only the devices type and characteristics. Does not use any live - * network information like Wi-Fi scan lists etc. - */ - gboolean (*check_connection_compatible)(NMDevice * self, - NMConnection *connection, - GError ** error); - - /* Checks whether the connection is likely available to be activated, - * including any live network information like scan lists. The connection - * is checked against the object defined by @specific_object, if given. - * Returns TRUE if the connection is available; FALSE if not. - * - * The passed @flags affect whether a connection is considered - * available or not. Adding more flags, means the connection is - * *more* available. - * - * Specifying @specific_object can only reduce the availability of a connection. - */ - gboolean (*check_connection_available)(NMDevice * self, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error); - - gboolean (*complete_connection)(NMDevice * self, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error); - - NMActStageReturn (*act_stage1_prepare)(NMDevice *self, NMDeviceStateReason *out_failure_reason); - NMActStageReturn (*act_stage2_config)(NMDevice *self, NMDeviceStateReason *out_failure_reason); - NMActStageReturn (*act_stage3_ip_config_start)(NMDevice * self, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason); - NMActStageReturn (*act_stage4_ip_config_timeout)(NMDevice * self, - int addr_family, - NMDeviceStateReason *out_failure_reason); - - void (*ip4_config_pre_commit)(NMDevice *self, NMIP4Config *config); - - /* Async deactivating (in the DEACTIVATING phase) */ - void (*deactivate_async)(NMDevice * self, - GCancellable * cancellable, - NMDeviceDeactivateCallback callback, - gpointer user_data); - - void (*deactivate_reset_hw_addr)(NMDevice *self); - - /* Sync deactivating (in the DISCONNECTED phase) */ - void (*deactivate)(NMDevice *self); - - const char *(*get_type_description)(NMDevice *self); - - const char *(*get_s390_subchannels)(NMDevice *self); - - /* Update the connection with currently configured L2 settings */ - void (*update_connection)(NMDevice *device, NMConnection *connection); - - gboolean (*master_update_slave_connection)(NMDevice * self, - NMDevice * slave, - NMConnection *connection, - GError ** error); - - gboolean (*enslave_slave)(NMDevice * self, - NMDevice * slave, - NMConnection *connection, - gboolean configure); - - void (*release_slave)(NMDevice *self, NMDevice *slave, gboolean configure); - - void (*parent_changed_notify)(NMDevice *self, - int old_ifindex, - NMDevice *old_parent, - int new_ifindex, - NMDevice *new_parent); - - gboolean (*owns_iface)(NMDevice *self, const char *iface); - - NMConnection *(*new_default_connection)(NMDevice *self); - - gboolean (*unmanaged_on_quit)(NMDevice *self); - - gboolean (*can_reapply_change)(NMDevice * self, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error); - - void (*reapply_connection)(NMDevice *self, NMConnection *con_old, NMConnection *con_new); - - guint32 (*get_dhcp_timeout_for_device)(NMDevice *self, int addr_family); - - gboolean (*get_guessed_metered)(NMDevice *self); - - gboolean (*can_update_from_platform_link)(NMDevice *self, const NMPlatformLink *plink); - - gboolean (*set_platform_mtu)(NMDevice *self, guint32 mtu); - - /* Control whether to call stage1 and stage2 callbacks also for assuming - * a device or for external activations. In this case, the callback must - * take care not to touch the device's configuration. */ - bool act_stage1_prepare_also_for_external_or_assume : 1; - bool act_stage2_config_also_for_external_or_assume : 1; - - bool act_stage1_prepare_set_hwaddr_ethernet : 1; - -} NMDeviceClass; - -GType nm_device_get_type(void); - -struct _NMDedupMultiIndex *nm_device_get_multi_index(NMDevice *self); -NMNetns * nm_device_get_netns(NMDevice *self); -NMPlatform * nm_device_get_platform(NMDevice *self); - -const char *nm_device_get_udi(NMDevice *dev); -const char *nm_device_get_iface(NMDevice *dev); - -static inline const char * -_nm_device_get_iface(NMDevice *device) -{ - /* like nm_device_get_iface(), but gracefully accept NULL without - * asserting. */ - return device ? nm_device_get_iface(device) : NULL; -} - -int nm_device_get_ifindex(NMDevice *dev); -gboolean nm_device_is_software(NMDevice *dev); -gboolean nm_device_is_real(NMDevice *dev); -const char * nm_device_get_ip_iface(NMDevice *dev); -const char * nm_device_get_ip_iface_from_platform(NMDevice *dev); -int nm_device_get_ip_ifindex(const NMDevice *dev); -const char * nm_device_get_driver(NMDevice *dev); -const char * nm_device_get_driver_version(NMDevice *dev); -const char * nm_device_get_type_desc(NMDevice *dev); -const char * nm_device_get_type_description(NMDevice *dev); -NMDeviceType nm_device_get_device_type(NMDevice *dev); -NMLinkType nm_device_get_link_type(NMDevice *dev); -NMMetered nm_device_get_metered(NMDevice *dev); - -guint32 nm_device_get_route_table(NMDevice *self, int addr_family); -guint32 nm_device_get_route_metric(NMDevice *dev, int addr_family); - -guint32 nm_device_get_route_metric_default(NMDeviceType device_type); - -const char *nm_device_get_hw_address(NMDevice *dev); -const char *nm_device_get_permanent_hw_address(NMDevice *self); -const char *nm_device_get_permanent_hw_address_full(NMDevice *self, - gboolean force_freeze, - gboolean *out_is_fake); -const char *nm_device_get_initial_hw_address(NMDevice *dev); - -NMProxyConfig *nm_device_get_proxy_config(NMDevice *dev); - -NMDhcpConfig *nm_device_get_dhcp_config(NMDevice *dev, int addr_family); -NMIP4Config * nm_device_get_ip4_config(NMDevice *dev); -void nm_device_replace_vpn4_config(NMDevice *dev, NMIP4Config *old, NMIP4Config *config); - -NMIP6Config *nm_device_get_ip6_config(NMDevice *dev); -void nm_device_replace_vpn6_config(NMDevice *dev, NMIP6Config *old, NMIP6Config *config); - -void nm_device_capture_initial_config(NMDevice *dev); - -int nm_device_parent_get_ifindex(NMDevice *dev); -NMDevice *nm_device_parent_get_device(NMDevice *dev); -void nm_device_parent_set_ifindex(NMDevice *self, int parent_ifindex); -gboolean nm_device_parent_notify_changed(NMDevice *self, - NMDevice *change_candidate, - gboolean device_removed); - -const char *nm_device_parent_find_for_connection(NMDevice * self, - const char *current_setting_parent); - -/* Master */ -gboolean nm_device_is_master(NMDevice *dev); - -/* Slave */ -NMDevice *nm_device_get_master(NMDevice *dev); - -NMActRequest * nm_device_get_act_request(NMDevice *dev); -NMSettingsConnection * nm_device_get_settings_connection(NMDevice *dev); -NMConnection * nm_device_get_settings_connection_get_connection(NMDevice *self); -NMConnection * nm_device_get_applied_connection(NMDevice *dev); -gboolean nm_device_has_unmodified_applied_connection(NMDevice * self, - NMSettingCompareFlags compare_flags); -NMActivationStateFlags nm_device_get_activation_state_flags(NMDevice *self); - -gpointer /* (NMSetting *) */ nm_device_get_applied_setting(NMDevice *dev, GType setting_type); - -void nm_device_removed(NMDevice *self, gboolean unconfigure_ip_config); - -gboolean nm_device_ignore_carrier_by_default(NMDevice *self); - -gboolean nm_device_is_available(NMDevice *dev, NMDeviceCheckDevAvailableFlags flags); -gboolean nm_device_has_carrier(NMDevice *dev); - -NMConnection *nm_device_generate_connection(NMDevice *self, - NMDevice *master, - gboolean *out_maybe_later, - GError ** error); - -gboolean nm_device_master_update_slave_connection(NMDevice * master, - NMDevice * slave, - NMConnection *connection, - GError ** error); - -gboolean -nm_device_can_auto_connect(NMDevice *self, NMSettingsConnection *sett_conn, char **specific_object); - -gboolean nm_device_complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error); - -gboolean -nm_device_check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error); - -gboolean nm_device_check_slave_connection_compatible(NMDevice *device, NMConnection *connection); - -gboolean nm_device_unmanage_on_quit(NMDevice *self); - -gboolean nm_device_spec_match_list(NMDevice *device, const GSList *specs); -int nm_device_spec_match_list_full(NMDevice *self, const GSList *specs, int no_match_value); - -gboolean nm_device_is_activating(NMDevice *dev); -gboolean nm_device_autoconnect_allowed(NMDevice *self); - -NMDeviceState nm_device_get_state(NMDevice *device); - -gboolean nm_device_get_enabled(NMDevice *device); - -void nm_device_set_enabled(NMDevice *device, gboolean enabled); - -RfKillType nm_device_get_rfkill_type(NMDevice *device); - -/* IPv6 prefix delegation */ - -void nm_device_request_ip6_prefixes(NMDevice *self, int needed_prefixes); - -gboolean nm_device_needs_ip6_subnet(NMDevice *self); - -void nm_device_use_ip6_subnet(NMDevice *self, const NMPlatformIP6Address *subnet); - -void nm_device_copy_ip6_dns_config(NMDevice *self, NMDevice *from_device); - -/** - * NMUnmanagedFlags: - * @NM_UNMANAGED_NONE: placeholder value - * @NM_UNMANAGED_SLEEPING: %TRUE when unmanaged because NM is sleeping. - * @NM_UNMANAGED_QUITTING: %TRUE when unmanaged because NM is shutting down. - * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged - * @NM_UNMANAGED_BY_TYPE: %TRUE for unmanaging device by type, like loopback. - * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not - * yet initialized. Unrealized device are also unmanaged for this reason. - * @NM_UNMANAGED_USER_EXPLICIT: %TRUE when unmanaged by explicit user decision - * (e.g. via a D-Bus command) - * @NM_UNMANAGED_USER_SETTINGS: %TRUE when unmanaged by user decision via - * the settings plugin (for example keyfile.unmanaged-devices or ifcfg-rh's - * NM_CONTROLLED=no). Although this is user-configuration (provided from - * the settings plugins, such as NM_CONTROLLED=no in ifcfg-rh), it cannot - * be overruled and is authoritative. That is because users may depend on - * dropping a ifcfg-rh file to ensure the device is unmanaged. - * @NM_UNMANAGED_USER_CONF: %TRUE when unmanaged by user decision via - * the NetworkManager.conf ("unmanaged" in the [device] section). - * Contray to @NM_UNMANAGED_USER_SETTINGS, this can be overwritten via - * D-Bus. - * @NM_UNMANAGED_BY_DEFAULT: %TRUE for certain device types where we unmanage - * them by default - * @NM_UNMANAGED_USER_UDEV: %TRUE when unmanaged by user decision (via UDev rule) - * @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM - * @NM_UNMANAGED_IS_SLAVE: indicates that the device is enslaved. Note that - * setting the NM_UNMANAGED_IS_SLAVE to %TRUE makes no sense, this flag has only - * meaning to set a slave device as managed if the parent is managed too. - */ -typedef enum { /*< skip >*/ - NM_UNMANAGED_NONE = 0, - - /* these flags are authoritative. If one of them is set, - * the device cannot be managed. */ - NM_UNMANAGED_SLEEPING = (1LL << 0), - NM_UNMANAGED_QUITTING = (1LL << 1), - NM_UNMANAGED_PARENT = (1LL << 2), - NM_UNMANAGED_BY_TYPE = (1LL << 3), - NM_UNMANAGED_PLATFORM_INIT = (1LL << 4), - NM_UNMANAGED_USER_EXPLICIT = (1LL << 5), - NM_UNMANAGED_USER_SETTINGS = (1LL << 6), - - /* These flags can be non-effective and be overwritten - * by other flags. */ - NM_UNMANAGED_BY_DEFAULT = (1LL << 8), - NM_UNMANAGED_USER_CONF = (1LL << 9), - NM_UNMANAGED_USER_UDEV = (1LL << 10), - NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 11), - NM_UNMANAGED_IS_SLAVE = (1LL << 12), - -} NMUnmanagedFlags; - -typedef enum { - NM_UNMAN_FLAG_OP_SET_MANAGED = FALSE, - NM_UNMAN_FLAG_OP_SET_UNMANAGED = TRUE, - NM_UNMAN_FLAG_OP_FORGET = 2, -} NMUnmanFlagOp; - -const char *nm_unmanaged_flags2str(NMUnmanagedFlags flags, char *buf, gsize len); - -gboolean nm_device_get_managed(NMDevice *device, gboolean for_user_request); -NMUnmanagedFlags nm_device_get_unmanaged_mask(NMDevice *device, NMUnmanagedFlags flag); -NMUnmanagedFlags nm_device_get_unmanaged_flags(NMDevice *device, NMUnmanagedFlags flag); -void nm_device_set_unmanaged_flags(NMDevice *device, NMUnmanagedFlags flags, NMUnmanFlagOp set_op); -void nm_device_set_unmanaged_by_flags(NMDevice * device, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op, - NMDeviceStateReason reason); -void nm_device_set_unmanaged_by_flags_queue(NMDevice * self, - NMUnmanagedFlags flags, - NMUnmanFlagOp set_op, - NMDeviceStateReason reason); -void nm_device_set_unmanaged_by_user_settings(NMDevice *self); -void nm_device_set_unmanaged_by_user_udev(NMDevice *self); -void nm_device_set_unmanaged_by_user_conf(NMDevice *self); -void nm_device_set_unmanaged_by_quitting(NMDevice *device); - -gboolean nm_device_check_unrealized_device_managed(NMDevice *self); - -gboolean nm_device_is_nm_owned(NMDevice *device); - -gboolean nm_device_has_capability(NMDevice *self, NMDeviceCapabilities caps); - -/*****************************************************************************/ - -void nm_device_assume_state_get(NMDevice * self, - gboolean * out_assume_state_guess_assume, - const char **out_assume_state_connection_uuid); -void nm_device_assume_state_reset(NMDevice *self); - -/*****************************************************************************/ - -gboolean nm_device_realize_start(NMDevice * device, - const NMPlatformLink *plink, - gboolean assume_state_guess_assume, - const char * assume_state_connection_uuid, - gboolean set_nm_owned, - NMUnmanFlagOp unmanaged_user_explicit, - gboolean * out_compatible, - GError ** error); -void nm_device_realize_finish(NMDevice *self, const NMPlatformLink *plink); -gboolean nm_device_create_and_realize(NMDevice * self, - NMConnection *connection, - NMDevice * parent, - GError ** error); -gboolean nm_device_unrealize(NMDevice *device, gboolean remove_resources, GError **error); - -void nm_device_update_from_platform_link(NMDevice *self, const NMPlatformLink *plink); - -typedef enum { - NM_DEVICE_AUTOCONNECT_BLOCKED_NONE = 0, - - NM_DEVICE_AUTOCONNECT_BLOCKED_USER = (1LL << 0), - - NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN = (1LL << 1), - NM_DEVICE_AUTOCONNECT_BLOCKED_MANUAL_DISCONNECT = (1LL << 2), - NM_DEVICE_AUTOCONNECT_BLOCKED_SIM_MISSING = (1LL << 3), - NM_DEVICE_AUTOCONNECT_BLOCKED_INIT_FAILED = (1LL << 4), - - _NM_DEVICE_AUTOCONNECT_BLOCKED_LAST, - - NM_DEVICE_AUTOCONNECT_BLOCKED_ALL = (((_NM_DEVICE_AUTOCONNECT_BLOCKED_LAST - 1) << 1) - 1), - - NM_DEVICE_AUTOCONNECT_BLOCKED_INTERNAL = - NM_DEVICE_AUTOCONNECT_BLOCKED_ALL & ~NM_DEVICE_AUTOCONNECT_BLOCKED_USER, -} NMDeviceAutoconnectBlockedFlags; - -NMDeviceAutoconnectBlockedFlags -nm_device_autoconnect_blocked_get(NMDevice *device, NMDeviceAutoconnectBlockedFlags mask); - -void nm_device_autoconnect_blocked_set_full(NMDevice * device, - NMDeviceAutoconnectBlockedFlags mask, - NMDeviceAutoconnectBlockedFlags values); - -static inline void -nm_device_autoconnect_blocked_set(NMDevice *device, NMDeviceAutoconnectBlockedFlags mask) -{ - nm_device_autoconnect_blocked_set_full(device, mask, mask); -} - -static inline void -nm_device_autoconnect_blocked_unset(NMDevice *device, NMDeviceAutoconnectBlockedFlags mask) -{ - nm_device_autoconnect_blocked_set_full(device, mask, NM_DEVICE_AUTOCONNECT_BLOCKED_NONE); -} - -void nm_device_emit_recheck_auto_activate(NMDevice *device); - -NMDeviceSysIfaceState nm_device_sys_iface_state_get(NMDevice *device); - -gboolean nm_device_sys_iface_state_is_external(NMDevice *self); -gboolean nm_device_sys_iface_state_is_external_or_assume(NMDevice *self); - -void nm_device_sys_iface_state_set(NMDevice *device, NMDeviceSysIfaceState sys_iface_state); - -void nm_device_state_changed(NMDevice *device, NMDeviceState state, NMDeviceStateReason reason); - -void nm_device_queue_state(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason); - -gboolean nm_device_get_firmware_missing(NMDevice *self); - -void nm_device_disconnect_active_connection(NMActiveConnection * active, - NMDeviceStateReason device_reason, - NMActiveConnectionStateReason active_reason); - -void nm_device_queue_activation(NMDevice *device, NMActRequest *req); - -gboolean nm_device_supports_vlans(NMDevice *device); - -gboolean -nm_device_add_pending_action(NMDevice *device, const char *action, gboolean assert_not_yet_pending); -gboolean -nm_device_remove_pending_action(NMDevice *device, const char *action, gboolean assert_is_pending); -const char *nm_device_has_pending_action_reason(NMDevice *device); - -static inline gboolean -nm_device_has_pending_action(NMDevice *device) -{ - return !!nm_device_has_pending_action_reason(device); -} - -NMSettingsConnection * -nm_device_get_best_connection(NMDevice *device, const char *specific_object, GError **error); - -gboolean nm_device_check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error); - -void nm_device_notify_availability_maybe_changed(NMDevice *self); - -gboolean nm_device_owns_iface(NMDevice *device, const char *iface); - -NMConnection *nm_device_new_default_connection(NMDevice *self); - -const NMPObject *nm_device_get_best_default_route(NMDevice *self, int addr_family); - -void nm_device_spawn_iface_helper(NMDevice *self); - -gboolean nm_device_reapply(NMDevice *self, NMConnection *connection, GError **error); -void nm_device_reapply_settings_immediately(NMDevice *self); - -void nm_device_update_firewall_zone(NMDevice *self); -void nm_device_update_metered(NMDevice *self); -void nm_device_reactivate_ip4_config(NMDevice * device, - NMSettingIPConfig *s_ip4_old, - NMSettingIPConfig *s_ip4_new); -void nm_device_reactivate_ip6_config(NMDevice * device, - NMSettingIPConfig *s_ip6_old, - NMSettingIPConfig *s_ip6_new); - -gboolean nm_device_update_hw_address(NMDevice *self); -void nm_device_update_initial_hw_address(NMDevice *self); -void nm_device_update_permanent_hw_address(NMDevice *self, gboolean force_freeze); -void nm_device_update_dynamic_ip_setup(NMDevice *self); -guint nm_device_get_supplicant_timeout(NMDevice *self); - -gboolean nm_device_auth_retries_try_next(NMDevice *self); - -gboolean nm_device_hw_addr_get_cloned(NMDevice * self, - NMConnection *connection, - gboolean is_wifi, - char ** hwaddr, - gboolean * preserve, - GError ** error); - -typedef struct _NMDeviceConnectivityHandle NMDeviceConnectivityHandle; - -typedef void (*NMDeviceConnectivityCallback)(NMDevice * self, - NMDeviceConnectivityHandle *handle, - NMConnectivityState state, - GError * error, - gpointer user_data); - -void nm_device_check_connectivity_update_interval(NMDevice *self); - -NMDeviceConnectivityHandle *nm_device_check_connectivity(NMDevice * self, - int addr_family, - NMDeviceConnectivityCallback callback, - gpointer user_data); - -void nm_device_check_connectivity_cancel(NMDeviceConnectivityHandle *handle); - -NMConnectivityState nm_device_get_connectivity_state(NMDevice *self, int addr_family); - -typedef struct _NMBtVTableNetworkServer NMBtVTableNetworkServer; - -typedef void (*NMBtVTableRegisterCallback)(GError *error, gpointer user_data); - -struct _NMBtVTableNetworkServer { - gboolean (*is_available)(const NMBtVTableNetworkServer *vtable, - const char * addr, - NMDevice * device_accept_busy); - - gboolean (*register_bridge)(const NMBtVTableNetworkServer *vtable, - const char * addr, - NMDevice * device, - GCancellable * cancellable, - NMBtVTableRegisterCallback callback, - gpointer callback_user_data, - GError ** error); - gboolean (*unregister_bridge)(const NMBtVTableNetworkServer *vtable, NMDevice *device); -}; - -const char *nm_device_state_to_str(NMDeviceState state); -const char *nm_device_state_reason_to_str(NMDeviceStateReason reason); - -gboolean nm_device_is_vpn(NMDevice *self); - -#endif /* __NETWORKMANAGER_DEVICE_H__ */ diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c deleted file mode 100644 index 25d863c8..00000000 --- a/src/devices/nm-lldp-listener.c +++ /dev/null @@ -1,1122 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-lldp-listener.h" - -#include <net/ethernet.h> - -#include "nm-std-aux/unaligned.h" -#include "platform/nm-platform.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-utils.h" - -#include "systemd/nm-sd.h" - -#define MAX_NEIGHBORS 128 -#define MIN_UPDATE_INTERVAL_NSEC (2 * NM_UTILS_NSEC_PER_SEC) - -#define LLDP_MAC_NEAREST_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e}})) -#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x03}})) -#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE \ - (&((struct ether_addr){.ether_addr_octet = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}})) - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMLldpListener, PROP_NEIGHBORS, ); - -typedef struct { - sd_lldp * lldp_handle; - GHashTable *lldp_neighbors; - GVariant * variant; - - /* the timestamp in nsec until which we delay updates. */ - gint64 ratelimit_next_nsec; - guint ratelimit_id; - - int ifindex; -} NMLldpListenerPrivate; - -struct _NMLldpListener { - GObject parent; - NMLldpListenerPrivate _priv; -}; - -struct _NMLldpListenerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMLldpListener, nm_lldp_listener, G_TYPE_OBJECT) - -#define NM_LLDP_LISTENER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMLldpListener, NM_IS_LLDP_LISTENER) - -/*****************************************************************************/ - -typedef struct { - GVariant * variant; - sd_lldp_neighbor *neighbor_sd; - char * chassis_id; - char * port_id; - guint8 chassis_id_type; - guint8 port_id_type; -} LldpNeighbor; - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "lldp" -#define _NMLOG_DOMAIN LOGD_DEVICE -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - \ - if (nm_logging_enabled(_level, _NMLOG_DOMAIN)) { \ - char _sbuf[64]; \ - int _ifindex = (self) ? NM_LLDP_LISTENER_GET_PRIVATE(self)->ifindex : 0; \ - \ - _nm_log(_level, \ - _NMLOG_DOMAIN, \ - 0, \ - _ifindex > 0 ? nm_platform_link_get_name(NM_PLATFORM_GET, _ifindex) : NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - ((_ifindex > 0) ? nm_sprintf_buf(_sbuf, "[%p,%d]", (self), _ifindex) \ - : ((self) ? nm_sprintf_buf(_sbuf, "[%p]", (self)) : "")) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -#define LOG_NEIGH_FMT "CHASSIS=%u/%s PORT=%u/%s" -#define LOG_NEIGH_ARG(neigh) \ - (neigh)->chassis_id_type, (neigh)->chassis_id, (neigh)->port_id_type, (neigh)->port_id - -/*****************************************************************************/ - -static void -lldp_neighbor_get_raw(LldpNeighbor *neigh, const guint8 **out_raw_data, gsize *out_raw_len) -{ - gconstpointer raw_data; - gsize raw_len; - int r; - - nm_assert(neigh); - - r = sd_lldp_neighbor_get_raw(neigh->neighbor_sd, &raw_data, &raw_len); - - nm_assert(r >= 0); - nm_assert(raw_data); - nm_assert(raw_len > 0); - - *out_raw_data = raw_data; - *out_raw_len = raw_len; -} - -static gboolean -lldp_neighbor_id_get(struct sd_lldp_neighbor *neighbor_sd, - guint8 * out_chassis_id_type, - const guint8 ** out_chassis_id, - gsize * out_chassis_id_len, - guint8 * out_port_id_type, - const guint8 ** out_port_id, - gsize * out_port_id_len) -{ - int r; - - r = sd_lldp_neighbor_get_chassis_id(neighbor_sd, - out_chassis_id_type, - (gconstpointer *) out_chassis_id, - out_chassis_id_len); - if (r < 0) - return FALSE; - - r = sd_lldp_neighbor_get_port_id(neighbor_sd, - out_port_id_type, - (gconstpointer *) out_port_id, - out_port_id_len); - if (r < 0) - return FALSE; - - return TRUE; -} - -static guint -lldp_neighbor_id_hash(gconstpointer ptr) -{ - const LldpNeighbor *neigh = ptr; - guint8 chassis_id_type; - guint8 port_id_type; - const guint8 * chassis_id; - const guint8 * port_id; - gsize chassis_id_len; - gsize port_id_len; - NMHashState h; - - if (!lldp_neighbor_id_get(neigh->neighbor_sd, - &chassis_id_type, - &chassis_id, - &chassis_id_len, - &port_id_type, - &port_id, - &port_id_len)) { - nm_assert_not_reached(); - return 0; - } - - nm_hash_init(&h, 23423423u); - nm_hash_update_vals(&h, chassis_id_len, port_id_len, chassis_id_type, port_id_type); - nm_hash_update(&h, chassis_id, chassis_id_len); - nm_hash_update(&h, port_id, port_id_len); - return nm_hash_complete(&h); -} - -static int -lldp_neighbor_id_cmp(const LldpNeighbor *a, const LldpNeighbor *b) -{ - guint8 a_chassis_id_type; - guint8 b_chassis_id_type; - guint8 a_port_id_type; - guint8 b_port_id_type; - const guint8 *a_chassis_id; - const guint8 *b_chassis_id; - const guint8 *a_port_id; - const guint8 *b_port_id; - gsize a_chassis_id_len; - gsize b_chassis_id_len; - gsize a_port_id_len; - gsize b_port_id_len; - - NM_CMP_SELF(a, b); - - if (!lldp_neighbor_id_get(a->neighbor_sd, - &a_chassis_id_type, - &a_chassis_id, - &a_chassis_id_len, - &a_port_id_type, - &a_port_id, - &a_port_id_len)) { - nm_assert_not_reached(); - return FALSE; - } - - if (!lldp_neighbor_id_get(b->neighbor_sd, - &b_chassis_id_type, - &b_chassis_id, - &b_chassis_id_len, - &b_port_id_type, - &b_port_id, - &b_port_id_len)) { - nm_assert_not_reached(); - return FALSE; - } - - NM_CMP_DIRECT(a_chassis_id_type, b_chassis_id_type); - NM_CMP_DIRECT(a_port_id_type, b_port_id_type); - NM_CMP_DIRECT(a_chassis_id_len, b_chassis_id_len); - NM_CMP_DIRECT(a_port_id_len, b_port_id_len); - NM_CMP_DIRECT_MEMCMP(a_chassis_id, b_chassis_id, a_chassis_id_len); - NM_CMP_DIRECT_MEMCMP(a_port_id, b_port_id, a_port_id_len); - return 0; -} - -static int -lldp_neighbor_id_cmp_p(gconstpointer a, gconstpointer b, gpointer user_data) -{ - return lldp_neighbor_id_cmp(*((const LldpNeighbor *const *) a), - *((const LldpNeighbor *const *) b)); -} - -static gboolean -lldp_neighbor_id_equal(gconstpointer a, gconstpointer b) -{ - return lldp_neighbor_id_cmp(a, b) == 0; -} - -static void -lldp_neighbor_free(LldpNeighbor *neighbor) -{ - if (!neighbor) - return; - - g_free(neighbor->chassis_id); - g_free(neighbor->port_id); - nm_g_variant_unref(neighbor->variant); - sd_lldp_neighbor_unref(neighbor->neighbor_sd); - nm_g_slice_free(neighbor); -} - -static void -lldp_neighbor_freep(LldpNeighbor **ptr) -{ - lldp_neighbor_free(*ptr); -} - -static gboolean -lldp_neighbor_equal(LldpNeighbor *a, LldpNeighbor *b) -{ - const guint8 *raw_data_a; - const guint8 *raw_data_b; - gsize raw_len_a; - gsize raw_len_b; - - if (a->neighbor_sd == b->neighbor_sd) - return TRUE; - - lldp_neighbor_get_raw(a, &raw_data_a, &raw_len_a); - lldp_neighbor_get_raw(b, &raw_data_b, &raw_len_b); - return raw_len_a == raw_len_b && (memcmp(raw_data_a, raw_data_b, raw_len_a) == 0); -} - -static GVariant * -parse_management_address_tlv(const uint8_t *data, gsize len) -{ - GVariantBuilder builder; - gsize addr_len; - const guint8 * v_object_id_arr; - gsize v_object_id_len; - const guint8 * v_address_arr; - gsize v_address_len; - guint32 v_interface_number; - guint32 v_interface_number_subtype; - guint32 v_address_subtype; - - /* 802.1AB-2009 - Figure 8-11 - * - * - TLV type / length (2 bytes) - * - address string length (1 byte) - * - address subtype (1 byte) - * - address (1 to 31 bytes) - * - interface number subtype (1 byte) - * - interface number (4 bytes) - * - OID string length (1 byte) - * - OID (0 to 128 bytes) - */ - - if (len < 11) - return NULL; - - nm_assert((data[0] >> 1) == SD_LLDP_TYPE_MGMT_ADDRESS); - nm_assert((((data[0] & 1) << 8) + data[1]) + 2 == len); - - data += 2; - len -= 2; - addr_len = *data; /* length of (address subtype + address) */ - - if (addr_len < 2 || addr_len > 32) - return NULL; - if (len < (1 /* address stringth length */ - + addr_len /* address subtype + address */ - + 5 /* interface */ - + 1)) /* oid */ - return NULL; - - data++; - len--; - v_address_subtype = *data; - v_address_arr = &data[1]; - v_address_len = addr_len - 1; - - data += addr_len; - len -= addr_len; - v_interface_number_subtype = *data; - - data++; - len--; - v_interface_number = unaligned_read_be32(data); - - data += 4; - len -= 4; - v_object_id_len = *data; - if (len < (1 + v_object_id_len)) - return NULL; - data++; - v_object_id_arr = data; - - g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); - nm_g_variant_builder_add_sv_uint32(&builder, "address-subtype", v_address_subtype); - nm_g_variant_builder_add_sv_bytearray(&builder, "address", v_address_arr, v_address_len); - nm_g_variant_builder_add_sv_uint32(&builder, - "interface-number-subtype", - v_interface_number_subtype); - nm_g_variant_builder_add_sv_uint32(&builder, "interface-number", v_interface_number); - if (v_object_id_len > 0) - nm_g_variant_builder_add_sv_bytearray(&builder, - "object-id", - v_object_id_arr, - v_object_id_len); - return g_variant_builder_end(&builder); -} - -static char * -format_network_address(const guint8 *data, gsize sz) -{ - NMIPAddr a; - int family; - - if (sz == 5 && data[0] == 1 /* LLDP_MGMT_ADDR_IP4 */) { - memcpy(&a, &data[1], sizeof(a.addr4)); - family = AF_INET; - } else if (sz == 17 && data[0] == 2 /* LLDP_MGMT_ADDR_IP6 */) { - memcpy(&a, &data[1], sizeof(a.addr6)); - family = AF_INET6; - } else - return NULL; - - return nm_utils_inet_ntop_dup(family, &a); -} - -static const char * -format_string(const guint8 *data, gsize len, gboolean allow_trim, char **out_to_free) -{ - gboolean is_null_terminated = FALSE; - - nm_assert(out_to_free && !*out_to_free); - - if (allow_trim) { - while (len > 0 && data[len - 1] == '\0') { - is_null_terminated = TRUE; - len--; - } - } - - if (len == 0) - return NULL; - - if (memchr(data, len, '\0')) - return NULL; - - return nm_utils_buf_utf8safe_escape(data, - is_null_terminated ? -1 : (gssize) len, - NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL - | NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_NON_ASCII, - out_to_free); -} - -static char * -format_string_cp(const guint8 *data, gsize len, gboolean allow_trim) -{ - char * s_free = NULL; - const char *s; - - s = format_string(data, len, allow_trim, &s_free); - nm_assert(!s_free || s == s_free); - return s ? (s_free ?: g_strdup(s)) : NULL; -} - -static LldpNeighbor * -lldp_neighbor_new(sd_lldp_neighbor *neighbor_sd) -{ - LldpNeighbor *neigh; - guint8 chassis_id_type; - guint8 port_id_type; - const guint8 *chassis_id; - const guint8 *port_id; - gsize chassis_id_len; - gsize port_id_len; - gs_free char *s_chassis_id = NULL; - gs_free char *s_port_id = NULL; - - if (!lldp_neighbor_id_get(neighbor_sd, - &chassis_id_type, - &chassis_id, - &chassis_id_len, - &port_id_type, - &port_id, - &port_id_len)) - return NULL; - - switch (chassis_id_type) { - case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: - case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: - case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: - case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: - case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: - s_chassis_id = format_string_cp(chassis_id, chassis_id_len, FALSE); - break; - case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - s_chassis_id = nm_utils_hwaddr_ntoa(chassis_id, chassis_id_len); - break; - case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: - s_chassis_id = format_network_address(chassis_id, chassis_id_len); - break; - } - if (!s_chassis_id) { - /* Invalid/unsupported chassis_id? Expose as hex string. This format is not stable, and - * in the future we may add a better string representation for these case (thus - * changing the API). */ - s_chassis_id = nm_utils_bin2hexstr_full(chassis_id, chassis_id_len, '\0', FALSE, NULL); - } - - switch (port_id_type) { - case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: - s_port_id = format_string_cp(port_id, port_id_len, FALSE); - break; - case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS: - s_port_id = nm_utils_hwaddr_ntoa(port_id, port_id_len); - break; - case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: - s_port_id = format_network_address(port_id, port_id_len); - break; - } - if (!s_port_id) { - /* Invalid/unsupported port_id? Expose as hex string. This format is not stable, and - * in the future we may add a better string representation for these case (thus - * changing the API). */ - s_port_id = nm_utils_bin2hexstr_full(port_id, port_id_len, '\0', FALSE, NULL); - } - - neigh = g_slice_new(LldpNeighbor); - *neigh = (LldpNeighbor){ - .neighbor_sd = sd_lldp_neighbor_ref(neighbor_sd), - .chassis_id_type = chassis_id_type, - .chassis_id = g_steal_pointer(&s_chassis_id), - .port_id_type = port_id_type, - .port_id = g_steal_pointer(&s_port_id), - }; - return neigh; -} - -static GVariant * -lldp_neighbor_to_variant(LldpNeighbor *neigh) -{ - struct ether_addr destination_address; - GVariantBuilder builder; - const char * str; - const guint8 * raw_data; - gsize raw_len; - uint16_t u16; - uint8_t * data8; - gsize len; - int r; - - if (neigh->variant) - return neigh->variant; - - lldp_neighbor_get_raw(neigh, &raw_data, &raw_len); - - g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); - - nm_g_variant_builder_add_sv_bytearray(&builder, NM_LLDP_ATTR_RAW, raw_data, raw_len); - nm_g_variant_builder_add_sv_uint32(&builder, - NM_LLDP_ATTR_CHASSIS_ID_TYPE, - neigh->chassis_id_type); - nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_CHASSIS_ID, neigh->chassis_id); - nm_g_variant_builder_add_sv_uint32(&builder, NM_LLDP_ATTR_PORT_ID_TYPE, neigh->port_id_type); - nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_PORT_ID, neigh->port_id); - - r = sd_lldp_neighbor_get_destination_address(neigh->neighbor_sd, &destination_address); - if (r < 0) - str = NULL; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_BRIDGE)) - str = NM_LLDP_DEST_NEAREST_BRIDGE; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE)) - str = NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE; - else if (nm_utils_ether_addr_equal(&destination_address, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE)) - str = NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE; - else - str = NULL; - if (str) - nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_DESTINATION, str); - - if (sd_lldp_neighbor_get_port_description(neigh->neighbor_sd, &str) == 0) - nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_PORT_DESCRIPTION, str); - - if (sd_lldp_neighbor_get_system_name(neigh->neighbor_sd, &str) == 0) - nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_SYSTEM_NAME, str); - - if (sd_lldp_neighbor_get_system_description(neigh->neighbor_sd, &str) == 0) - nm_g_variant_builder_add_sv_str(&builder, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, str); - - if (sd_lldp_neighbor_get_system_capabilities(neigh->neighbor_sd, &u16) == 0) - nm_g_variant_builder_add_sv_uint32(&builder, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, u16); - - r = sd_lldp_neighbor_tlv_rewind(neigh->neighbor_sd); - if (r < 0) - nm_assert_not_reached(); - else { - gboolean v_management_addresses_has = FALSE; - GVariantBuilder v_management_addresses; - GVariant * v_ieee_802_1_pvid = NULL; - GVariant * v_ieee_802_1_ppvid = NULL; - GVariant * v_ieee_802_1_ppvid_flags = NULL; - GVariantBuilder v_ieee_802_1_ppvids; - GVariant * v_ieee_802_1_vid = NULL; - GVariant * v_ieee_802_1_vlan_name = NULL; - GVariantBuilder v_ieee_802_1_vlans; - GVariant * v_ieee_802_3_mac_phy_conf = NULL; - GVariant * v_ieee_802_3_power_via_mdi = NULL; - GVariant * v_ieee_802_3_max_frame_size = NULL; - GVariant * v_mud_url = NULL; - GVariantBuilder tmp_builder; - GVariant * tmp_variant; - - do { - guint8 oui[3]; - guint8 type; - guint8 subtype; - - if (sd_lldp_neighbor_tlv_get_type(neigh->neighbor_sd, &type) < 0) - continue; - - if (sd_lldp_neighbor_tlv_get_raw(neigh->neighbor_sd, (void *) &data8, &len) < 0) - continue; - - switch (type) { - case SD_LLDP_TYPE_MGMT_ADDRESS: - tmp_variant = parse_management_address_tlv(data8, len); - if (tmp_variant) { - if (!v_management_addresses_has) { - v_management_addresses_has = TRUE; - g_variant_builder_init(&v_management_addresses, G_VARIANT_TYPE("aa{sv}")); - } - g_variant_builder_add_value(&v_management_addresses, tmp_variant); - } - continue; - case SD_LLDP_TYPE_PRIVATE: - break; - default: - continue; - } - - r = sd_lldp_neighbor_tlv_get_oui(neigh->neighbor_sd, oui, &subtype); - if (r < 0) { - if (r == -ENXIO) - continue; - - /* in other cases, something is seriously wrong. Abort, but - * keep what we parsed so far. */ - break; - } - - if (len <= 6) - continue; - - /* skip over leading TLV, OUI and subtype */ -#if NM_MORE_ASSERTS > 5 - { - guint8 check_hdr[] = {0xfe | (((len - 2) >> 8) & 0x01), - ((len - 2) & 0xFF), - oui[0], - oui[1], - oui[2], - subtype}; - - nm_assert(len > 2 + 3 + 1); - nm_assert(memcmp(data8, check_hdr, sizeof check_hdr) == 0); - } -#endif - data8 += 6; - len -= 6; - - if (memcmp(oui, SD_LLDP_OUI_802_1, sizeof(oui)) == 0) { - switch (subtype) { - case SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID: - if (len != 2) - continue; - if (!v_ieee_802_1_pvid) - v_ieee_802_1_pvid = g_variant_new_uint32(unaligned_read_be16(data8)); - break; - case SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID: - if (len != 3) - continue; - if (!v_ieee_802_1_ppvid) { - v_ieee_802_1_ppvid_flags = g_variant_new_uint32(data8[0]); - v_ieee_802_1_ppvid = g_variant_new_uint32(unaligned_read_be16(&data8[1])); - g_variant_builder_init(&v_ieee_802_1_ppvids, G_VARIANT_TYPE("aa{sv}")); - } - g_variant_builder_init(&tmp_builder, G_VARIANT_TYPE("a{sv}")); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, - "ppvid", - unaligned_read_be16(&data8[1])); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, "flags", data8[0]); - g_variant_builder_add_value(&v_ieee_802_1_ppvids, - g_variant_builder_end(&tmp_builder)); - break; - case SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME: - { - gs_free char *name_to_free = NULL; - const char * name; - guint32 vid; - gsize l; - - if (len <= 3) - continue; - - l = data8[2]; - if (len != 3 + l) - continue; - if (l > 32) - continue; - - name = format_string(&data8[3], l, TRUE, &name_to_free); - if (!name) - continue; - - vid = unaligned_read_be16(&data8[0]); - if (!v_ieee_802_1_vid) { - v_ieee_802_1_vid = g_variant_new_uint32(vid); - v_ieee_802_1_vlan_name = g_variant_new_string(name); - g_variant_builder_init(&v_ieee_802_1_vlans, G_VARIANT_TYPE("aa{sv}")); - } - g_variant_builder_init(&tmp_builder, G_VARIANT_TYPE("a{sv}")); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, "vid", vid); - nm_g_variant_builder_add_sv_str(&tmp_builder, "name", name); - g_variant_builder_add_value(&v_ieee_802_1_vlans, - g_variant_builder_end(&tmp_builder)); - break; - } - default: - continue; - } - } else if (memcmp(oui, SD_LLDP_OUI_802_3, sizeof(oui)) == 0) { - switch (subtype) { - case SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS: - if (len != 5) - continue; - - if (!v_ieee_802_3_mac_phy_conf) { - g_variant_builder_init(&tmp_builder, G_VARIANT_TYPE("a{sv}")); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, "autoneg", data8[0]); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, - "pmd-autoneg-cap", - unaligned_read_be16(&data8[1])); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, - "operational-mau-type", - unaligned_read_be16(&data8[3])); - v_ieee_802_3_mac_phy_conf = g_variant_builder_end(&tmp_builder); - } - break; - case SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI: - if (len != 3) - continue; - - if (!v_ieee_802_3_power_via_mdi) { - g_variant_builder_init(&tmp_builder, G_VARIANT_TYPE("a{sv}")); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, - "mdi-power-support", - data8[0]); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, - "pse-power-pair", - data8[1]); - nm_g_variant_builder_add_sv_uint32(&tmp_builder, "power-class", data8[2]); - v_ieee_802_3_power_via_mdi = g_variant_builder_end(&tmp_builder); - } - break; - case SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE: - if (len != 2) - continue; - if (!v_ieee_802_3_max_frame_size) - v_ieee_802_3_max_frame_size = - g_variant_new_uint32(unaligned_read_be16(data8)); - break; - } - } else if (memcmp(oui, SD_LLDP_OUI_MUD, sizeof(oui)) == 0) { - switch (subtype) { - case SD_LLDP_OUI_SUBTYPE_MUD_USAGE_DESCRIPTION: - if (!v_mud_url) { - gs_free char *s_free = NULL; - const char * s; - - s = format_string(data8, len, TRUE, &s_free); - if (s) - v_mud_url = g_variant_new_string(s); - } - break; - } - } - } while (sd_lldp_neighbor_tlv_next(neigh->neighbor_sd) > 0); - - if (v_management_addresses_has) - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_MANAGEMENT_ADDRESSES, - g_variant_builder_end(&v_management_addresses)); - if (v_ieee_802_1_pvid) - nm_g_variant_builder_add_sv(&builder, NM_LLDP_ATTR_IEEE_802_1_PVID, v_ieee_802_1_pvid); - if (v_ieee_802_1_ppvid) { - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_IEEE_802_1_PPVID, - v_ieee_802_1_ppvid); - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, - v_ieee_802_1_ppvid_flags); - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_IEEE_802_1_PPVIDS, - g_variant_builder_end(&v_ieee_802_1_ppvids)); - } - if (v_ieee_802_1_vid) { - nm_g_variant_builder_add_sv(&builder, NM_LLDP_ATTR_IEEE_802_1_VID, v_ieee_802_1_vid); - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, - v_ieee_802_1_vlan_name); - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_IEEE_802_1_VLANS, - g_variant_builder_end(&v_ieee_802_1_vlans)); - } - if (v_ieee_802_3_mac_phy_conf) - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_IEEE_802_3_MAC_PHY_CONF, - v_ieee_802_3_mac_phy_conf); - if (v_ieee_802_3_power_via_mdi) - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_IEEE_802_3_POWER_VIA_MDI, - v_ieee_802_3_power_via_mdi); - if (v_ieee_802_3_max_frame_size) - nm_g_variant_builder_add_sv(&builder, - NM_LLDP_ATTR_IEEE_802_3_MAX_FRAME_SIZE, - v_ieee_802_3_max_frame_size); - if (v_mud_url) - nm_g_variant_builder_add_sv(&builder, NM_LLDP_ATTR_MUD_URL, v_mud_url); - } - - return (neigh->variant = g_variant_ref_sink(g_variant_builder_end(&builder))); -} - -/*****************************************************************************/ - -GVariant * -nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len) -{ - nm_auto(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *neighbor_sd = NULL; - nm_auto(lldp_neighbor_freep) LldpNeighbor * neigh = NULL; - GVariant * variant; - int r; - - g_assert(raw_data); - g_assert(raw_len > 0); - - r = sd_lldp_neighbor_from_raw(&neighbor_sd, raw_data, raw_len); - g_assert(r >= 0); - - neigh = lldp_neighbor_new(neighbor_sd); - g_assert(neigh); - - variant = lldp_neighbor_to_variant(neigh); - g_assert(variant); - - return g_variant_ref(variant); -} - -/*****************************************************************************/ - -static void -data_changed_notify(NMLldpListener *self, NMLldpListenerPrivate *priv) -{ - nm_clear_g_variant(&priv->variant); - _notify(self, PROP_NEIGHBORS); -} - -static gboolean -data_changed_timeout(gpointer user_data) -{ - NMLldpListener * self = user_data; - NMLldpListenerPrivate *priv; - - g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), G_SOURCE_REMOVE); - - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - priv->ratelimit_id = 0; - priv->ratelimit_next_nsec = nm_utils_get_monotonic_timestamp_nsec() + MIN_UPDATE_INTERVAL_NSEC; - data_changed_notify(self, priv); - return G_SOURCE_REMOVE; -} - -static void -data_changed_schedule(NMLldpListener *self) -{ - NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - gint64 now_nsec; - - if (priv->ratelimit_id != 0) - return; - - now_nsec = nm_utils_get_monotonic_timestamp_nsec(); - if (now_nsec < priv->ratelimit_next_nsec) { - priv->ratelimit_id = - g_timeout_add_full(G_PRIORITY_LOW, - NM_UTILS_NSEC_TO_MSEC_CEIL(priv->ratelimit_next_nsec - now_nsec), - data_changed_timeout, - self, - NULL); - return; - } - - priv->ratelimit_id = g_idle_add_full(G_PRIORITY_LOW, data_changed_timeout, self, NULL); -} - -static void -process_lldp_neighbor(NMLldpListener *self, sd_lldp_neighbor *neighbor_sd, gboolean remove) -{ - NMLldpListenerPrivate * priv; - nm_auto(lldp_neighbor_freep) LldpNeighbor *neigh = NULL; - LldpNeighbor * neigh_old; - - g_return_if_fail(NM_IS_LLDP_LISTENER(self)); - - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - g_return_if_fail(priv->lldp_handle); - g_return_if_fail(neighbor_sd); - - nm_assert(priv->lldp_neighbors); - - neigh = lldp_neighbor_new(neighbor_sd); - if (!neigh) { - _LOGT("process: failed to parse neighbor"); - return; - } - - neigh_old = g_hash_table_lookup(priv->lldp_neighbors, neigh); - - if (remove) { - if (neigh_old) { - _LOGT("process: %s neigh: " LOG_NEIGH_FMT, "remove", LOG_NEIGH_ARG(neigh)); - - g_hash_table_remove(priv->lldp_neighbors, neigh_old); - goto handle_changed; - } - return; - } - - if (neigh_old && lldp_neighbor_equal(neigh_old, neigh)) - return; - - _LOGD("process: %s neigh: " LOG_NEIGH_FMT, neigh_old ? "update" : "new", LOG_NEIGH_ARG(neigh)); - - g_hash_table_add(priv->lldp_neighbors, g_steal_pointer(&neigh)); - -handle_changed: - data_changed_schedule(self); -} - -static void -lldp_event_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) -{ - process_lldp_neighbor( - userdata, - n, - !NM_IN_SET(event, SD_LLDP_EVENT_ADDED, SD_LLDP_EVENT_UPDATED, SD_LLDP_EVENT_REFRESHED)); -} - -gboolean -nm_lldp_listener_start(NMLldpListener *self, int ifindex, GError **error) -{ - NMLldpListenerPrivate *priv; - int ret; - - g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), FALSE); - g_return_val_if_fail(ifindex > 0, FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - if (priv->lldp_handle) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "already running"); - return FALSE; - } - - ret = sd_lldp_new(&priv->lldp_handle); - if (ret < 0) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "initialization failed"); - return FALSE; - } - - ret = sd_lldp_set_ifindex(priv->lldp_handle, ifindex); - if (ret < 0) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "failed setting ifindex"); - goto err; - } - - ret = sd_lldp_set_callback(priv->lldp_handle, lldp_event_handler, self); - if (ret < 0) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "set callback failed"); - goto err; - } - - ret = sd_lldp_set_neighbors_max(priv->lldp_handle, MAX_NEIGHBORS); - nm_assert(ret == 0); - - priv->ifindex = ifindex; - - ret = sd_lldp_attach_event(priv->lldp_handle, NULL, 0); - if (ret < 0) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "attach event failed"); - goto err_free; - } - - ret = sd_lldp_start(priv->lldp_handle); - if (ret < 0) { - g_set_error_literal(error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, "start failed"); - goto err; - } - - priv->lldp_neighbors = g_hash_table_new_full(lldp_neighbor_id_hash, - lldp_neighbor_id_equal, - (GDestroyNotify) lldp_neighbor_free, - NULL); - - _LOGD("start"); - - return TRUE; - -err: - sd_lldp_detach_event(priv->lldp_handle); -err_free: - sd_lldp_unref(priv->lldp_handle); - priv->lldp_handle = NULL; - priv->ifindex = 0; - return FALSE; -} - -void -nm_lldp_listener_stop(NMLldpListener *self) -{ - NMLldpListenerPrivate *priv; - guint size; - gboolean changed = FALSE; - - g_return_if_fail(NM_IS_LLDP_LISTENER(self)); - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - if (priv->lldp_handle) { - _LOGD("stop"); - sd_lldp_stop(priv->lldp_handle); - sd_lldp_detach_event(priv->lldp_handle); - sd_lldp_unref(priv->lldp_handle); - priv->lldp_handle = NULL; - - size = g_hash_table_size(priv->lldp_neighbors); - g_hash_table_remove_all(priv->lldp_neighbors); - nm_clear_pointer(&priv->lldp_neighbors, g_hash_table_unref); - if (size > 0 || priv->ratelimit_id != 0) - changed = TRUE; - } - - nm_clear_g_source(&priv->ratelimit_id); - priv->ratelimit_next_nsec = 0; - priv->ifindex = 0; - - if (changed) - data_changed_notify(self, priv); -} - -gboolean -nm_lldp_listener_is_running(NMLldpListener *self) -{ - NMLldpListenerPrivate *priv; - - g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), FALSE); - - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - return !!priv->lldp_handle; -} - -GVariant * -nm_lldp_listener_get_neighbors(NMLldpListener *self) -{ - NMLldpListenerPrivate *priv; - - g_return_val_if_fail(NM_IS_LLDP_LISTENER(self), FALSE); - - priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - if (G_UNLIKELY(!priv->variant)) { - gs_free LldpNeighbor **neighbors = NULL; - GVariantBuilder array_builder; - guint i, n; - - g_variant_builder_init(&array_builder, G_VARIANT_TYPE("aa{sv}")); - neighbors = (LldpNeighbor **) - nm_utils_hash_keys_to_array(priv->lldp_neighbors, lldp_neighbor_id_cmp_p, NULL, &n); - for (i = 0; i < n; i++) - g_variant_builder_add_value(&array_builder, lldp_neighbor_to_variant(neighbors[i])); - priv->variant = g_variant_ref_sink(g_variant_builder_end(&array_builder)); - } - return priv->variant; -} - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMLldpListener *self = NM_LLDP_LISTENER(object); - - switch (prop_id) { - case PROP_NEIGHBORS: - g_value_set_variant(value, nm_lldp_listener_get_neighbors(self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -nm_lldp_listener_init(NMLldpListener *self) -{ - _LOGT("lldp listener created"); -} - -NMLldpListener * -nm_lldp_listener_new(void) -{ - return (NMLldpListener *) g_object_new(NM_TYPE_LLDP_LISTENER, NULL); -} - -static void -dispose(GObject *object) -{ - nm_lldp_listener_stop(NM_LLDP_LISTENER(object)); - - G_OBJECT_CLASS(nm_lldp_listener_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMLldpListener * self = NM_LLDP_LISTENER(object); - NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE(self); - - nm_lldp_listener_stop(self); - - nm_clear_g_variant(&priv->variant); - - _LOGT("lldp listener destroyed"); - - G_OBJECT_CLASS(nm_lldp_listener_parent_class)->finalize(object); -} - -static void -nm_lldp_listener_class_init(NMLldpListenerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->dispose = dispose; - object_class->finalize = finalize; - object_class->get_property = get_property; - - obj_properties[PROP_NEIGHBORS] = - g_param_spec_variant(NM_LLDP_LISTENER_NEIGHBORS, - "", - "", - G_VARIANT_TYPE("aa{sv}"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/nm-lldp-listener.h b/src/devices/nm-lldp-listener.h deleted file mode 100644 index 8c83cd67..00000000 --- a/src/devices/nm-lldp-listener.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#ifndef __NM_LLDP_LISTENER__ -#define __NM_LLDP_LISTENER__ - -#define NM_TYPE_LLDP_LISTENER (nm_lldp_listener_get_type()) -#define NM_LLDP_LISTENER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_LLDP_LISTENER, NMLldpListener)) -#define NM_LLDP_LISTENER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_LLDP_LISTENER, NMLldpListenerClass)) -#define NM_IS_LLDP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_LLDP_LISTENER)) -#define NM_IS_LLDP_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_LLDP_LISTENER)) -#define NM_LLDP_LISTENER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_LLDP_LISTENER, NMLldpListenerClass)) - -#define NM_LLDP_LISTENER_NEIGHBORS "neighbors" - -typedef struct _NMLldpListenerClass NMLldpListenerClass; - -GType nm_lldp_listener_get_type(void); -NMLldpListener *nm_lldp_listener_new(void); -gboolean nm_lldp_listener_start(NMLldpListener *self, int ifindex, GError **error); -void nm_lldp_listener_stop(NMLldpListener *self); -gboolean nm_lldp_listener_is_running(NMLldpListener *self); - -GVariant *nm_lldp_listener_get_neighbors(NMLldpListener *self); - -GVariant *nmtst_lldp_parse_from_raw(const guint8 *raw_data, gsize raw_len); - -#endif /* __NM_LLDP_LISTENER__ */ diff --git a/src/devices/ovs/meson.build b/src/devices/ovs/meson.build deleted file mode 100644 index 8457e68a..00000000 --- a/src/devices/ovs/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -sources = files( - 'nm-device-ovs-bridge.c', - 'nm-device-ovs-interface.c', - 'nm-device-ovs-port.c', - 'nm-ovsdb.c', - 'nm-ovs-factory.c', -) - -deps = [ - daemon_nm_default_dep, - jansson_dep, -] - -libnm_device_plugin_ovs = shared_module( - 'nm-device-plugin-ovs', - sources: sources, - dependencies: deps, - c_args: daemon_c_flags, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_plugindir, -) - -core_plugins += libnm_device_plugin_ovs - -test( - 'check-local-devices-ovs', - check_exports, - args: [libnm_device_plugin_ovs.full_path(), linker_script_devices], -) diff --git a/src/devices/ovs/nm-device-ovs-bridge.c b/src/devices/ovs/nm-device-ovs-bridge.c deleted file mode 100644 index a7b7a539..00000000 --- a/src/devices/ovs/nm-device-ovs-bridge.c +++ /dev/null @@ -1,125 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ovs-bridge.h" -#include "nm-device-ovs-port.h" -#include "nm-ovsdb.h" - -#include "devices/nm-device-private.h" -#include "nm-active-connection.h" -#include "nm-setting-connection.h" -#include "nm-setting-ovs-bridge.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceOvsBridge); - -/*****************************************************************************/ - -struct _NMDeviceOvsBridge { - NMDevice parent; -}; - -struct _NMDeviceOvsBridgeClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceOvsBridge, nm_device_ovs_bridge, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -static const char * -get_type_description(NMDevice *device) -{ - return "ovs-bridge"; -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - /* The actual backing resources will be created on enslavement by the port - * when it can identify the port and the bridge. */ - - return TRUE; -} - -static gboolean -unrealize(NMDevice *device, GError **error) -{ - return TRUE; -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - return NM_ACT_STAGE_RETURN_IP_FAIL; -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - if (!configure) - return TRUE; - - if (!NM_IS_DEVICE_OVS_PORT(slave)) - return FALSE; - - return TRUE; -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{} - -/*****************************************************************************/ - -static void -nm_device_ovs_bridge_init(NMDeviceOvsBridge *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_bridge = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_OVS_BRIDGE, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ovs_bridge_class_init(NMDeviceOvsBridgeClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_ovs_bridge); - - device_class->connection_type_supported = NM_SETTING_OVS_BRIDGE_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_OVS_BRIDGE_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(); - - device_class->is_master = TRUE; - device_class->get_type_description = get_type_description; - device_class->create_and_realize = create_and_realize; - device_class->unrealize = unrealize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; -} diff --git a/src/devices/ovs/nm-device-ovs-bridge.h b/src/devices/ovs/nm-device-ovs-bridge.h deleted file mode 100644 index ba04bfeb..00000000 --- a/src/devices/ovs/nm-device-ovs-bridge.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ -#define __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ - -#define NM_TYPE_DEVICE_OVS_BRIDGE (nm_device_ovs_bridge_get_type()) -#define NM_DEVICE_OVS_BRIDGE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridge)) -#define NM_DEVICE_OVS_BRIDGE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) -#define NM_IS_DEVICE_OVS_BRIDGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_BRIDGE)) -#define NM_IS_DEVICE_OVS_BRIDGE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_OVS_BRIDGE)) -#define NM_DEVICE_OVS_BRIDGE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_OVS_BRIDGE, NMDeviceOvsBridgeClass)) - -typedef struct _NMDeviceOvsBridge NMDeviceOvsBridge; -typedef struct _NMDeviceOvsBridgeClass NMDeviceOvsBridgeClass; - -GType nm_device_ovs_bridge_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_OVS_BRIDGE_H__ */ diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c deleted file mode 100644 index 16b6e04d..00000000 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ /dev/null @@ -1,398 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ovs-interface.h" -#include "nm-ovsdb.h" - -#include "devices/nm-device-private.h" -#include "nm-active-connection.h" -#include "nm-setting-connection.h" -#include "nm-setting-ovs-interface.h" -#include "nm-setting-ovs-port.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceOvsInterface); - -/*****************************************************************************/ - -typedef struct { - bool waiting_for_interface : 1; -} NMDeviceOvsInterfacePrivate; - -struct _NMDeviceOvsInterface { - NMDevice parent; - NMDeviceOvsInterfacePrivate _priv; -}; - -struct _NMDeviceOvsInterfaceClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceOvsInterface, nm_device_ovs_interface, NM_TYPE_DEVICE) - -#define NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceOvsInterface, NM_IS_DEVICE_OVS_INTERFACE, NMDevice) - -/*****************************************************************************/ - -static const char * -get_type_description(NMDevice *device) -{ - return "ovs-interface"; -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - /* The actual backing resources will be created once an interface is - * added to a port of ours, since there can be neither an empty port nor - * an empty bridge. */ - - return TRUE; -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - return TRUE; -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingOvsInterface *s_ovs_iface; - - if (!NM_DEVICE_CLASS(nm_device_ovs_interface_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_ovs_iface = nm_connection_get_setting_ovs_interface(connection); - - if (!NM_IN_STRSET(nm_setting_ovs_interface_get_interface_type(s_ovs_iface), - "dpdk", - "internal", - "patch")) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "unsupported OVS interface type in profile"); - return FALSE; - } - - return TRUE; -} - -static void -link_changed(NMDevice *device, const NMPlatformLink *pllink) -{ - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(device); - - if (!pllink || !priv->waiting_for_interface) - return; - - priv->waiting_for_interface = FALSE; - - if (nm_device_get_state(device) == NM_DEVICE_STATE_IP_CONFIG) { - if (!nm_device_hw_addr_set_cloned(device, - nm_device_get_applied_connection(device), - FALSE)) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - nm_device_bring_up(device, TRUE, NULL); - nm_device_activate_schedule_stage3_ip_config_start(device); - } -} - -static gboolean -_is_internal_interface(NMDevice *device) -{ - NMSettingOvsInterface *s_ovs_iface; - - s_ovs_iface = nm_device_get_applied_setting(device, NM_TYPE_SETTING_OVS_INTERFACE); - - g_return_val_if_fail(s_ovs_iface, FALSE); - - return nm_streq(nm_setting_ovs_interface_get_interface_type(s_ovs_iface), "internal"); -} - -static void -set_platform_mtu_cb(GError *error, gpointer user_data) -{ - NMDevice * device = user_data; - NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); - - if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) { - _LOGW(LOGD_DEVICE, - "could not change mtu of '%s': %s", - nm_device_get_iface(device), - error->message); - } - - g_object_unref(device); -} - -static gboolean -set_platform_mtu(NMDevice *device, guint32 mtu) -{ - /* - * If the MTU is not set in ovsdb, Open vSwitch will change - * the MTU of an internal interface to match the minimum of - * the other interfaces in the bridge. - */ - /* FIXME(shutdown): the function should become cancellable so - * that it doesn't need to hold a reference to the device, and - * it can be stopped during shutdown. - */ - if (_is_internal_interface(device)) { - nm_ovsdb_set_interface_mtu(nm_ovsdb_get(), - nm_device_get_ip_iface(device), - mtu, - set_platform_mtu_cb, - g_object_ref(device)); - } - - return NM_DEVICE_CLASS(nm_device_ovs_interface_parent_class)->set_platform_mtu(device, mtu); -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(device); - - if (!_is_internal_interface(device)) - return NM_ACT_STAGE_RETURN_IP_FAIL; - - if (nm_device_get_ip_ifindex(device) <= 0) { - _LOGT(LOGD_DEVICE, "waiting for link to appear"); - priv->waiting_for_interface = TRUE; - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (!nm_device_hw_addr_set_cloned(device, nm_device_get_applied_connection(device), FALSE)) { - *out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_DEVICE_CLASS(nm_device_ovs_interface_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static gboolean -can_unmanaged_external_down(NMDevice *self) -{ - return FALSE; -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - - priv->waiting_for_interface = FALSE; -} - -typedef struct { - NMDeviceOvsInterface * self; - GCancellable * cancellable; - NMDeviceDeactivateCallback callback; - gpointer callback_user_data; - gulong link_changed_id; - gulong cancelled_id; - guint link_timeout_id; -} DeactivateData; - -static void -deactivate_invoke_cb(DeactivateData *data, GError *error) -{ - NMDeviceOvsInterface *self = data->self; - - _LOGT(LOGD_CORE, "deactivate: async callback (%s)", error ? error->message : "success"); - data->callback(NM_DEVICE(data->self), error, data->callback_user_data); - - nm_clear_g_signal_handler(nm_device_get_platform(NM_DEVICE(data->self)), - &data->link_changed_id); - nm_clear_g_signal_handler(data->cancellable, &data->cancelled_id); - nm_clear_g_source(&data->link_timeout_id); - g_object_unref(data->self); - g_object_unref(data->cancellable); - nm_g_slice_free(data); -} - -static void -deactivate_link_changed_cb(NMPlatform * platform, - int obj_type_i, - int ifindex, - NMPlatformLink *info, - int change_type_i, - DeactivateData *data) -{ - NMDeviceOvsInterface * self = data->self; - const NMPlatformSignalChangeType change_type = change_type_i; - - if (change_type == NM_PLATFORM_SIGNAL_REMOVED - && nm_streq0(info->name, nm_device_get_iface(NM_DEVICE(self)))) { - _LOGT(LOGD_DEVICE, "deactivate: link removed, proceeding"); - nm_device_update_from_platform_link(NM_DEVICE(self), NULL); - deactivate_invoke_cb(data, NULL); - return; - } -} - -static gboolean -deactivate_link_timeout(gpointer user_data) -{ - DeactivateData * data = user_data; - NMDeviceOvsInterface *self = data->self; - - _LOGT(LOGD_DEVICE, "deactivate: timeout waiting link removal"); - deactivate_invoke_cb(data, NULL); - return G_SOURCE_REMOVE; -} - -static void -deactivate_cancelled_cb(GCancellable *cancellable, gpointer user_data) -{ - gs_free_error GError *error = NULL; - - nm_utils_error_set_cancelled(&error, FALSE, NULL); - deactivate_invoke_cb((DeactivateData *) user_data, error); -} - -static void -deactivate_cb_on_idle(gpointer user_data, GCancellable *cancellable) -{ - DeactivateData *data = user_data; - gs_free_error GError *cancelled_error = NULL; - - g_cancellable_set_error_if_cancelled(data->cancellable, &cancelled_error); - deactivate_invoke_cb(data, cancelled_error); -} - -static void -deactivate_async(NMDevice * device, - GCancellable * cancellable, - NMDeviceDeactivateCallback callback, - gpointer callback_user_data) -{ - NMDeviceOvsInterface * self = NM_DEVICE_OVS_INTERFACE(device); - NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - DeactivateData * data; - - _LOGT(LOGD_CORE, "deactivate: start async"); - - /* We want to ensure that the kernel link for this device is - * removed upon disconnection so that it will not interfere with - * later activations of the same device. Unfortunately there is - * no synchronization mechanism with vswitchd, we only update - * ovsdb and wait that changes are picked up. - */ - - data = g_slice_new(DeactivateData); - *data = (DeactivateData){ - .self = g_object_ref(self), - .cancellable = g_object_ref(cancellable), - .callback = callback, - .callback_user_data = callback_user_data, - }; - - if (!priv->waiting_for_interface - && !nm_platform_link_get_by_ifname(nm_device_get_platform(device), - nm_device_get_iface(device))) { - _LOGT(LOGD_CORE, "deactivate: link not present, proceeding"); - nm_device_update_from_platform_link(NM_DEVICE(self), NULL); - nm_utils_invoke_on_idle(cancellable, deactivate_cb_on_idle, data); - return; - } - - if (priv->waiting_for_interface) { - /* At this point we have issued an INSERT and a DELETE - * command for the interface to ovsdb. We don't know if - * vswitchd will see the two updates or only one. We - * must add a timeout to avoid waiting forever in case - * the link doesn't appear. - */ - data->link_timeout_id = g_timeout_add(6000, deactivate_link_timeout, data); - _LOGT(LOGD_DEVICE, "deactivate: waiting for link to disappear in 6 seconds"); - } else - _LOGT(LOGD_DEVICE, "deactivate: waiting for link to disappear"); - - data->cancelled_id = - g_cancellable_connect(cancellable, G_CALLBACK(deactivate_cancelled_cb), data, NULL); - data->link_changed_id = g_signal_connect(nm_device_get_platform(device), - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK(deactivate_link_changed_cb), - data); -} - -static gboolean -can_update_from_platform_link(NMDevice *device, const NMPlatformLink *plink) -{ - /* If the device is deactivating, we already sent the - * deletion command to ovsdb and we don't want to deal - * with any new link appearing from the previous - * activation. - */ - return !plink || nm_device_get_state(device) != NM_DEVICE_STATE_DEACTIVATING; -} - -/*****************************************************************************/ - -static void -nm_device_ovs_interface_init(NMDeviceOvsInterface *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_interface = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_OVS_INTERFACE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ovs_interface_class_init(NMDeviceOvsInterfaceClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = - NM_DBUS_INTERFACE_INFOS(&interface_info_device_ovs_interface); - - device_class->connection_type_supported = NM_SETTING_OVS_INTERFACE_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_OVS_INTERFACE_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_OPENVSWITCH); - - device_class->can_update_from_platform_link = can_update_from_platform_link; - device_class->deactivate = deactivate; - device_class->deactivate_async = deactivate_async; - device_class->get_type_description = get_type_description; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->is_available = is_available; - device_class->check_connection_compatible = check_connection_compatible; - device_class->link_changed = link_changed; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->can_unmanaged_external_down = can_unmanaged_external_down; - device_class->set_platform_mtu = set_platform_mtu; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; -} diff --git a/src/devices/ovs/nm-device-ovs-interface.h b/src/devices/ovs/nm-device-ovs-interface.h deleted file mode 100644 index 902847de..00000000 --- a/src/devices/ovs/nm-device-ovs-interface.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ -#define __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ - -#define NM_TYPE_DEVICE_OVS_INTERFACE (nm_device_ovs_interface_get_type()) -#define NM_DEVICE_OVS_INTERFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterface)) -#define NM_DEVICE_OVS_INTERFACE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) -#define NM_IS_DEVICE_OVS_INTERFACE(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_INTERFACE)) -#define NM_IS_DEVICE_OVS_INTERFACE_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_OVS_INTERFACE)) -#define NM_DEVICE_OVS_INTERFACE_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_OVS_INTERFACE, NMDeviceOvsInterfaceClass)) - -typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface; -typedef struct _NMDeviceOvsInterfaceClass NMDeviceOvsInterfaceClass; - -GType nm_device_ovs_interface_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_OVS_INTERFACE_H__ */ diff --git a/src/devices/ovs/nm-device-ovs-port.c b/src/devices/ovs/nm-device-ovs-port.c deleted file mode 100644 index de98e29e..00000000 --- a/src/devices/ovs/nm-device-ovs-port.c +++ /dev/null @@ -1,192 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-ovs-port.h" -#include "nm-device-ovs-interface.h" -#include "nm-ovsdb.h" - -#include "devices/nm-device-private.h" -#include "nm-active-connection.h" -#include "nm-setting-connection.h" -#include "nm-setting-ovs-port.h" -#include "nm-setting-ovs-port.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceOvsPort); - -/*****************************************************************************/ - -struct _NMDeviceOvsPort { - NMDevice parent; -}; - -struct _NMDeviceOvsPortClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceOvsPort, nm_device_ovs_port, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -static const char * -get_type_description(NMDevice *device) -{ - return "ovs-port"; -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - /* The port will be added to ovsdb when an interface is enslaved, - * because there's no such thing like an empty port. */ - - return TRUE; -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_SOFTWARE; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - return NM_ACT_STAGE_RETURN_IP_FAIL; -} - -static void -add_iface_cb(GError *error, gpointer user_data) -{ - NMDevice *slave = user_data; - - if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) { - nm_log_warn(LOGD_DEVICE, - "device %s could not be added to a ovs port: %s", - nm_device_get_iface(slave), - error->message); - nm_device_state_changed(slave, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED); - } - - g_object_unref(slave); -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - NMDeviceOvsPort * self = NM_DEVICE_OVS_PORT(device); - NMActiveConnection *ac_port = NULL; - NMActiveConnection *ac_bridge = NULL; - NMDevice * bridge_device; - - if (!configure) - return TRUE; - - ac_port = NM_ACTIVE_CONNECTION(nm_device_get_act_request(device)); - ac_bridge = nm_active_connection_get_master(ac_port); - if (!ac_bridge) { - _LOGW(LOGD_DEVICE, - "can't enslave %s: bridge active-connection not found", - nm_device_get_iface(slave)); - return FALSE; - } - - bridge_device = nm_active_connection_get_device(ac_bridge); - if (!bridge_device) { - _LOGW(LOGD_DEVICE, "can't enslave %s: bridge device not found", nm_device_get_iface(slave)); - return FALSE; - } - - nm_ovsdb_add_interface(nm_ovsdb_get(), - nm_active_connection_get_applied_connection(ac_bridge), - nm_device_get_applied_connection(device), - nm_device_get_applied_connection(slave), - bridge_device, - slave, - add_iface_cb, - g_object_ref(slave)); - - return TRUE; -} - -static void -del_iface_cb(GError *error, gpointer user_data) -{ - NMDevice *slave = user_data; - - if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) { - nm_log_warn(LOGD_DEVICE, - "device %s could not be removed from a ovs port: %s", - nm_device_get_iface(slave), - error->message); - nm_device_state_changed(slave, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED); - } - - g_object_unref(slave); -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{ - NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device); - - if (configure) { - _LOGI(LOGD_DEVICE, "releasing ovs interface %s", nm_device_get_ip_iface(slave)); - nm_ovsdb_del_interface(nm_ovsdb_get(), - nm_device_get_iface(slave), - del_iface_cb, - g_object_ref(slave)); - /* Open VSwitch is going to delete this one. We must ignore what happens - * next with the interface. */ - if (NM_IS_DEVICE_OVS_INTERFACE(slave)) - nm_device_update_from_platform_link(slave, NULL); - } else - _LOGI(LOGD_DEVICE, "ovs interface %s was released", nm_device_get_ip_iface(slave)); -} - -/*****************************************************************************/ - -static void -nm_device_ovs_port_init(NMDeviceOvsPort *self) -{} - -static const NMDBusInterfaceInfoExtended interface_info_device_ovs_port = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_OVS_PORT, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Slaves", "ao", NM_DEVICE_SLAVES), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_ovs_port_class_init(NMDeviceOvsPortClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_ovs_port); - - device_class->connection_type_supported = NM_SETTING_OVS_PORT_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_OVS_PORT_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(); - - device_class->is_master = TRUE; - device_class->get_type_description = get_type_description; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; -} diff --git a/src/devices/ovs/nm-device-ovs-port.h b/src/devices/ovs/nm-device-ovs-port.h deleted file mode 100644 index 3f5d7793..00000000 --- a/src/devices/ovs/nm-device-ovs-port.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_OVS_PORT_H__ -#define __NETWORKMANAGER_DEVICE_OVS_PORT_H__ - -#define NM_TYPE_DEVICE_OVS_PORT (nm_device_ovs_port_get_type()) -#define NM_DEVICE_OVS_PORT(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPort)) -#define NM_DEVICE_OVS_PORT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) -#define NM_IS_DEVICE_OVS_PORT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OVS_PORT)) -#define NM_IS_DEVICE_OVS_PORT_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_OVS_PORT)) -#define NM_DEVICE_OVS_PORT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_OVS_PORT, NMDeviceOvsPortClass)) - -typedef struct _NMDeviceOvsPort NMDeviceOvsPort; -typedef struct _NMDeviceOvsPortClass NMDeviceOvsPortClass; - -GType nm_device_ovs_port_get_type(void); - -#endif /* __NETWORKMANAGER_DEVICE_OVS_PORT_H__ */ diff --git a/src/devices/ovs/nm-ovs-factory.c b/src/devices/ovs/nm-ovs-factory.c deleted file mode 100644 index e1feacbd..00000000 --- a/src/devices/ovs/nm-ovs-factory.c +++ /dev/null @@ -1,269 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-manager.h" -#include "nm-ovsdb.h" -#include "nm-device-ovs-interface.h" -#include "nm-device-ovs-port.h" -#include "nm-device-ovs-bridge.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" -#include "settings/nm-settings.h" -#include "devices/nm-device-factory.h" -#include "devices/nm-device-private.h" - -/*****************************************************************************/ - -typedef struct { - NMDeviceFactory parent; -} NMOvsFactory; - -typedef struct { - NMDeviceFactoryClass parent; -} NMOvsFactoryClass; - -#define NM_TYPE_OVS_FACTORY (nm_ovs_factory_get_type()) -#define NM_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVS_FACTORY, NMOvsFactory)) -#define NM_OVS_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass)) -#define NM_IS_OVS_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVS_FACTORY)) -#define NM_IS_OVS_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_OVS_FACTORY)) -#define NM_OVS_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_OVS_FACTORY, NMOvsFactoryClass)) - -static GType nm_ovs_factory_get_type(void); -G_DEFINE_TYPE(NMOvsFactory, nm_ovs_factory, NM_TYPE_DEVICE_FACTORY) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_DEVICE -#define _NMLOG(level, ifname, con_uuid, ...) \ - G_STMT_START \ - { \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - (ifname), \ - (con_uuid), \ - "ovs: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES( - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_OPENVSWITCH) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_OVS_BRIDGE_SETTING_NAME, - NM_SETTING_OVS_INTERFACE_SETTING_NAME, - NM_SETTING_OVS_PORT_SETTING_NAME)) - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - nm_manager_set_capability(NM_MANAGER_GET, NM_CAPABILITY_OVS); - return (NMDeviceFactory *) g_object_new(NM_TYPE_OVS_FACTORY, NULL); -} - -static NMDevice * -new_device_from_type(const char *name, NMDeviceType device_type) -{ - GType type; - const char *type_desc; - NMLinkType link_type = NM_LINK_TYPE_NONE; - - if (nm_manager_get_device(NM_MANAGER_GET, name, device_type)) - return NULL; - - if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE) { - type = NM_TYPE_DEVICE_OVS_INTERFACE; - type_desc = "Open vSwitch Interface"; - link_type = NM_LINK_TYPE_OPENVSWITCH; - } else if (device_type == NM_DEVICE_TYPE_OVS_PORT) { - type = NM_TYPE_DEVICE_OVS_PORT; - type_desc = "Open vSwitch Port"; - } else if (device_type == NM_DEVICE_TYPE_OVS_BRIDGE) { - type = NM_TYPE_DEVICE_OVS_BRIDGE; - type_desc = "Open vSwitch Bridge"; - } else { - return NULL; - } - - return g_object_new(type, - NM_DEVICE_IFACE, - name, - NM_DEVICE_DRIVER, - "openvswitch", - NM_DEVICE_DEVICE_TYPE, - device_type, - NM_DEVICE_TYPE_DESC, - type_desc, - NM_DEVICE_LINK_TYPE, - link_type, - NULL); -} - -static void -ovsdb_device_added(NMOvsdb * ovsdb, - const char * name, - NMDeviceType device_type, - NMDeviceFactory *self) -{ - NMDevice *device = NULL; - - device = new_device_from_type(name, device_type); - if (!device) - return; - - g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); - g_object_unref(device); -} - -static void -ovsdb_device_removed(NMOvsdb * ovsdb, - const char * name, - NMDeviceType device_type, - NMDeviceFactory *self) -{ - NMDevice * device; - NMDeviceState device_state; - - device = nm_manager_get_device(NM_MANAGER_GET, name, device_type); - if (!device) - return; - - device_state = nm_device_get_state(device); - if (device_type == NM_DEVICE_TYPE_OVS_INTERFACE && device_state > NM_DEVICE_STATE_DISCONNECTED - && device_state < NM_DEVICE_STATE_DEACTIVATING) { - nm_device_state_changed(device, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED); - } else if (device_state == NM_DEVICE_STATE_UNMANAGED) { - nm_device_unrealize(device, TRUE, NULL); - } -} - -static void -ovsdb_interface_failed(NMOvsdb * ovsdb, - const char * name, - const char * connection_uuid, - const char * error, - NMDeviceFactory *self) -{ - NMDevice * device = NULL; - NMSettingsConnection * connection = NULL; - NMConnection * c; - const char * type; - NMSettingOvsInterface *s_ovs_int; - gboolean is_patch = FALSE; - gboolean ignore; - - device = nm_manager_get_device(NM_MANAGER_GET, name, NM_DEVICE_TYPE_OVS_INTERFACE); - if (device && connection_uuid) { - connection = - nm_settings_get_connection_by_uuid(nm_device_get_settings(device), connection_uuid); - } - - /* The patch interface which gets created first is expected to - * fail because the second patch doesn't exist yet. Ignore all - * failures of patch interfaces. */ - if (connection && (c = nm_settings_connection_get_connection(connection)) - && (type = nm_connection_get_connection_type(c)) - && nm_streq0(type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) - && (s_ovs_int = nm_connection_get_setting_ovs_interface(c)) - && nm_streq0(nm_setting_ovs_interface_get_interface_type(s_ovs_int), "patch")) - is_patch = TRUE; - - ignore = !device || is_patch; - - _NMLOG(ignore ? LOGL_DEBUG : LOGL_INFO, - name, - connection_uuid, - "ovs interface \"%s\" (%s) failed%s: %s", - name, - connection_uuid, - ignore ? " (ignored)" : "", - error); - - if (ignore) - return; - - if (connection) { - nm_settings_connection_autoconnect_blocked_reason_set( - connection, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, - TRUE); - } - - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED); -} - -static void -start(NMDeviceFactory *self) -{ - NMOvsdb *ovsdb; - - ovsdb = nm_ovsdb_get(); - - g_signal_connect_object(ovsdb, - NM_OVSDB_DEVICE_ADDED, - G_CALLBACK(ovsdb_device_added), - self, - (GConnectFlags) 0); - g_signal_connect_object(ovsdb, - NM_OVSDB_DEVICE_REMOVED, - G_CALLBACK(ovsdb_device_removed), - self, - (GConnectFlags) 0); - g_signal_connect_object(ovsdb, - NM_OVSDB_INTERFACE_FAILED, - G_CALLBACK(ovsdb_interface_failed), - self, - (GConnectFlags) 0); -} - -static NMDevice * -create_device(NMDeviceFactory * self, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - NMDeviceType device_type = NM_DEVICE_TYPE_UNKNOWN; - const char * connection_type = NULL; - - if (g_strcmp0(iface, "ovs-system") == 0) { - *out_ignore = TRUE; - return NULL; - } - - if (connection) - connection_type = nm_connection_get_connection_type(connection); - - if (plink) - device_type = NM_DEVICE_TYPE_OVS_INTERFACE; - else if (g_strcmp0(connection_type, NM_SETTING_OVS_INTERFACE_SETTING_NAME) == 0) - device_type = NM_DEVICE_TYPE_OVS_INTERFACE; - else if (g_strcmp0(connection_type, NM_SETTING_OVS_PORT_SETTING_NAME) == 0) - device_type = NM_DEVICE_TYPE_OVS_PORT; - else if (g_strcmp0(connection_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) == 0) - device_type = NM_DEVICE_TYPE_OVS_BRIDGE; - - return new_device_from_type(iface, device_type); -} - -static void -nm_ovs_factory_init(NMOvsFactory *self) -{} - -static void -nm_ovs_factory_class_init(NMOvsFactoryClass *klass) -{ - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - factory_class->get_supported_types = get_supported_types; - factory_class->start = start; - factory_class->create_device = create_device; -} diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c deleted file mode 100644 index 27ef789f..00000000 --- a/src/devices/ovs/nm-ovsdb.c +++ /dev/null @@ -1,2100 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-ovsdb.h" - -#include <gmodule.h> -#include <gio/gunixsocketaddress.h> - -#include "nm-glib-aux/nm-jansson.h" -#include "nm-core-utils.h" -#include "nm-core-internal.h" -#include "devices/nm-device.h" - -/*****************************************************************************/ - -#if JANSSON_VERSION_HEX < 0x020400 - #warning "requires at least libjansson 2.4" -#endif - -typedef struct { - char * name; - char * connection_uuid; - GPtrArray *interfaces; /* interface uuids */ -} OpenvswitchPort; - -typedef struct { - char * name; - char * connection_uuid; - GPtrArray *ports; /* port uuids */ -} OpenvswitchBridge; - -typedef struct { - char *name; - char *type; - char *connection_uuid; -} OpenvswitchInterface; - -/*****************************************************************************/ - -enum { DEVICE_ADDED, DEVICE_REMOVED, INTERFACE_FAILED, LAST_SIGNAL }; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct { - GSocketClient * client; - GSocketConnection *conn; - GCancellable * cancellable; - char buf[4096]; /* Input buffer */ - size_t bufp; /* Last decoded byte in the input buffer. */ - GString * input; /* JSON stream waiting for decoding. */ - GString * output; /* JSON stream to be sent. */ - gint64 seq; - GArray * calls; /* Method calls waiting for a response. */ - GHashTable * interfaces; /* interface uuid => OpenvswitchInterface */ - GHashTable * ports; /* port uuid => OpenvswitchPort */ - GHashTable * bridges; /* bridge uuid => OpenvswitchBridge */ - char * db_uuid; - guint num_failures; -} NMOvsdbPrivate; - -struct _NMOvsdb { - GObject parent; - NMOvsdbPrivate _priv; -}; - -struct _NMOvsdbClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMOvsdb, nm_ovsdb, G_TYPE_OBJECT) - -#define NM_OVSDB_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMOvsdb, NM_IS_OVSDB) - -#define _NMLOG_DOMAIN LOGD_DEVICE -#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "ovsdb", __VA_ARGS__) - -NM_DEFINE_SINGLETON_GETTER(NMOvsdb, nm_ovsdb_get, NM_TYPE_OVSDB); - -/*****************************************************************************/ - -static void ovsdb_try_connect(NMOvsdb *self); -static void ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing); -static void ovsdb_read(NMOvsdb *self); -static void ovsdb_write(NMOvsdb *self); -static void ovsdb_next_command(NMOvsdb *self); - -/*****************************************************************************/ - -/* ovsdb command abstraction. */ - -typedef void (*OvsdbMethodCallback)(NMOvsdb *self, - json_t * response, - GError * error, - gpointer user_data); - -typedef enum { - OVSDB_MONITOR, - OVSDB_ADD_INTERFACE, - OVSDB_DEL_INTERFACE, - OVSDB_SET_INTERFACE_MTU, -} OvsdbCommand; - -typedef struct { - gint64 id; -#define COMMAND_PENDING -1 /* id not yet assigned */ - OvsdbCommand command; - OvsdbMethodCallback callback; - gpointer user_data; - union { - struct { - char * ifname; - guint32 mtu; - }; - struct { - NMConnection *bridge; - NMConnection *port; - NMConnection *interface; - NMDevice * bridge_device; - NMDevice * interface_device; - }; - }; -} OvsdbMethodCall; - -#define OVSDB_MAX_FAILURES 3 - -static void -_LOGT_call_do(const char *comment, OvsdbMethodCall *call, json_t *msg) -{ - gs_free char *str = NULL; - - if (msg) - str = json_dumps(msg, 0); - - switch (call->command) { - case OVSDB_MONITOR: - _LOGT("%s: monitor%s%s", comment, msg ? ": " : "", msg ? str : ""); - break; - case OVSDB_ADD_INTERFACE: - _LOGT("%s: add-iface bridge=%s port=%s interface=%s%s%s", - comment, - nm_connection_get_interface_name(call->bridge), - nm_connection_get_interface_name(call->port), - nm_connection_get_interface_name(call->interface), - msg ? ": " : "", - msg ? str : ""); - break; - case OVSDB_DEL_INTERFACE: - _LOGT("%s: del-iface interface=%s%s%s", - comment, - call->ifname, - msg ? ": " : "", - msg ? str : ""); - break; - case OVSDB_SET_INTERFACE_MTU: - _LOGT("%s: set-iface-mtu interface=%s%s%s mtu=%u", - comment, - call->ifname, - msg ? ": " : "", - msg ? str : "", - call->mtu); - break; - } -} - -#define _LOGT_call(comment, call, message) \ - G_STMT_START \ - { \ - if (_LOGT_ENABLED()) \ - _LOGT_call_do((comment), (call), (message)); \ - } \ - G_STMT_END - -/** - * ovsdb_call_method: - * - * Queues the ovsdb command. Eventually fires the command right away if - * there's no command pending completion. - */ -static void -ovsdb_call_method(NMOvsdb * self, - OvsdbCommand command, - const char * ifname, - NMConnection * bridge, - NMConnection * port, - NMConnection * interface, - NMDevice * bridge_device, - NMDevice * interface_device, - guint32 mtu, - OvsdbMethodCallback callback, - gpointer user_data, - gboolean add_first) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - OvsdbMethodCall *call; - - /* Ensure we're not unsynchronized before we queue the method call. */ - ovsdb_try_connect(self); - - if (add_first) { - g_array_prepend_val(priv->calls, (OvsdbMethodCall){}); - call = &g_array_index(priv->calls, OvsdbMethodCall, 0); - } else { - g_array_set_size(priv->calls, priv->calls->len + 1); - call = &g_array_index(priv->calls, OvsdbMethodCall, priv->calls->len - 1); - } - call->id = COMMAND_PENDING; - call->command = command; - call->callback = callback; - call->user_data = user_data; - - switch (call->command) { - case OVSDB_MONITOR: - break; - case OVSDB_ADD_INTERFACE: - call->bridge = nm_simple_connection_new_clone(bridge); - call->port = nm_simple_connection_new_clone(port); - call->interface = nm_simple_connection_new_clone(interface); - call->bridge_device = g_object_ref(bridge_device); - call->interface_device = g_object_ref(interface_device); - break; - case OVSDB_DEL_INTERFACE: - call->ifname = g_strdup(ifname); - break; - case OVSDB_SET_INTERFACE_MTU: - call->ifname = g_strdup(ifname); - call->mtu = mtu; - break; - } - - _LOGT_call("enqueue", call, NULL); - - ovsdb_next_command(self); -} - -/*****************************************************************************/ - -/* Create and process the JSON-RPC messages from ovsdb. */ - -/** - * _expect_ovs_bridges: - * - * Return a command that will fail the transaction if the actual set of - * bridges doesn't match @bridges. This is a way of detecting race conditions - * with other ovsdb clients that might be adding or removing bridges - * at the same time. - */ -static void -_expect_ovs_bridges(json_t *params, const char *db_uuid, json_t *bridges) -{ - json_array_append_new( - params, - json_pack("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, [s, s]]]}", - "op", - "wait", - "table", - "Open_vSwitch", - "timeout", - 0, - "columns", - "bridges", - "until", - "==", - "rows", - "bridges", - "set", - bridges, - "where", - "_uuid", - "==", - "uuid", - db_uuid)); -} - -/** - * _set_ovs_bridges: - * - * Return a command that will update the list of bridges in @db_uuid - * database to @new_bridges. - */ -static void -_set_ovs_bridges(json_t *params, const char *db_uuid, json_t *new_bridges) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, [s, s]]]}", - "op", - "update", - "table", - "Open_vSwitch", - "row", - "bridges", - "set", - new_bridges, - "where", - "_uuid", - "==", - "uuid", - db_uuid)); -} - -/** - * _expect_bridge_ports: - * - * Return a command that will fail the transaction if the actual set of - * ports in bridge @ifname doesn't match @ports. This is a way of detecting - * race conditions with other ovsdb clients that might be adding or removing - * bridge ports at the same time. - */ -static void -_expect_bridge_ports(json_t *params, const char *ifname, json_t *ports) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, s]]}", - "op", - "wait", - "table", - "Bridge", - "timeout", - 0, - "columns", - "ports", - "until", - "==", - "rows", - "ports", - "set", - ports, - "where", - "name", - "==", - ifname)); -} - -/** - * _set_bridge_ports: - * - * Return a command that will update the list of ports of bridge - * @ifname to @new_ports. - */ -static void -_set_bridge_ports(json_t *params, const char *ifname, json_t *new_ports) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, s]]}", - "op", - "update", - "table", - "Bridge", - "row", - "ports", - "set", - new_ports, - "where", - "name", - "==", - ifname)); -} - -static void -_set_bridge_mac(json_t *params, const char *ifname, const char *mac) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, [[s, s]]]}, s:[[s, s, s]]}", - "op", - "update", - "table", - "Bridge", - "row", - "other_config", - "map", - "hwaddr", - mac, - "where", - "name", - "==", - ifname)); -} - -/** - * _expect_port_interfaces: - * - * Return a command that will fail the transaction if the actual set of - * interfaces in port @ifname doesn't match @interfaces. This is a way of - * detecting race conditions with other ovsdb clients that might be adding - * or removing port interfaces at the same time. - */ -static void -_expect_port_interfaces(json_t *params, const char *ifname, json_t *interfaces) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:i, s:[s], s:s, s:[{s:[s, O]}], s:[[s, s, s]]}", - "op", - "wait", - "table", - "Port", - "timeout", - 0, - "columns", - "interfaces", - "until", - "==", - "rows", - "interfaces", - "set", - interfaces, - "where", - "name", - "==", - ifname)); -} - -/** - * _set_port_interfaces: - * - * Return a command that will update the list of interfaces of port @ifname - * to @new_interfaces. - */ -static void -_set_port_interfaces(json_t *params, const char *ifname, json_t *new_interfaces) -{ - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s:[s, O]}, s:[[s, s, s]]}", - "op", - "update", - "table", - "Port", - "row", - "interfaces", - "set", - new_interfaces, - "where", - "name", - "==", - ifname)); -} - -/** - * _insert_interface: - * - * Returns an commands that adds new interface from a given connection. - */ -static void -_insert_interface(json_t * params, - NMConnection *interface, - NMDevice * interface_device, - const char * cloned_mac) -{ - const char * type = NULL; - NMSettingOvsInterface *s_ovs_iface; - NMSettingOvsDpdk * s_ovs_dpdk; - NMSettingOvsPatch * s_ovs_patch; - json_t * options = json_array(); - json_t * row; - guint32 mtu = 0; - - s_ovs_iface = nm_connection_get_setting_ovs_interface(interface); - if (s_ovs_iface) - type = nm_setting_ovs_interface_get_interface_type(s_ovs_iface); - - if (nm_streq0(type, "internal")) { - NMSettingWired *s_wired; - - s_wired = _nm_connection_get_setting(interface, NM_TYPE_SETTING_WIRED); - if (s_wired) - mtu = nm_setting_wired_get_mtu(s_wired); - } - - json_array_append_new(options, json_string("map")); - - s_ovs_dpdk = - (NMSettingOvsDpdk *) nm_connection_get_setting(interface, NM_TYPE_SETTING_OVS_DPDK); - if (!s_ovs_dpdk) - s_ovs_patch = nm_connection_get_setting_ovs_patch(interface); - - if (s_ovs_dpdk) { - json_array_append_new( - options, - json_pack("[[s, s]]", "dpdk-devargs", nm_setting_ovs_dpdk_get_devargs(s_ovs_dpdk))); - } else if (s_ovs_patch) { - json_array_append_new( - options, - json_pack("[[s, s]]", "peer", nm_setting_ovs_patch_get_peer(s_ovs_patch))); - } else { - json_array_append_new(options, json_array()); - } - - row = json_pack("{s:s, s:s, s:o, s:[s, [[s, s]]]}", - "name", - nm_connection_get_interface_name(interface), - "type", - type ?: "", - "options", - options, - "external_ids", - "map", - "NM.connection.uuid", - nm_connection_get_uuid(interface)); - - if (cloned_mac) - json_object_set_new(row, "mac", json_string(cloned_mac)); - - if (mtu != 0) - json_object_set_new(row, "mtu_request", json_integer(mtu)); - - json_array_append_new(params, - json_pack("{s:s, s:s, s:o, s:s}", - "op", - "insert", - "table", - "Interface", - "row", - row, - "uuid-name", - "rowInterface")); -} - -/** - * _insert_port: - * - * Returns an commands that adds new port from a given connection. - */ -static void -_insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) -{ - NMSettingOvsPort *s_ovs_port; - const char * vlan_mode = NULL; - guint tag = 0; - const char * lacp = NULL; - const char * bond_mode = NULL; - guint bond_updelay = 0; - guint bond_downdelay = 0; - json_t * row; - - s_ovs_port = nm_connection_get_setting_ovs_port(port); - - row = json_object(); - - if (s_ovs_port) { - vlan_mode = nm_setting_ovs_port_get_vlan_mode(s_ovs_port); - tag = nm_setting_ovs_port_get_tag(s_ovs_port); - lacp = nm_setting_ovs_port_get_lacp(s_ovs_port); - bond_mode = nm_setting_ovs_port_get_bond_mode(s_ovs_port); - bond_updelay = nm_setting_ovs_port_get_bond_updelay(s_ovs_port); - bond_downdelay = nm_setting_ovs_port_get_bond_downdelay(s_ovs_port); - } - - if (vlan_mode) - json_object_set_new(row, "vlan_mode", json_string(vlan_mode)); - if (tag) - json_object_set_new(row, "tag", json_integer(tag)); - if (lacp) - json_object_set_new(row, "lacp", json_string(lacp)); - if (bond_mode) - json_object_set_new(row, "bond_mode", json_string(bond_mode)); - if (bond_updelay) - json_object_set_new(row, "bond_updelay", json_integer(bond_updelay)); - if (bond_downdelay) - json_object_set_new(row, "bond_downdelay", json_integer(bond_downdelay)); - - json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(port))); - json_object_set_new(row, "interfaces", json_pack("[s, O]", "set", new_interfaces)); - json_object_set_new( - row, - "external_ids", - json_pack("[s, [[s, s]]]", "map", "NM.connection.uuid", nm_connection_get_uuid(port))); - - /* Create a new one. */ - json_array_append_new(params, - json_pack("{s:s, s:s, s:o, s:s}", - "op", - "insert", - "table", - "Port", - "row", - row, - "uuid-name", - "rowPort")); -} - -/** - * _insert_bridge: - * - * Returns an commands that adds new bridge from a given connection. - */ -static void -_insert_bridge(json_t * params, - NMConnection *bridge, - NMDevice * bridge_device, - json_t * new_ports, - const char * cloned_mac) -{ - NMSettingOvsBridge *s_ovs_bridge; - const char * fail_mode = NULL; - gboolean mcast_snooping_enable = FALSE; - gboolean rstp_enable = FALSE; - gboolean stp_enable = FALSE; - const char * datapath_type = NULL; - json_t * row; - - s_ovs_bridge = nm_connection_get_setting_ovs_bridge(bridge); - - row = json_object(); - - if (s_ovs_bridge) { - fail_mode = nm_setting_ovs_bridge_get_fail_mode(s_ovs_bridge); - mcast_snooping_enable = nm_setting_ovs_bridge_get_mcast_snooping_enable(s_ovs_bridge); - rstp_enable = nm_setting_ovs_bridge_get_rstp_enable(s_ovs_bridge); - stp_enable = nm_setting_ovs_bridge_get_stp_enable(s_ovs_bridge); - datapath_type = nm_setting_ovs_bridge_get_datapath_type(s_ovs_bridge); - } - - if (fail_mode) - json_object_set_new(row, "fail_mode", json_string(fail_mode)); - if (mcast_snooping_enable) - json_object_set_new(row, "mcast_snooping_enable", json_boolean(mcast_snooping_enable)); - if (rstp_enable) - json_object_set_new(row, "rstp_enable", json_boolean(rstp_enable)); - if (stp_enable) - json_object_set_new(row, "stp_enable", json_boolean(stp_enable)); - if (datapath_type) - json_object_set_new(row, "datapath_type", json_string(datapath_type)); - - json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(bridge))); - json_object_set_new(row, "ports", json_pack("[s, O]", "set", new_ports)); - json_object_set_new( - row, - "external_ids", - json_pack("[s, [[s, s]]]", "map", "NM.connection.uuid", nm_connection_get_uuid(bridge))); - - if (cloned_mac) { - json_object_set_new(row, - "other_config", - json_pack("[s, [[s, s]]]", "map", "hwaddr", cloned_mac)); - } - - /* Create a new one. */ - json_array_append_new(params, - json_pack("{s:s, s:s, s:o, s:s}", - "op", - "insert", - "table", - "Bridge", - "row", - row, - "uuid-name", - "rowBridge")); -} - -/** - * _inc_next_cfg: - * - * Returns an mutate command that bumps next_cfg upon successful completion - * of the transaction it is in. - */ -static json_t * -_inc_next_cfg(const char *db_uuid) -{ - return json_pack("{s:s, s:s, s:[[s, s, i]], s:[[s, s, [s, s]]]}", - "op", - "mutate", - "table", - "Open_vSwitch", - "mutations", - "next_cfg", - "+=", - 1, - "where", - "_uuid", - "==", - "uuid", - db_uuid); -} - -/** - * _add_interface: - * - * Adds an interface as specified by @interface connection, optionally creating - * a parent @port and @bridge if needed. - */ -static void -_add_interface(NMOvsdb * self, - json_t * params, - NMConnection *bridge, - NMConnection *port, - NMConnection *interface, - NMDevice * bridge_device, - NMDevice * interface_device) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - GHashTableIter iter; - const char * bridge_uuid; - const char * port_uuid; - const char * interface_uuid; - const char * bridge_name; - const char * port_name; - const char * interface_name; - OpenvswitchBridge * ovs_bridge = NULL; - OpenvswitchPort * ovs_port = NULL; - OpenvswitchInterface *ovs_interface = NULL; - nm_auto_decref_json json_t *bridges = NULL; - nm_auto_decref_json json_t *new_bridges = NULL; - nm_auto_decref_json json_t *ports = NULL; - nm_auto_decref_json json_t *new_ports = NULL; - nm_auto_decref_json json_t *interfaces = NULL; - nm_auto_decref_json json_t *new_interfaces = NULL; - gboolean has_interface = FALSE; - gboolean interface_is_local; - gs_free char * bridge_cloned_mac = NULL; - gs_free char * interface_cloned_mac = NULL; - GError * error = NULL; - int pi; - int ii; - - bridges = json_array(); - ports = json_array(); - interfaces = json_array(); - new_bridges = json_array(); - new_ports = json_array(); - new_interfaces = json_array(); - - bridge_name = nm_connection_get_interface_name(bridge); - port_name = nm_connection_get_interface_name(port); - interface_name = nm_connection_get_interface_name(interface); - interface_is_local = nm_streq0(bridge_name, interface_name); - - /* Determine cloned MAC addresses */ - if (!nm_device_hw_addr_get_cloned(bridge_device, - bridge, - FALSE, - &bridge_cloned_mac, - NULL, - &error)) { - _LOGW("Cannot determine cloned MAC for OVS %s '%s': %s", - "bridge", - bridge_name, - error->message); - g_clear_error(&error); - } - - if (!nm_device_hw_addr_get_cloned(interface_device, - interface, - FALSE, - &interface_cloned_mac, - NULL, - &error)) { - _LOGW("Cannot determine cloned MAC for OVS %s '%s': %s", - "interface", - interface_name, - error->message); - g_clear_error(&error); - } - - /* For local interfaces, ovs complains if it finds a - * MAC address in the Interface table because it only takes - * the MAC from the Bridge table. - * Set any cloned MAC present in a local interface connection - * into the Bridge table, unless conflicting with the bridge MAC. */ - if (interface_is_local && interface_cloned_mac) { - if (bridge_cloned_mac && !nm_streq(interface_cloned_mac, bridge_cloned_mac)) { - _LOGW("Cloned MAC '%s' of local ovs-interface '%s' conflicts with MAC '%s' of bridge " - "'%s'", - interface_cloned_mac, - interface_name, - bridge_cloned_mac, - bridge_name); - nm_clear_g_free(&interface_cloned_mac); - } else { - nm_clear_g_free(&bridge_cloned_mac); - bridge_cloned_mac = g_steal_pointer(&interface_cloned_mac); - _LOGT("'%s' is a local ovs-interface, the MAC will be set on ovs-bridge '%s'", - interface_name, - bridge_name); - } - } - - g_hash_table_iter_init(&iter, priv->bridges); - while (g_hash_table_iter_next(&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) { - json_array_append_new(bridges, json_pack("[s, s]", "uuid", bridge_uuid)); - - if (g_strcmp0(ovs_bridge->name, bridge_name) != 0 - || g_strcmp0(ovs_bridge->connection_uuid, nm_connection_get_uuid(bridge)) != 0) - continue; - - for (pi = 0; pi < ovs_bridge->ports->len; pi++) { - port_uuid = g_ptr_array_index(ovs_bridge->ports, pi); - ovs_port = g_hash_table_lookup(priv->ports, port_uuid); - - json_array_append_new(ports, json_pack("[s, s]", "uuid", port_uuid)); - - if (!ovs_port) { - /* This would be a violation of ovsdb's reference integrity (a bug). */ - _LOGW("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid); - continue; - } else if (strcmp(ovs_port->name, port_name) != 0 - || g_strcmp0(ovs_port->connection_uuid, nm_connection_get_uuid(port)) != 0) { - continue; - } - - for (ii = 0; ii < ovs_port->interfaces->len; ii++) { - interface_uuid = g_ptr_array_index(ovs_port->interfaces, ii); - ovs_interface = g_hash_table_lookup(priv->interfaces, interface_uuid); - - json_array_append_new(interfaces, json_pack("[s, s]", "uuid", interface_uuid)); - - if (!ovs_interface) { - /* This would be a violation of ovsdb's reference integrity (a bug). */ - _LOGW("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid); - } else if (strcmp(ovs_interface->name, interface_name) == 0 - && g_strcmp0(ovs_interface->connection_uuid, - nm_connection_get_uuid(interface)) - == 0) { - has_interface = TRUE; - } - } - - break; - } - - break; - } - - json_array_extend(new_bridges, bridges); - json_array_extend(new_ports, ports); - json_array_extend(new_interfaces, interfaces); - - if (json_array_size(interfaces) == 0) { - /* Need to create a port. */ - if (json_array_size(ports) == 0) { - /* Need to create a bridge. */ - _expect_ovs_bridges(params, priv->db_uuid, bridges); - json_array_append_new(new_bridges, json_pack("[s, s]", "named-uuid", "rowBridge")); - _set_ovs_bridges(params, priv->db_uuid, new_bridges); - _insert_bridge(params, bridge, bridge_device, new_ports, bridge_cloned_mac); - } else { - /* Bridge already exists. */ - g_return_if_fail(ovs_bridge); - _expect_bridge_ports(params, ovs_bridge->name, ports); - _set_bridge_ports(params, bridge_name, new_ports); - if (bridge_cloned_mac && interface_is_local) - _set_bridge_mac(params, bridge_name, bridge_cloned_mac); - } - - json_array_append_new(new_ports, json_pack("[s, s]", "named-uuid", "rowPort")); - _insert_port(params, port, new_interfaces); - } else { - /* Port already exists */ - g_return_if_fail(ovs_port); - _expect_port_interfaces(params, ovs_port->name, interfaces); - _set_port_interfaces(params, port_name, new_interfaces); - } - - if (!has_interface) { - _insert_interface(params, interface, interface_device, interface_cloned_mac); - json_array_append_new(new_interfaces, json_pack("[s, s]", "named-uuid", "rowInterface")); - } -} - -/** - * _delete_interface: - * - * Removes an interface of @ifname name, collecting empty ports and bridge - * if last item is removed from them. - */ -static void -_delete_interface(NMOvsdb *self, json_t *params, const char *ifname) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - GHashTableIter iter; - char * bridge_uuid; - char * port_uuid; - char * interface_uuid; - OpenvswitchBridge * ovs_bridge; - OpenvswitchPort * ovs_port; - OpenvswitchInterface *ovs_interface; - nm_auto_decref_json json_t *bridges = NULL; - nm_auto_decref_json json_t *new_bridges = NULL; - gboolean bridges_changed; - gboolean ports_changed; - gboolean interfaces_changed; - int pi; - int ii; - - bridges = json_array(); - new_bridges = json_array(); - bridges_changed = FALSE; - - g_hash_table_iter_init(&iter, priv->bridges); - while (g_hash_table_iter_next(&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) { - nm_auto_decref_json json_t *ports = NULL; - nm_auto_decref_json json_t *new_ports = NULL; - - ports = json_array(); - new_ports = json_array(); - ports_changed = FALSE; - - json_array_append_new(bridges, json_pack("[s,s]", "uuid", bridge_uuid)); - - for (pi = 0; pi < ovs_bridge->ports->len; pi++) { - nm_auto_decref_json json_t *interfaces = NULL; - nm_auto_decref_json json_t *new_interfaces = NULL; - - interfaces = json_array(); - new_interfaces = json_array(); - port_uuid = g_ptr_array_index(ovs_bridge->ports, pi); - ovs_port = g_hash_table_lookup(priv->ports, port_uuid); - - json_array_append_new(ports, json_pack("[s,s]", "uuid", port_uuid)); - - interfaces_changed = FALSE; - - if (!ovs_port) { - /* This would be a violation of ovsdb's reference integrity (a bug). */ - _LOGW("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid); - continue; - } - - for (ii = 0; ii < ovs_port->interfaces->len; ii++) { - interface_uuid = g_ptr_array_index(ovs_port->interfaces, ii); - ovs_interface = g_hash_table_lookup(priv->interfaces, interface_uuid); - - json_array_append_new(interfaces, json_pack("[s,s]", "uuid", interface_uuid)); - - if (ovs_interface) { - if (strcmp(ovs_interface->name, ifname) == 0) { - /* skip the interface */ - interfaces_changed = TRUE; - continue; - } - } else { - /* This would be a violation of ovsdb's reference integrity (a bug). */ - _LOGW("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid); - } - - json_array_append_new(new_interfaces, json_pack("[s,s]", "uuid", interface_uuid)); - } - - if (json_array_size(new_interfaces) == 0) { - ports_changed = TRUE; - } else { - if (interfaces_changed) { - _expect_port_interfaces(params, ovs_port->name, interfaces); - _set_port_interfaces(params, ovs_port->name, new_interfaces); - } - json_array_append_new(new_ports, json_pack("[s,s]", "uuid", port_uuid)); - } - } - - if (json_array_size(new_ports) == 0) { - bridges_changed = TRUE; - } else { - if (ports_changed) { - _expect_bridge_ports(params, ovs_bridge->name, ports); - _set_bridge_ports(params, ovs_bridge->name, new_ports); - } - json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", bridge_uuid)); - } - } - - if (bridges_changed) { - _expect_ovs_bridges(params, priv->db_uuid, bridges); - _set_ovs_bridges(params, priv->db_uuid, new_bridges); - } -} - -/** - * ovsdb_next_command: - * - * Translates a higher level operation (add/remove bridge/port) to a RFC 7047 - * command serialized into JSON ands sends it over to the database. - - * Only called when no command is waiting for a response, since the serialized - * command might depend on result of a previous one (add and remove need to - * include an up to date bridge list in their transactions to rule out races). - */ -static void -ovsdb_next_command(NMOvsdb *self) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - OvsdbMethodCall * call = NULL; - char * cmd; - nm_auto_decref_json json_t *msg = NULL; - json_t * params; - - if (!priv->conn) - return; - if (!priv->calls->len) - return; - call = &g_array_index(priv->calls, OvsdbMethodCall, 0); - if (call->id != COMMAND_PENDING) - return; - call->id = priv->seq++; - - switch (call->command) { - case OVSDB_MONITOR: - msg = json_pack("{s:i, s:s, s:[s, n, {" - " s:[{s:[s, s, s]}]," - " s:[{s:[s, s, s]}]," - " s:[{s:[s, s, s, s]}]," - " s:[{s:[]}]" - "}]}", - "id", - call->id, - "method", - "monitor", - "params", - "Open_vSwitch", - "Bridge", - "columns", - "name", - "ports", - "external_ids", - "Port", - "columns", - "name", - "interfaces", - "external_ids", - "Interface", - "columns", - "name", - "type", - "external_ids", - "error", - "Open_vSwitch", - "columns"); - break; - case OVSDB_ADD_INTERFACE: - params = json_array(); - json_array_append_new(params, json_string("Open_vSwitch")); - json_array_append_new(params, _inc_next_cfg(priv->db_uuid)); - - _add_interface(self, - params, - call->bridge, - call->port, - call->interface, - call->bridge_device, - call->interface_device); - - msg = json_pack("{s:i, s:s, s:o}", "id", call->id, "method", "transact", "params", params); - break; - case OVSDB_DEL_INTERFACE: - params = json_array(); - json_array_append_new(params, json_string("Open_vSwitch")); - json_array_append_new(params, _inc_next_cfg(priv->db_uuid)); - - _delete_interface(self, params, call->ifname); - - msg = json_pack("{s:i, s:s, s:o}", "id", call->id, "method", "transact", "params", params); - break; - case OVSDB_SET_INTERFACE_MTU: - params = json_array(); - json_array_append_new(params, json_string("Open_vSwitch")); - json_array_append_new(params, _inc_next_cfg(priv->db_uuid)); - - json_array_append_new(params, - json_pack("{s:s, s:s, s:{s: i}, s:[[s, s, s]]}", - "op", - "update", - "table", - "Interface", - "row", - "mtu_request", - call->mtu, - "where", - "name", - "==", - call->ifname)); - - msg = json_pack("{s:i, s:s, s:o}", "id", call->id, "method", "transact", "params", params); - break; - } - - g_return_if_fail(msg); - _LOGT_call("send", call, msg); - cmd = json_dumps(msg, 0); - - g_string_append(priv->output, cmd); - free(cmd); - - ovsdb_write(self); -} - -/** - * _uuids_to_array: - * - * This tidies up the somewhat non-straightforward way ovsdb represents an array - * of UUID elements. The single element is a tuple (called <atom> in RFC7047), - * - * [ "uuid", "aa095ffb-e1f1-0fc4-8038-82c1ea7e4797" ] - * - * while the list of multiple UUIDs are turned into a set of such tuples ("atoms"): - * - * [ "set", [ [ "uuid", "aa095ffb-e1f1-0fc4-8038-82c1ea7e4797" ], - * [ "uuid", "185c93f6-0b39-424e-8587-77d074aa7ce0" ], ... ] ] - */ -static void -_uuids_to_array(GPtrArray *array, const json_t *items) -{ - const char *key; - json_t * value; - size_t index = 0; - json_t * set_value; - size_t set_index; - - while (index < json_array_size(items)) { - key = json_string_value(json_array_get(items, index)); - index++; - value = json_array_get(items, index); - index++; - - if (!value) - return; - - if (g_strcmp0(key, "uuid") == 0 && json_is_string(value)) { - g_ptr_array_add(array, g_strdup(json_string_value(value))); - } else if (g_strcmp0(key, "set") == 0 && json_is_array(value)) { - json_array_foreach(value, set_index, set_value) - { - _uuids_to_array(array, set_value); - } - } - } -} - -static char * -_connection_uuid_from_external_ids(json_t *external_ids) -{ - json_t *value; - size_t index; - - if (g_strcmp0("map", json_string_value(json_array_get(external_ids, 0))) != 0) - return NULL; - - json_array_foreach(json_array_get(external_ids, 1), index, value) - { - if (g_strcmp0("NM.connection.uuid", json_string_value(json_array_get(value, 0))) == 0) - return g_strdup(json_string_value(json_array_get(value, 1))); - } - - return NULL; -} - -/** - * ovsdb_got_update: - * - * Called when we've got an "update" method call (we asked for it with the monitor - * command). We use it to maintain a consistent view of bridge list regardless of - * whether the changes are done by us or externally. - */ -static void -ovsdb_got_update(NMOvsdb *self, json_t *msg) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - json_t * ovs = NULL; - json_t * bridge = NULL; - json_t * port = NULL; - json_t * interface = NULL; - json_t * items; - json_t * external_ids; - json_error_t json_error = { - 0, - }; - void * iter; - const char * name; - const char * key; - const char * type; - json_t * value; - OpenvswitchBridge * ovs_bridge; - OpenvswitchPort * ovs_port; - OpenvswitchInterface *ovs_interface; - - if (json_unpack_ex(msg, - &json_error, - 0, - "{s?:o, s?:o, s?:o, s?:o}", - "Open_vSwitch", - &ovs, - "Bridge", - &bridge, - "Port", - &port, - "Interface", - &interface) - == -1) { - /* This doesn't really have to be an error; the key might - * be missing if there really are no bridges present. */ - _LOGD("Bad update: %s", json_error.text); - } - - if (ovs) { - const char *s; - - iter = json_object_iter(ovs); - s = json_object_iter_key(iter); - if (s) - nm_utils_strdup_reset(&priv->db_uuid, s); - } - - /* Interfaces */ - json_object_foreach(interface, key, value) - { - json_t * error = NULL; - gboolean old = FALSE; - gboolean new = FALSE; - - if (json_unpack(value, "{s:{}}", "old") == 0) - old = TRUE; - - if (json_unpack(value, - "{s:{s:s, s:s, s?:o, s:o}}", - "new", - "name", - &name, - "type", - &type, - "error", - &error, - "external_ids", - &external_ids) - == 0) - new = TRUE; - - if (old) { - ovs_interface = g_hash_table_lookup(priv->interfaces, key); - if (!ovs_interface) { - _LOGW("Interface '%s' was not seen", key); - } else if (!new || strcmp(ovs_interface->name, name) != 0) { - old = FALSE; - _LOGT("removed an '%s' interface: %s%s%s", - ovs_interface->type, - ovs_interface->name, - ovs_interface->connection_uuid ? ", " : "", - ovs_interface->connection_uuid ?: ""); - if (g_strcmp0(ovs_interface->type, "internal") == 0) { - /* Currently, the factory only creates NMDevices for - * internal interfaces. Ignore the rest. */ - g_signal_emit(self, - signals[DEVICE_REMOVED], - 0, - ovs_interface->name, - NM_DEVICE_TYPE_OVS_INTERFACE); - } - } - g_hash_table_remove(priv->interfaces, key); - } - - if (new) { - ovs_interface = g_slice_new(OpenvswitchInterface); - ovs_interface->name = g_strdup(name); - ovs_interface->type = g_strdup(type); - ovs_interface->connection_uuid = _connection_uuid_from_external_ids(external_ids); - g_hash_table_insert(priv->interfaces, g_strdup(key), ovs_interface); - if (old) { - _LOGT("changed an '%s' interface: %s%s%s", - type, - ovs_interface->name, - ovs_interface->connection_uuid ? ", " : "", - ovs_interface->connection_uuid ?: ""); - } else { - _LOGT("added an '%s' interface: %s%s%s", - ovs_interface->type, - ovs_interface->name, - ovs_interface->connection_uuid ? ", " : "", - ovs_interface->connection_uuid ?: ""); - if (g_strcmp0(ovs_interface->type, "internal") == 0) { - /* Currently, the factory only creates NMDevices for - * internal interfaces. Ignore the rest. */ - g_signal_emit(self, - signals[DEVICE_ADDED], - 0, - ovs_interface->name, - NM_DEVICE_TYPE_OVS_INTERFACE); - } - } - /* The error is a string. No error is indicated by an empty set, - * because why the fuck not: [ "set": [] ] */ - if (error && json_is_string(error)) { - g_signal_emit(self, - signals[INTERFACE_FAILED], - 0, - ovs_interface->name, - ovs_interface->connection_uuid, - json_string_value(error)); - } - } - } - - /* Ports */ - json_object_foreach(port, key, value) - { - gboolean old = FALSE; - gboolean new = FALSE; - - if (json_unpack(value, "{s:{}}", "old") == 0) - old = TRUE; - - if (json_unpack(value, - "{s:{s:s, s:o, s:o}}", - "new", - "name", - &name, - "external_ids", - &external_ids, - "interfaces", - &items) - == 0) - new = TRUE; - - if (old) { - ovs_port = g_hash_table_lookup(priv->ports, key); - if (!new || g_strcmp0(ovs_port->name, name) != 0) { - old = FALSE; - _LOGT("removed a port: %s%s%s", - ovs_port->name, - ovs_port->connection_uuid ? ", " : "", - ovs_port->connection_uuid ?: ""); - g_signal_emit(self, - signals[DEVICE_REMOVED], - 0, - ovs_port->name, - NM_DEVICE_TYPE_OVS_PORT); - } - g_hash_table_remove(priv->ports, key); - } - - if (new) { - ovs_port = g_slice_new(OpenvswitchPort); - ovs_port->name = g_strdup(name); - ovs_port->connection_uuid = _connection_uuid_from_external_ids(external_ids); - ovs_port->interfaces = g_ptr_array_new_with_free_func(g_free); - _uuids_to_array(ovs_port->interfaces, items); - g_hash_table_insert(priv->ports, g_strdup(key), ovs_port); - if (old) { - _LOGT("changed a port: %s%s%s", - ovs_port->name, - ovs_port->connection_uuid ? ", " : "", - ovs_port->connection_uuid ?: ""); - } else { - _LOGT("added a port: %s%s%s", - ovs_port->name, - ovs_port->connection_uuid ? ", " : "", - ovs_port->connection_uuid ?: ""); - g_signal_emit(self, - signals[DEVICE_ADDED], - 0, - ovs_port->name, - NM_DEVICE_TYPE_OVS_PORT); - } - } - } - - /* Bridges */ - json_object_foreach(bridge, key, value) - { - gboolean old = FALSE; - gboolean new = FALSE; - - if (json_unpack(value, "{s:{}}", "old") == 0) - old = TRUE; - - if (json_unpack(value, - "{s:{s:s, s:o, s:o}}", - "new", - "name", - &name, - "external_ids", - &external_ids, - "ports", - &items) - == 0) - new = TRUE; - - if (old) { - ovs_bridge = g_hash_table_lookup(priv->bridges, key); - if (!new || g_strcmp0(ovs_bridge->name, name) != 0) { - old = FALSE; - _LOGT("removed a bridge: %s%s%s", - ovs_bridge->name, - ovs_bridge->connection_uuid ? ", " : "", - ovs_bridge->connection_uuid ?: ""); - g_signal_emit(self, - signals[DEVICE_REMOVED], - 0, - ovs_bridge->name, - NM_DEVICE_TYPE_OVS_BRIDGE); - } - g_hash_table_remove(priv->bridges, key); - } - - if (new) { - ovs_bridge = g_slice_new(OpenvswitchBridge); - ovs_bridge->name = g_strdup(name); - ovs_bridge->connection_uuid = _connection_uuid_from_external_ids(external_ids); - ovs_bridge->ports = g_ptr_array_new_with_free_func(g_free); - _uuids_to_array(ovs_bridge->ports, items); - g_hash_table_insert(priv->bridges, g_strdup(key), ovs_bridge); - if (old) { - _LOGT("changed a bridge: %s%s%s", - ovs_bridge->name, - ovs_bridge->connection_uuid ? ", " : "", - ovs_bridge->connection_uuid ?: ""); - } else { - _LOGT("added a bridge: %s%s%s", - ovs_bridge->name, - ovs_bridge->connection_uuid ? ", " : "", - ovs_bridge->connection_uuid ?: ""); - g_signal_emit(self, - signals[DEVICE_ADDED], - 0, - ovs_bridge->name, - NM_DEVICE_TYPE_OVS_BRIDGE); - } - } - } -} - -/** - * ovsdb_got_echo: - * - * Only implemented because the specification mandates it. Actual ovsdb hasn't been - * seen doing this. - */ -static void -ovsdb_got_echo(NMOvsdb *self, json_int_t id, json_t *data) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - nm_auto_decref_json json_t *msg = NULL; - char * reply; - gboolean output_was_empty; - - output_was_empty = priv->output->len == 0; - - msg = json_pack("{s:I, s:O}", "id", id, "result", data); - reply = json_dumps(msg, 0); - g_string_append(priv->output, reply); - free(reply); - - if (output_was_empty) - ovsdb_write(self); -} - -/** - * ovsdb_got_msg:: - * - * Called when a complete JSON object was seen and unmarshalled. - * Either finishes a method call or processes a method call. - */ -static void -ovsdb_got_msg(NMOvsdb *self, json_t *msg) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - json_error_t json_error = { - 0, - }; - json_t * json_id = NULL; - gint64 id = -1; - const char * method = NULL; - json_t * params = NULL; - json_t * result = NULL; - json_t * error = NULL; - OvsdbMethodCall * call = NULL; - OvsdbMethodCallback callback; - gpointer user_data; - gs_free_error GError *local = NULL; - - if (json_unpack_ex(msg, - &json_error, - 0, - "{s?:o, s?:s, s?:o, s?:o, s?:o}", - "id", - &json_id, - "method", - &method, - "params", - ¶ms, - "result", - &result, - "error", - &error) - == -1) { - _LOGW("couldn't grok the message: %s", json_error.text); - ovsdb_disconnect(self, FALSE, FALSE); - return; - } - - if (json_is_number(json_id)) - id = json_integer_value(json_id); - - if (method) { - /* It's a method call! */ - if (!params) { - _LOGW("a method call with no params: '%s'", method); - ovsdb_disconnect(self, FALSE, FALSE); - return; - } - - if (g_strcmp0(method, "update") == 0) { - /* This is a update method call. */ - ovsdb_got_update(self, json_array_get(params, 1)); - } else if (g_strcmp0(method, "echo") == 0) { - /* This is an echo request. */ - ovsdb_got_echo(self, id, params); - } else { - _LOGW("got an unknown method call: '%s'", method); - } - return; - } - - if (id > -1) { - /* This is a response to a method call. */ - if (!priv->calls->len) { - _LOGE("there are no queued calls expecting response %" G_GUINT64_FORMAT, id); - ovsdb_disconnect(self, FALSE, FALSE); - return; - } - call = &g_array_index(priv->calls, OvsdbMethodCall, 0); - if (call->id != id) { - _LOGE("expected a response to call %" G_GUINT64_FORMAT ", not %" G_GUINT64_FORMAT, - call->id, - id); - ovsdb_disconnect(self, FALSE, FALSE); - return; - } - /* Cool, we found a corresponding call. Finish it. */ - - _LOGT_call("response", call, msg); - - if (!json_is_null(error)) { - /* The response contains an error. */ - g_set_error(&local, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Error call to OVSDB returned an error: %s", - json_string_value(error)); - } - - callback = call->callback; - user_data = call->user_data; - g_array_remove_index(priv->calls, 0); - callback(self, result, local, user_data); - priv->num_failures = 0; - - /* Don't progress further commands in case the callback hit an error - * and disconnected us. */ - if (!priv->conn) - return; - - /* Now we're free to serialize and send the next command, if any. */ - ovsdb_next_command(self); - - return; - } - - /* This is a message we are not interested in. */ - _LOGW("got an unknown message, ignoring"); -} - -/*****************************************************************************/ - -/* Lower level marshalling and demarshalling of the JSON-RPC traffic on the - * ovsdb socket. */ - -static size_t -_json_callback(void *buffer, size_t buflen, void *user_data) -{ - NMOvsdb * self = NM_OVSDB(user_data); - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - - if (priv->bufp == priv->input->len) { - /* No more bytes buffered for decoding. */ - return 0; - } - - /* Pass one more byte to the JSON decoder. */ - *(char *) buffer = priv->input->str[priv->bufp]; - priv->bufp++; - - return (size_t) 1; -} - -/** - * ovsdb_read_cb: - * - * Read out the data available from the ovsdb socket and try to deserialize - * the JSON. If we see a complete object, pass it upwards to ovsdb_got_msg(). - */ -static void -ovsdb_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - NMOvsdb * self = NM_OVSDB(user_data); - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - GInputStream * stream = G_INPUT_STREAM(source_object); - GError * error = NULL; - gssize size; - json_t * msg; - json_error_t json_error = { - 0, - }; - - size = g_input_stream_read_finish(stream, res, &error); - if (size == -1) { - /* ovsdb-server was possibly restarted */ - _LOGW("short read from ovsdb: %s", error->message); - priv->num_failures++; - g_clear_error(&error); - ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE); - return; - } - - g_string_append_len(priv->input, priv->buf, size); - do { - priv->bufp = 0; - /* The callback always eats up only up to a single byte. This makes - * it possible for us to identify complete JSON objects in spite of - * us not knowing the length in advance. */ - msg = json_load_callback(_json_callback, self, JSON_DISABLE_EOF_CHECK, &json_error); - if (msg) { - ovsdb_got_msg(self, msg); - g_string_erase(priv->input, 0, priv->bufp); - } - json_decref(msg); - } while (msg); - - if (!priv->conn) - return; - - if (size) - ovsdb_read(self); -} - -static void -ovsdb_read(NMOvsdb *self) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - - g_input_stream_read_async(g_io_stream_get_input_stream(G_IO_STREAM(priv->conn)), - priv->buf, - sizeof(priv->buf), - G_PRIORITY_DEFAULT, - NULL, - ovsdb_read_cb, - self); -} - -static void -ovsdb_write_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - GOutputStream * stream = G_OUTPUT_STREAM(source_object); - NMOvsdb * self = NM_OVSDB(user_data); - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - GError * error = NULL; - gssize size; - - size = g_output_stream_write_finish(stream, res, &error); - if (size == -1) { - /* ovsdb-server was possibly restarted */ - _LOGW("short write to ovsdb: %s", error->message); - priv->num_failures++; - g_clear_error(&error); - ovsdb_disconnect(self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE); - return; - } - - if (!priv->conn) - return; - - g_string_erase(priv->output, 0, size); - - ovsdb_write(self); -} - -static void -ovsdb_write(NMOvsdb *self) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - GOutputStream * stream; - - if (!priv->output->len) - return; - - stream = g_io_stream_get_output_stream(G_IO_STREAM(priv->conn)); - if (g_output_stream_has_pending(stream)) - return; - - g_output_stream_write_async(stream, - priv->output->str, - priv->output->len, - G_PRIORITY_DEFAULT, - NULL, - ovsdb_write_cb, - self); -} - -/*****************************************************************************/ - -/* Routines to maintain the ovsdb connection. */ - -/** - * ovsdb_disconnect: - * - * Clean up the internal state to the point equivalent to before connecting. - * Apart from clean shutdown this is a good response to unexpected trouble, - * since the next method call attempt a will trigger reconnect which hopefully - * puts us back in sync. - */ -static void -ovsdb_disconnect(NMOvsdb *self, gboolean retry, gboolean is_disposing) -{ - NMOvsdbPrivate * priv = NM_OVSDB_GET_PRIVATE(self); - OvsdbMethodCall * call; - OvsdbMethodCallback callback; - gpointer user_data; - gs_free_error GError *error = NULL; - - nm_assert(!retry || !is_disposing); - - if (!priv->client) - return; - - _LOGD("disconnecting from ovsdb, retry %d", retry); - - if (retry) { - if (priv->calls->len != 0) - g_array_index(priv->calls, OvsdbMethodCall, 0).id = COMMAND_PENDING; - } else { - nm_utils_error_set_cancelled(&error, is_disposing, "NMOvsdb"); - - while (priv->calls->len) { - call = &g_array_index(priv->calls, OvsdbMethodCall, priv->calls->len - 1); - callback = call->callback; - user_data = call->user_data; - g_array_remove_index(priv->calls, priv->calls->len - 1); - callback(self, NULL, error, user_data); - } - } - - priv->bufp = 0; - g_string_truncate(priv->input, 0); - g_string_truncate(priv->output, 0); - g_clear_object(&priv->client); - g_clear_object(&priv->conn); - nm_clear_g_free(&priv->db_uuid); - nm_clear_g_cancellable(&priv->cancellable); - - if (retry) - ovsdb_try_connect(self); -} - -static void -_monitor_bridges_cb(NMOvsdb *self, json_t *result, GError *error, gpointer user_data) -{ - if (error) { - if (!nm_utils_error_is_cancelled_or_disposing(error)) { - _LOGI("%s", error->message); - ovsdb_disconnect(self, FALSE, FALSE); - } - return; - } - - /* Treat the first response the same as the subsequent "update" - * messages we eventually get. */ - ovsdb_got_update(self, result); -} - -static void -_client_connect_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - GSocketClient * client = G_SOCKET_CLIENT(source_object); - NMOvsdb * self = NM_OVSDB(user_data); - NMOvsdbPrivate * priv; - GError * error = NULL; - GSocketConnection *conn; - - conn = g_socket_client_connect_finish(client, res, &error); - if (conn == NULL) { - if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - _LOGI("%s", error->message); - - ovsdb_disconnect(self, FALSE, FALSE); - g_clear_error(&error); - return; - } - - priv = NM_OVSDB_GET_PRIVATE(self); - priv->conn = conn; - g_clear_object(&priv->cancellable); - - ovsdb_read(self); - ovsdb_next_command(self); -} - -/** - * ovsdb_try_connect: - * - * Establish a connection to ovsdb unless it's already established or being - * established. Queues a monitor command as a very first one so that we're in - * sync when other commands are issued. - */ -static void -ovsdb_try_connect(NMOvsdb *self) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - GSocketAddress *addr; - - if (priv->client) - return; - - /* TODO: This should probably be made configurable via NetworkManager.conf */ - addr = g_unix_socket_address_new(RUNSTATEDIR "/openvswitch/db.sock"); - - priv->client = g_socket_client_new(); - priv->cancellable = g_cancellable_new(); - g_socket_client_connect_async(priv->client, - G_SOCKET_CONNECTABLE(addr), - priv->cancellable, - _client_connect_cb, - self); - g_object_unref(addr); - - /* Queue a monitor call before any other command, ensuring that we have an up - * to date view of existing bridged that we need for add and remove ops. */ - ovsdb_call_method(self, - OVSDB_MONITOR, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - _monitor_bridges_cb, - NULL, - TRUE); -} - -/*****************************************************************************/ - -/* Public functions useful for NMDeviceOpenvswitch to maintain the life cycle of - * their ovsdb entries without having to deal with ovsdb complexities themselves. */ - -typedef struct { - NMOvsdbCallback callback; - gpointer user_data; -} OvsdbCall; - -static void -_transact_cb(NMOvsdb *self, json_t *result, GError *error, gpointer user_data) -{ - OvsdbCall * call = user_data; - const char *err; - const char *err_details; - size_t index; - json_t * value; - - if (error) - goto out; - - json_array_foreach(result, index, value) - { - if (json_unpack(value, "{s:s, s:s}", "error", &err, "details", &err_details) == 0) { - g_set_error(&error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Error running the transaction: %s: %s", - err, - err_details); - goto out; - } - } - -out: - call->callback(error, call->user_data); - g_slice_free(OvsdbCall, call); -} - -static OvsdbCall * -ovsdb_call_new(NMOvsdbCallback callback, gpointer user_data) -{ - OvsdbCall *call; - - call = g_slice_new(OvsdbCall); - call->callback = callback; - call->user_data = user_data; - - return call; -} - -void -nm_ovsdb_add_interface(NMOvsdb * self, - NMConnection * bridge, - NMConnection * port, - NMConnection * interface, - NMDevice * bridge_device, - NMDevice * interface_device, - NMOvsdbCallback callback, - gpointer user_data) -{ - ovsdb_call_method(self, - OVSDB_ADD_INTERFACE, - NULL, - bridge, - port, - interface, - bridge_device, - interface_device, - 0, - _transact_cb, - ovsdb_call_new(callback, user_data), - FALSE); -} - -void -nm_ovsdb_del_interface(NMOvsdb * self, - const char * ifname, - NMOvsdbCallback callback, - gpointer user_data) -{ - ovsdb_call_method(self, - OVSDB_DEL_INTERFACE, - ifname, - NULL, - NULL, - NULL, - NULL, - NULL, - 0, - _transact_cb, - ovsdb_call_new(callback, user_data), - FALSE); -} - -void -nm_ovsdb_set_interface_mtu(NMOvsdb * self, - const char * ifname, - guint32 mtu, - NMOvsdbCallback callback, - gpointer user_data) -{ - ovsdb_call_method(self, - OVSDB_SET_INTERFACE_MTU, - ifname, - NULL, - NULL, - NULL, - NULL, - NULL, - mtu, - _transact_cb, - ovsdb_call_new(callback, user_data), - FALSE); -} - -/*****************************************************************************/ - -static void -_clear_call(gpointer data) -{ - OvsdbMethodCall *call = data; - - switch (call->command) { - case OVSDB_MONITOR: - break; - case OVSDB_ADD_INTERFACE: - g_clear_object(&call->bridge); - g_clear_object(&call->port); - g_clear_object(&call->interface); - g_clear_object(&call->bridge_device); - g_clear_object(&call->interface_device); - break; - case OVSDB_DEL_INTERFACE: - case OVSDB_SET_INTERFACE_MTU: - nm_clear_g_free(&call->ifname); - break; - } -} - -static void -_free_bridge(gpointer data) -{ - OpenvswitchBridge *ovs_bridge = data; - - g_free(ovs_bridge->name); - g_free(ovs_bridge->connection_uuid); - g_ptr_array_free(ovs_bridge->ports, TRUE); - g_slice_free(OpenvswitchBridge, ovs_bridge); -} - -static void -_free_port(gpointer data) -{ - OpenvswitchPort *ovs_port = data; - - g_free(ovs_port->name); - g_free(ovs_port->connection_uuid); - g_ptr_array_free(ovs_port->interfaces, TRUE); - g_slice_free(OpenvswitchPort, ovs_port); -} - -static void -_free_interface(gpointer data) -{ - OpenvswitchInterface *ovs_interface = data; - - g_free(ovs_interface->name); - g_free(ovs_interface->connection_uuid); - g_free(ovs_interface->type); - g_slice_free(OpenvswitchInterface, ovs_interface); -} - -static void -nm_ovsdb_init(NMOvsdb *self) -{ - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - - priv->calls = g_array_new(FALSE, TRUE, sizeof(OvsdbMethodCall)); - g_array_set_clear_func(priv->calls, _clear_call); - priv->input = g_string_new(NULL); - priv->output = g_string_new(NULL); - priv->bridges = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, _free_bridge); - priv->ports = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, _free_port); - priv->interfaces = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, _free_interface); - - ovsdb_try_connect(self); -} - -static void -dispose(GObject *object) -{ - NMOvsdb * self = NM_OVSDB(object); - NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); - - ovsdb_disconnect(self, FALSE, TRUE); - - if (priv->input) { - g_string_free(priv->input, TRUE); - priv->input = NULL; - } - if (priv->output) { - g_string_free(priv->output, TRUE); - priv->output = NULL; - } - if (priv->calls) { - g_array_free(priv->calls, TRUE); - priv->calls = NULL; - } - - nm_clear_pointer(&priv->bridges, g_hash_table_destroy); - nm_clear_pointer(&priv->ports, g_hash_table_destroy); - nm_clear_pointer(&priv->interfaces, g_hash_table_destroy); - - G_OBJECT_CLASS(nm_ovsdb_parent_class)->dispose(object); -} - -static void -nm_ovsdb_class_init(NMOvsdbClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->dispose = dispose; - - signals[DEVICE_ADDED] = g_signal_new(NM_OVSDB_DEVICE_ADDED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_UINT); - - signals[DEVICE_REMOVED] = g_signal_new(NM_OVSDB_DEVICE_REMOVED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_STRING, - G_TYPE_UINT); - - signals[INTERFACE_FAILED] = g_signal_new(NM_OVSDB_INTERFACE_FAILED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_STRING); -} diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h deleted file mode 100644 index c9eee19c..00000000 --- a/src/devices/ovs/nm-ovsdb.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_OVSDB_H__ -#define __NETWORKMANAGER_OVSDB_H__ - -#define NM_TYPE_OVSDB (nm_ovsdb_get_type()) -#define NM_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_OVSDB, NMOvsdb)) -#define NM_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_OVSDB, NMOvsdbClass)) -#define NM_IS_OVSDB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_OVSDB)) -#define NM_IS_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_OVSDB)) -#define NM_OVSDB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_OVSDB, NMOvsdbClass)) - -#define NM_OVSDB_DEVICE_ADDED "device-added" -#define NM_OVSDB_DEVICE_REMOVED "device-removed" -#define NM_OVSDB_INTERFACE_FAILED "interface-failed" - -typedef struct _NMOvsdb NMOvsdb; -typedef struct _NMOvsdbClass NMOvsdbClass; - -typedef void (*NMOvsdbCallback)(GError *error, gpointer user_data); - -NMOvsdb *nm_ovsdb_get(void); - -GType nm_ovsdb_get_type(void); - -void nm_ovsdb_add_interface(NMOvsdb * self, - NMConnection * bridge, - NMConnection * port, - NMConnection * interface, - NMDevice * bridge_device, - NMDevice * interface_device, - NMOvsdbCallback callback, - gpointer user_data); - -void nm_ovsdb_del_interface(NMOvsdb * self, - const char * ifname, - NMOvsdbCallback callback, - gpointer user_data); - -void nm_ovsdb_set_interface_mtu(NMOvsdb * self, - const char * ifname, - guint32 mtu, - NMOvsdbCallback callback, - gpointer user_data); - -#endif /* __NETWORKMANAGER_OVSDB_H__ */ diff --git a/src/devices/team/meson.build b/src/devices/team/meson.build deleted file mode 100644 index c2b77cb9..00000000 --- a/src/devices/team/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -sources = files( - 'nm-device-team.c', - 'nm-team-factory.c', -) - -deps = [ - daemon_nm_default_dep, - jansson_dep, - libteamdctl_dep, -] - -libnm_device_plugin_team = shared_module( - 'nm-device-plugin-team', - sources: sources, - dependencies: deps, - c_args: daemon_c_flags, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_plugindir, -) - -core_plugins += libnm_device_plugin_team - -test( - 'check-local-devices-team', - check_exports, - args: [libnm_device_plugin_team.full_path(), linker_script_devices], -) diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c deleted file mode 100644 index 27aa3004..00000000 --- a/src/devices/team/nm-device-team.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us> - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-team.h" - -#include <sys/types.h> -#include <unistd.h> -#include <signal.h> -#include <sys/wait.h> -#include <teamdctl.h> -#include <stdlib.h> - -#include "nm-glib-aux/nm-jansson.h" -#include "NetworkManagerUtils.h" -#include "devices/nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-config.h" -#include "nm-core-internal.h" -#include "nm-dbus-manager.h" -#include "nm-ip4-config.h" -#include "nm-std-aux/nm-dbus-compat.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceTeam); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceTeam, PROP_CONFIG, ); - -typedef struct { - struct teamdctl * tdc; - char * config; - GPid teamd_pid; - guint teamd_process_watch; - guint teamd_timeout; - guint teamd_read_timeout; - guint teamd_dbus_watch; - bool kill_in_progress : 1; - GFileMonitor * usock_monitor; - NMDeviceStageState stage1_state : 3; -} NMDeviceTeamPrivate; - -struct _NMDeviceTeam { - NMDevice parent; - NMDeviceTeamPrivate _priv; -}; - -struct _NMDeviceTeamClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceTeam, nm_device_team, NM_TYPE_DEVICE) - -#define NM_DEVICE_TEAM_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceTeam, NM_IS_DEVICE_TEAM, NMDevice) - -/*****************************************************************************/ - -static gboolean teamd_start(NMDeviceTeam *self); - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingTeam *s_team; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_TEAM_SETTING_NAME, - existing_connections, - NULL, - _("Team connection"), - "team", - NULL, - TRUE); - - s_team = nm_connection_get_setting_team(connection); - if (!s_team) { - s_team = (NMSettingTeam *) nm_setting_team_new(); - nm_connection_add_setting(connection, NM_SETTING(s_team)); - } - - return TRUE; -} - -static gboolean -ensure_teamd_connection(NMDevice *device) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - int err; - - if (priv->tdc) - return TRUE; - - priv->tdc = teamdctl_alloc(); - g_assert(priv->tdc); - err = teamdctl_connect(priv->tdc, nm_device_get_iface(device), NULL, NULL); - if (err != 0) { - _LOGE(LOGD_TEAM, "failed to connect to teamd (err=%d)", err); - teamdctl_free(priv->tdc); - priv->tdc = NULL; - } - - return !!priv->tdc; -} - -static const char * -_get_config(NMDeviceTeam *self) -{ - return nm_str_not_empty(NM_DEVICE_TEAM_GET_PRIVATE(self)->config); -} - -static gboolean -teamd_read_config(NMDeviceTeam *self) -{ - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - const char * config = NULL; - int err; - - if (priv->tdc) { - err = teamdctl_config_actual_get_raw_direct(priv->tdc, (char **) &config); - if (err) - return FALSE; - if (!config) { - /* set "" to distinguish an empty result from no config at all. */ - config = ""; - } - } - - if (!nm_streq0(config, priv->config)) { - g_free(priv->config); - priv->config = g_strdup(config); - _notify(self, PROP_CONFIG); - } - - return TRUE; -} - -static gboolean -teamd_read_timeout_cb(gpointer user_data) -{ - NMDeviceTeam * self = user_data; - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - - priv->teamd_read_timeout = 0; - teamd_read_config(self); - return G_SOURCE_REMOVE; -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(device); - NMSettingTeam * s_team = nm_connection_get_setting_team(connection); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - struct teamdctl * tdc = priv->tdc; - - if (!s_team) { - s_team = (NMSettingTeam *) nm_setting_team_new(); - nm_connection_add_setting(connection, (NMSetting *) s_team); - } - - /* Read the configuration only if not already set */ - if (!priv->config && ensure_teamd_connection(device)) - teamd_read_config(self); - - /* Restore previous tdc state */ - if (priv->tdc && !tdc) { - teamdctl_disconnect(priv->tdc); - teamdctl_free(priv->tdc); - priv->tdc = NULL; - } - - g_object_set(G_OBJECT(s_team), NM_SETTING_TEAM_CONFIG, _get_config(self), NULL); -} - -/*****************************************************************************/ - -static gboolean -master_update_slave_connection(NMDevice * self, - NMDevice * slave, - NMConnection *connection, - GError ** error) -{ - NMSettingTeamPort *s_port; - char * port_config = NULL; - int err = 0; - struct teamdctl * tdc; - const char * team_port_config = NULL; - const char * iface = nm_device_get_iface(self); - const char * iface_slave = nm_device_get_iface(slave); - - tdc = teamdctl_alloc(); - if (!tdc) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "update slave connection for slave '%s' failed to connect to teamd for master " - "%s (out of memory?)", - iface_slave, - iface); - g_return_val_if_reached(FALSE); - } - - err = teamdctl_connect(tdc, iface, NULL, NULL); - if (err) { - teamdctl_free(tdc); - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "update slave connection for slave '%s' failed to connect to teamd for master " - "%s (err=%d)", - iface_slave, - iface, - err); - return FALSE; - } - - err = teamdctl_port_config_get_raw_direct(tdc, iface_slave, (char **) &team_port_config); - port_config = g_strdup(team_port_config); - teamdctl_disconnect(tdc); - teamdctl_free(tdc); - if (err) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_FAILED, - "update slave connection for slave '%s' failed to get configuration from teamd " - "master %s (err=%d)", - iface_slave, - iface, - err); - g_free(port_config); - return FALSE; - } - - s_port = nm_connection_get_setting_team_port(connection); - if (!s_port) { - s_port = (NMSettingTeamPort *) nm_setting_team_port_new(); - nm_connection_add_setting(connection, NM_SETTING(s_port)); - } - - g_object_set(G_OBJECT(s_port), NM_SETTING_TEAM_PORT_CONFIG, port_config, NULL); - g_free(port_config); - - g_object_set(nm_connection_get_setting_connection(connection), - NM_SETTING_CONNECTION_MASTER, - iface, - NM_SETTING_CONNECTION_SLAVE_TYPE, - NM_SETTING_TEAM_SETTING_NAME, - NULL); - return TRUE; -} - -/*****************************************************************************/ - -static void -teamd_kill_cb(pid_t pid, gboolean success, int child_status, void *user_data) -{ - gs_unref_object NMDeviceTeam *self = user_data; - NMDeviceTeamPrivate * priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - - priv->kill_in_progress = FALSE; - - if (nm_device_get_state(NM_DEVICE(self)) != NM_DEVICE_STATE_PREPARE) { - _LOGT(LOGD_TEAM, "kill terminated"); - return; - } - - _LOGT(LOGD_TEAM, "kill terminated, starting teamd..."); - if (!teamd_start(self)) { - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } -} - -static void -teamd_cleanup(NMDeviceTeam *self, gboolean free_tdc) -{ - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - - nm_clear_g_source(&priv->teamd_process_watch); - nm_clear_g_source(&priv->teamd_timeout); - nm_clear_g_source(&priv->teamd_read_timeout); - - if (priv->teamd_pid > 0) { - priv->kill_in_progress = TRUE; - nm_utils_kill_child_async(priv->teamd_pid, - SIGTERM, - LOGD_TEAM, - "teamd", - 2000, - teamd_kill_cb, - g_object_ref(self)); - priv->teamd_pid = 0; - } - - if (priv->tdc && free_tdc) { - teamdctl_disconnect(priv->tdc); - teamdctl_free(priv->tdc); - priv->tdc = NULL; - } -} - -static gboolean -teamd_timeout_cb(gpointer user_data) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(user_data); - NMDevice * device = NM_DEVICE(self); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - - g_return_val_if_fail(priv->teamd_timeout, FALSE); - priv->teamd_timeout = 0; - - if (priv->teamd_pid && !priv->tdc) { - /* Timed out launching our own teamd process */ - _LOGW(LOGD_TEAM, "teamd timed out"); - teamd_cleanup(self, TRUE); - - g_warn_if_fail(nm_device_is_activating(device)); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } else { - /* Read again the configuration after the timeout since it might - * have changed. - */ - if (!teamd_read_config(self)) { - _LOGW(LOGD_TEAM, "failed to read teamd configuration"); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } - } - - return G_SOURCE_REMOVE; -} - -static void -teamd_ready(NMDeviceTeam *self) -{ - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - gboolean success; - - if (priv->kill_in_progress) { - /* If we are currently killing teamd, we are not - * interested in knowing when it becomes ready. */ - return; - } - - nm_device_queue_recheck_assume(device); - - /* Grab a teamd control handle even if we aren't going to use it - * immediately. But if we are, and grabbing it failed, fail the - * device activation. - */ - success = ensure_teamd_connection(device); - - if (nm_device_get_state(device) != NM_DEVICE_STATE_PREPARE - || priv->stage1_state != NM_DEVICE_STAGE_STATE_PENDING) - return; - - if (success) - success = teamd_read_config(self); - - if (!success) { - teamd_cleanup(self, TRUE); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - return; - } - - priv->stage1_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -teamd_gone(NMDeviceTeam *self) -{ - NMDevice * device = NM_DEVICE(self); - NMDeviceState state; - - teamd_cleanup(self, TRUE); - state = nm_device_get_state(device); - - /* Attempt to respawn teamd */ - if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) { - if (!teamd_start(self)) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } - } -} - -static void -teamd_dbus_appeared(GDBusConnection *connection, - const char * name, - const char * name_owner, - gpointer user_data) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(user_data); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - - g_return_if_fail(priv->teamd_dbus_watch); - - _LOGI(LOGD_TEAM, "teamd appeared on D-Bus"); - - /* If another teamd grabbed the bus name while our teamd was starting, - * just ignore the death of our teamd and run with the existing one. - */ - if (priv->teamd_process_watch) { - gs_unref_variant GVariant *ret = NULL; - guint32 pid; - - ret = g_dbus_connection_call_sync(connection, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixProcessID", - g_variant_new("(s)", name_owner), - NULL, - G_DBUS_CALL_FLAGS_NO_AUTO_START, - 2000, - NULL, - NULL); - - if (ret) { - g_variant_get(ret, "(u)", &pid); - if (pid != priv->teamd_pid) - teamd_cleanup(self, FALSE); - } else { - /* The process that registered on the bus died. If it's - * the teamd instance we just started, ignore the event - * as we already detect the failure through the process - * watch. If it's a previous instance that got killed, - * also ignore that as our new instance will register - * again. */ - _LOGD(LOGD_TEAM, "failed to determine D-Bus name owner, ignoring"); - return; - } - } - - teamd_ready(self); -} - -static void -teamd_dbus_vanished(GDBusConnection *dbus_connection, const char *name, gpointer user_data) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(user_data); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - - g_return_if_fail(priv->teamd_dbus_watch); - - if (!priv->tdc) { - /* g_bus_watch_name will always raise an initial signal, to indicate whether the - * name exists/not exists initially. Do not take this as a failure if it hadn't - * previously appeared. - */ - _LOGD(LOGD_TEAM, "teamd not on D-Bus (ignored)"); - return; - } - - _LOGI(LOGD_TEAM, "teamd vanished from D-Bus"); - - teamd_gone(self); -} - -static void -monitor_changed_cb(GFileMonitor * monitor, - GFile * file, - GFile * other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - NMDeviceTeam *self = NM_DEVICE_TEAM(user_data); - - switch (event_type) { - case G_FILE_MONITOR_EVENT_CREATED: - _LOGI(LOGD_TEAM, "file %s was created", g_file_get_path(file)); - teamd_ready(self); - break; - case G_FILE_MONITOR_EVENT_DELETED: - _LOGI(LOGD_TEAM, "file %s was deleted", g_file_get_path(file)); - teamd_gone(self); - break; - default:; - } -} - -static void -teamd_process_watch_cb(GPid pid, int status, gpointer user_data) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(user_data); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMDeviceState state = nm_device_get_state(device); - - g_return_if_fail(priv->teamd_process_watch); - - _LOGD(LOGD_TEAM, "teamd %lld died with status %d", (long long) pid, status); - priv->teamd_pid = 0; - priv->teamd_process_watch = 0; - - /* If teamd quit within 5 seconds of starting, it's probably hosed - * and will just die again, so fail the activation. - */ - if (priv->teamd_timeout && (state >= NM_DEVICE_STATE_PREPARE) - && (state <= NM_DEVICE_STATE_ACTIVATED)) { - _LOGW(LOGD_TEAM, - "teamd process %lld quit unexpectedly; failing activation", - (long long) pid); - teamd_cleanup(self, TRUE); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - } -} - -static void -teamd_child_setup(gpointer user_data) -{ - nm_utils_setpgid(NULL); - signal(SIGPIPE, SIG_IGN); -} - -static const char ** -teamd_env(void) -{ - const char **env = g_new0(const char *, 2); - - if (nm_config_get_is_debug(nm_config_get())) - env[0] = "TEAM_LOG_OUTPUT=stderr"; - else - env[0] = "TEAM_LOG_OUTPUT=syslog"; - - return env; -} - -static gboolean -teamd_kill(NMDeviceTeam *self, const char *teamd_binary, GError **error) -{ - gs_unref_ptrarray GPtrArray *argv = NULL; - gs_free char * tmp_str = NULL; - gs_free const char ** envp = NULL; - - if (!teamd_binary) { - teamd_binary = nm_utils_find_helper("teamd", NULL, error); - if (!teamd_binary) { - _LOGW(LOGD_TEAM, "Activation: (team) failed to start teamd: teamd binary not found"); - return FALSE; - } - } - - argv = g_ptr_array_new(); - g_ptr_array_add(argv, (gpointer) teamd_binary); - g_ptr_array_add(argv, (gpointer) "-k"); - g_ptr_array_add(argv, (gpointer) "-t"); - g_ptr_array_add(argv, (gpointer) nm_device_get_iface(NM_DEVICE(self))); - g_ptr_array_add(argv, NULL); - - envp = teamd_env(); - - _LOGD(LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv(" ", (char **) argv->pdata))); - return g_spawn_sync("/", - (char **) argv->pdata, - (char **) envp, - 0, - teamd_child_setup, - NULL, - NULL, - NULL, - NULL, - error); -} - -static gboolean -teamd_start(NMDeviceTeam *self) -{ - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - const char * iface = nm_device_get_ip_iface(NM_DEVICE(self)); - NMConnection * connection; - gs_unref_ptrarray GPtrArray *argv = NULL; - gs_free_error GError * error = NULL; - gs_free char * tmp_str = NULL; - const char * teamd_binary; - const char * config; - nm_auto_free const char *config_free = NULL; - NMSettingTeam * s_team; - gs_free char * cloned_mac = NULL; - gs_free const char ** envp = NULL; - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - - s_team = nm_connection_get_setting_team(connection); - if (!s_team) - g_return_val_if_reached(FALSE); - - nm_assert(iface); - - teamd_binary = nm_utils_find_helper("teamd", NULL, NULL); - if (!teamd_binary) { - _LOGW(LOGD_TEAM, "Activation: (team) failed to start teamd: teamd binary not found"); - return FALSE; - } - - if (priv->teamd_process_watch || priv->teamd_pid > 0 || priv->tdc) { - g_warn_if_reached(); - if (!priv->teamd_pid) - teamd_kill(self, teamd_binary, NULL); - teamd_cleanup(self, TRUE); - } - - /* Start teamd now */ - argv = g_ptr_array_new(); - g_ptr_array_add(argv, (gpointer) teamd_binary); - g_ptr_array_add(argv, (gpointer) "-o"); - g_ptr_array_add(argv, (gpointer) "-n"); - g_ptr_array_add(argv, (gpointer) "-U"); - if (priv->teamd_dbus_watch) - g_ptr_array_add(argv, (gpointer) "-D"); - g_ptr_array_add(argv, (gpointer) "-N"); - g_ptr_array_add(argv, (gpointer) "-t"); - g_ptr_array_add(argv, (gpointer) iface); - - config = nm_setting_team_get_config(s_team); - if (!nm_device_hw_addr_get_cloned(NM_DEVICE(self), - connection, - FALSE, - &cloned_mac, - NULL, - &error)) { - _LOGW(LOGD_DEVICE, "set-hw-addr: %s", error->message); - return FALSE; - } - - if (cloned_mac) { - json_t * json, *hwaddr; - json_error_t jerror; - - /* Inject the hwaddr property into the JSON configuration. - * While doing so, detect potential conflicts */ - - json = json_loads(config ?: "{}", JSON_REJECT_DUPLICATES, &jerror); - g_return_val_if_fail(json, FALSE); - - hwaddr = json_object_get(json, "hwaddr"); - if (hwaddr) { - if (!json_is_string(hwaddr) || !nm_streq0(json_string_value(hwaddr), cloned_mac)) - _LOGW(LOGD_TEAM, - "set-hw-addr: can't set team cloned-mac-address as the JSON configuration " - "already contains \"hwaddr\""); - } else { - hwaddr = json_string(cloned_mac); - json_object_set(json, "hwaddr", hwaddr); - config = config_free = - json_dumps(json, JSON_INDENT(0) | JSON_ENSURE_ASCII | JSON_SORT_KEYS); - _LOGD(LOGD_TEAM, - "set-hw-addr: injected \"hwaddr\" \"%s\" into team configuration", - cloned_mac); - json_decref(hwaddr); - } - json_decref(json); - } - - if (config) { - g_ptr_array_add(argv, (gpointer) "-c"); - g_ptr_array_add(argv, (gpointer) config); - } - - if (nm_logging_enabled(LOGL_DEBUG, LOGD_TEAM)) - g_ptr_array_add(argv, (gpointer) "-gg"); - g_ptr_array_add(argv, NULL); - - envp = teamd_env(); - - _LOGD(LOGD_TEAM, "running: %s", (tmp_str = g_strjoinv(" ", (char **) argv->pdata))); - if (!g_spawn_async("/", - (char **) argv->pdata, - (char **) envp, - G_SPAWN_DO_NOT_REAP_CHILD, - teamd_child_setup, - NULL, - &priv->teamd_pid, - &error)) { - _LOGW(LOGD_TEAM, "Activation: (team) failed to start teamd: %s", error->message); - teamd_cleanup(self, TRUE); - return FALSE; - } - - /* Start a timeout for teamd to appear at D-Bus */ - if (!priv->teamd_timeout) - priv->teamd_timeout = g_timeout_add_seconds(5, teamd_timeout_cb, self); - - /* Monitor the child process so we know when it dies */ - priv->teamd_process_watch = g_child_watch_add(priv->teamd_pid, teamd_process_watch_cb, self); - - _LOGI(LOGD_TEAM, "Activation: (team) started teamd [pid %u]...", (guint) priv->teamd_pid); - return TRUE; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - gs_free_error GError *error = NULL; - NMSettingTeam * s_team; - const char * cfg; - - if (nm_device_sys_iface_state_is_external(device)) - return NM_ACT_STAGE_RETURN_SUCCESS; - - if (nm_device_sys_iface_state_is_external_or_assume(device)) { - if (ensure_teamd_connection(device)) - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - s_team = nm_device_get_applied_setting(device, NM_TYPE_SETTING_TEAM); - if (!s_team) - g_return_val_if_reached(NM_ACT_STAGE_RETURN_FAILURE); - - if (priv->stage1_state == NM_DEVICE_STAGE_STATE_PENDING) - return NM_ACT_STAGE_RETURN_POSTPONE; - - if (priv->stage1_state == NM_DEVICE_STAGE_STATE_COMPLETED) - return NM_ACT_STAGE_RETURN_SUCCESS; - - priv->stage1_state = NM_DEVICE_STAGE_STATE_PENDING; - - if (priv->tdc) { - /* If the existing teamd config is the same as we're about to use, - * then we can proceed. If it's not the same, and we have a PID, - * kill it so we can respawn it with the right config. If we don't - * have a PID, then we must fail. - */ - cfg = teamdctl_config_get_raw(priv->tdc); - if (cfg && nm_streq0(cfg, nm_setting_team_get_config(s_team))) { - _LOGD(LOGD_TEAM, "using existing matching teamd config"); - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - if (!priv->teamd_pid) { - _LOGD(LOGD_TEAM, "existing teamd config mismatch; killing existing via teamdctl"); - if (!teamd_kill(self, NULL, &error)) { - _LOGW(LOGD_TEAM, - "existing teamd config mismatch; failed to kill existing teamd: %s", - error->message); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_TEAMD_CONTROL_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - } - - _LOGD(LOGD_TEAM, "existing teamd config mismatch; respawning..."); - teamd_cleanup(self, TRUE); - } - - if (priv->kill_in_progress) { - _LOGT(LOGD_TEAM, "kill in progress, wait before starting teamd"); - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (!teamd_start(self)) - return NM_ACT_STAGE_RETURN_FAILURE; - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - - priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT; - - if (nm_device_sys_iface_state_is_external(device)) - return; - - if (priv->teamd_pid || priv->tdc) - _LOGI(LOGD_TEAM, "deactivation: stopping teamd..."); - - if (!priv->teamd_pid) - teamd_kill(self, NULL, NULL); - - teamd_cleanup(self, TRUE); -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - gboolean success = TRUE; - const char * slave_iface = nm_device_get_ip_iface(slave); - NMSettingTeamPort * s_team_port; - - nm_device_master_check_slave_physical_port(device, slave, LOGD_TEAM); - - if (configure) { - nm_device_take_down(slave, TRUE); - - s_team_port = nm_connection_get_setting_team_port(connection); - if (s_team_port) { - const char *config = nm_setting_team_port_get_config(s_team_port); - - if (config) { - if (!priv->tdc) { - _LOGW(LOGD_TEAM, - "enslaved team port %s config not changed, not connected to teamd", - slave_iface); - } else { - int err; - char *sanitized_config; - - sanitized_config = g_strdelimit(g_strdup(config), "\r\n", ' '); - err = teamdctl_port_config_update_raw(priv->tdc, slave_iface, sanitized_config); - g_free(sanitized_config); - if (err != 0) { - _LOGE(LOGD_TEAM, - "failed to update config for port %s (err=%d)", - slave_iface, - err); - return FALSE; - } - } - } - } - success = nm_platform_link_enslave(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - nm_device_get_ip_ifindex(slave)); - nm_device_bring_up(slave, TRUE, NULL); - - if (!success) - return FALSE; - - nm_clear_g_source(&priv->teamd_read_timeout); - priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self); - - _LOGI(LOGD_TEAM, "enslaved team port %s", slave_iface); - } else - _LOGI(LOGD_TEAM, "team port %s was enslaved", slave_iface); - - return TRUE; -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - gboolean do_release, success; - NMSettingTeamPort * s_port; - int ifindex_slave; - int ifindex; - - do_release = configure; - if (do_release) { - ifindex = nm_device_get_ifindex(device); - if (ifindex <= 0 || !nm_platform_link_get(nm_device_get_platform(device), ifindex)) - do_release = FALSE; - } - - ifindex_slave = nm_device_get_ip_ifindex(slave); - - if (ifindex_slave <= 0) { - _LOGD(LOGD_TEAM, "team port %s is already released", nm_device_get_ip_iface(slave)); - } else if (do_release) { - success = nm_platform_link_release(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - ifindex_slave); - if (success) - _LOGI(LOGD_TEAM, "released team port %s", nm_device_get_ip_iface(slave)); - else - _LOGW(LOGD_TEAM, "failed to release team port %s", nm_device_get_ip_iface(slave)); - - /* Kernel team code "closes" the port when releasing it, (which clears - * IFF_UP), so we must bring it back up here to ensure carrier changes and - * other state is noticed by the now-released port. - */ - if (!nm_device_bring_up(slave, TRUE, NULL)) { - _LOGW(LOGD_TEAM, - "released team port %s could not be brought up", - nm_device_get_ip_iface(slave)); - } - - nm_clear_g_source(&priv->teamd_read_timeout); - priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self); - } else - _LOGI(LOGD_TEAM, "team port %s was released", nm_device_get_ip_iface(slave)); - - /* Delete any port configuration we previously set */ - if (configure && priv->tdc - && (s_port = nm_device_get_applied_setting(slave, NM_TYPE_SETTING_TEAM_PORT)) - && (nm_setting_team_port_get_config(s_port))) - teamdctl_port_config_update_raw(priv->tdc, nm_device_get_ip_iface(slave), "{}"); -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - const char *iface = nm_device_get_iface(device); - int r; - - r = nm_platform_link_team_add(nm_device_get_platform(device), iface, out_plink); - if (r < 0) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create team master interface '%s' for '%s': %s", - iface, - nm_connection_get_id(connection), - nm_strerror(r)); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceTeam *self = NM_DEVICE_TEAM(object); - - switch (prop_id) { - case PROP_CONFIG: - g_value_set_string(value, _get_config(self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_team_init(NMDeviceTeam *self) -{ - nm_assert(nm_device_is_master(NM_DEVICE(self))); -} - -static void -constructed(GObject *object) -{ - NMDevice * device = NM_DEVICE(object); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(device); - gs_free char * tmp_str = NULL; - gs_unref_object GFile *file = NULL; - GError * error; - - G_OBJECT_CLASS(nm_device_team_parent_class)->constructed(object); - - if (nm_dbus_manager_get_dbus_connection(nm_dbus_manager_get())) { - /* Register D-Bus name watcher */ - tmp_str = g_strdup_printf("org.libteam.teamd.%s", nm_device_get_ip_iface(device)); - priv->teamd_dbus_watch = g_bus_watch_name(G_BUS_TYPE_SYSTEM, - tmp_str, - G_BUS_NAME_WATCHER_FLAGS_NONE, - teamd_dbus_appeared, - teamd_dbus_vanished, - NM_DEVICE(device), - NULL); - return; - } - - /* No D-Bus, watch unix socket */ - tmp_str = g_strdup_printf("/run/teamd/%s.sock", nm_device_get_ip_iface(device)); - file = g_file_new_for_path(tmp_str); - priv->usock_monitor = g_file_monitor_file(file, G_FILE_MONITOR_NONE, NULL, &error); - if (!priv->usock_monitor) { - nm_log_warn(LOGD_TEAM, "error monitoring %s: %s", tmp_str, error->message); - } else { - g_signal_connect(priv->usock_monitor, "changed", G_CALLBACK(monitor_changed_cb), object); - } -} - -NMDevice * -nm_device_team_new(const char *iface) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_TEAM, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_DRIVER, - "team", - NM_DEVICE_TYPE_DESC, - "Team", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_TEAM, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_TEAM, - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceTeam * self = NM_DEVICE_TEAM(object); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - - if (priv->teamd_dbus_watch) { - g_bus_unwatch_name(priv->teamd_dbus_watch); - priv->teamd_dbus_watch = 0; - } - - if (priv->usock_monitor) { - g_signal_handlers_disconnect_by_data(priv->usock_monitor, object); - g_clear_object(&priv->usock_monitor); - } - - teamd_cleanup(self, TRUE); - nm_clear_g_free(&priv->config); - - G_OBJECT_CLASS(nm_device_team_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_team = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_TEAM, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Slaves", "ao", NM_DEVICE_SLAVES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Config", - "s", - NM_DEVICE_TEAM_CONFIG), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_team_class_init(NMDeviceTeamClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_team); - - device_class->connection_type_supported = NM_SETTING_TEAM_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_TEAM_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_TEAM); - - device_class->is_master = TRUE; - device_class->create_and_realize = create_and_realize; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->complete_connection = complete_connection; - device_class->update_connection = update_connection; - device_class->master_update_slave_connection = master_update_slave_connection; - - device_class->act_stage1_prepare_also_for_external_or_assume = TRUE; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - device_class->deactivate = deactivate; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; - - obj_properties[PROP_CONFIG] = g_param_spec_string(NM_DEVICE_TEAM_CONFIG, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/team/nm-device-team.h b/src/devices/team/nm-device-team.h deleted file mode 100644 index eabc63e6..00000000 --- a/src/devices/team/nm-device-team.h +++ /dev/null @@ -1,30 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 Jiri Pirko <jiri@resnulli.us> - */ - -#ifndef __NETWORKMANAGER_DEVICE_TEAM_H__ -#define __NETWORKMANAGER_DEVICE_TEAM_H__ - -#include "devices/nm-device.h" - -#define NM_TYPE_DEVICE_TEAM (nm_device_team_get_type()) -#define NM_DEVICE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeam)) -#define NM_DEVICE_TEAM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass)) -#define NM_IS_DEVICE_TEAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_TEAM)) -#define NM_IS_DEVICE_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_TEAM)) -#define NM_DEVICE_TEAM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass)) - -/* Properties */ -#define NM_DEVICE_TEAM_CONFIG "config" - -typedef struct _NMDeviceTeam NMDeviceTeam; -typedef struct _NMDeviceTeamClass NMDeviceTeamClass; - -GType nm_device_team_get_type(void); - -NMDevice *nm_device_team_new(const char *iface); - -#endif /* __NETWORKMANAGER_DEVICE_TEAM_H__ */ diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c deleted file mode 100644 index 644bef1c..00000000 --- a/src/devices/team/nm-team-factory.c +++ /dev/null @@ -1,77 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <gmodule.h> - -#include "nm-manager.h" -#include "devices/nm-device-factory.h" -#include "nm-device-team.h" -#include "platform/nm-platform.h" -#include "nm-core-internal.h" - -/*****************************************************************************/ - -#define NM_TYPE_TEAM_FACTORY (nm_team_factory_get_type()) -#define NM_TEAM_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_TEAM_FACTORY, NMTeamFactory)) -#define NM_TEAM_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_TEAM_FACTORY, NMTeamFactoryClass)) -#define NM_IS_TEAM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_TEAM_FACTORY)) -#define NM_IS_TEAM_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_TEAM_FACTORY)) -#define NM_TEAM_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_TEAM_FACTORY, NMTeamFactoryClass)) - -typedef struct { - NMDeviceFactory parent; -} NMTeamFactory; - -typedef struct { - NMDeviceFactoryClass parent; -} NMTeamFactoryClass; - -static GType nm_team_factory_get_type(void); - -G_DEFINE_TYPE(NMTeamFactory, nm_team_factory, NM_TYPE_DEVICE_FACTORY) - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES(NM_DEVICE_FACTORY_DECLARE_LINK_TYPES( - NM_LINK_TYPE_TEAM) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_TEAM_SETTING_NAME)) - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - nm_manager_set_capability(NM_MANAGER_GET, NM_CAPABILITY_TEAM); - return (NMDeviceFactory *) g_object_new(NM_TYPE_TEAM_FACTORY, NULL); -} - -/*****************************************************************************/ - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - return nm_device_team_new(iface); -} - -/*****************************************************************************/ - -static void -nm_team_factory_init(NMTeamFactory *self) -{} - -static void -nm_team_factory_class_init(NMTeamFactoryClass *klass) -{ - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - factory_class->create_device = create_device; - factory_class->get_supported_types = get_supported_types; -} diff --git a/src/devices/tests/meson.build b/src/devices/tests/meson.build deleted file mode 100644 index 1ddd4f85..00000000 --- a/src/devices/tests/meson.build +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -test_units = [ - 'test-acd', - 'test-lldp', -] - -foreach test_unit: test_units - exe = executable( - test_unit, - test_unit + '.c', - dependencies: libnetwork_manager_test_dep, - c_args: test_c_flags, - ) - - test( - 'devices/' + test_unit, - test_script, - args: test_args + [exe.full_path()], - timeout: default_test_timeout, - ) -endforeach diff --git a/src/devices/tests/test-acd.c b/src/devices/tests/test-acd.c deleted file mode 100644 index da7b3c3d..00000000 --- a/src/devices/tests/test-acd.c +++ /dev/null @@ -1,257 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "n-acd/src/n-acd.h" - -#include "devices/nm-acd-manager.h" -#include "platform/tests/test-common.h" - -#define IFACE_VETH0 "nm-test-veth0" -#define IFACE_VETH1 "nm-test-veth1" - -#define ADDR1 0x01010101 -#define ADDR2 0x02020202 -#define ADDR3 0x03030303 -#define ADDR4 0x04040404 - -/*****************************************************************************/ - -static gboolean -_skip_acd_test_check(void) -{ - NAcd * acd; - NAcdConfig * config; - const guint8 hwaddr[ETH_ALEN] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06}; - int r; - static int skip = -1; - - if (skip == -1) { - r = n_acd_config_new(&config); - g_assert(r == 0); - - n_acd_config_set_ifindex(config, 1); - n_acd_config_set_transport(config, N_ACD_TRANSPORT_ETHERNET); - n_acd_config_set_mac(config, hwaddr, sizeof(hwaddr)); - - r = n_acd_new(&acd, config); - n_acd_config_free(config); - if (r == 0) - n_acd_unref(acd); - - skip = (r != 0); - } - return skip; -} - -#define _skip_acd_test() \ - ({ \ - gboolean _skip = _skip_acd_test_check(); \ - \ - if (_skip) \ - g_test_skip("Cannot create NAcd. Running under valgind?"); \ - _skip; \ - }) - -/*****************************************************************************/ - -typedef struct { - int ifindex0; - int ifindex1; - const guint8 *hwaddr0; - const guint8 *hwaddr1; - size_t hwaddr0_len; - size_t hwaddr1_len; -} test_fixture; - -static void -fixture_setup(test_fixture *fixture, gconstpointer user_data) -{ - /* create veth pair. */ - fixture->ifindex0 = - nmtstp_link_veth_add(NM_PLATFORM_GET, -1, IFACE_VETH0, IFACE_VETH1)->ifindex; - fixture->ifindex1 = - nmtstp_link_get_typed(NM_PLATFORM_GET, -1, IFACE_VETH1, NM_LINK_TYPE_VETH)->ifindex; - - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, fixture->ifindex0, NULL)); - g_assert(nm_platform_link_set_up(NM_PLATFORM_GET, fixture->ifindex1, NULL)); - - fixture->hwaddr0 = - nm_platform_link_get_address(NM_PLATFORM_GET, fixture->ifindex0, &fixture->hwaddr0_len); - fixture->hwaddr1 = - nm_platform_link_get_address(NM_PLATFORM_GET, fixture->ifindex1, &fixture->hwaddr1_len); -} - -typedef struct { - in_addr_t addresses[8]; - in_addr_t peer_addresses[8]; - gboolean expected_result[8]; -} TestInfo; - -static void -acd_manager_probe_terminated(NMAcdManager *acd_manager, gpointer user_data) -{ - g_main_loop_quit(user_data); -} - -static void -test_acd_common(test_fixture *fixture, TestInfo *info) -{ - nm_auto_free_acdmgr NMAcdManager *manager = NULL; - nm_auto_unref_gmainloop GMainLoop *loop = NULL; - int i; - const guint WAIT_TIME_OPTIMISTIC = 50; - guint wait_time; - static const NMAcdCallbacks callbacks = { - .probe_terminated_callback = acd_manager_probe_terminated, - .user_data_destroy = (GDestroyNotify) g_main_loop_unref, - }; - int r; - - if (_skip_acd_test()) - return; - - /* first, try with a short waittime. We hope that this is long enough - * to successfully complete the test. Only if that's not the case, we - * assume the computer is currently busy (high load) and we retry with - * a longer timeout. */ - wait_time = WAIT_TIME_OPTIMISTIC; -again: - - nm_clear_pointer(&loop, g_main_loop_unref); - loop = g_main_loop_new(NULL, FALSE); - - nm_clear_pointer(&manager, nm_acd_manager_free); - manager = nm_acd_manager_new(fixture->ifindex0, - fixture->hwaddr0, - fixture->hwaddr0_len, - &callbacks, - g_main_loop_ref(loop)); - g_assert(manager != NULL); - - for (i = 0; info->addresses[i]; i++) - g_assert(nm_acd_manager_add_address(manager, info->addresses[i])); - - for (i = 0; info->peer_addresses[i]; i++) { - nmtstp_ip4_address_add(NULL, - FALSE, - fixture->ifindex1, - info->peer_addresses[i], - 24, - 0, - 3600, - 1800, - 0, - NULL); - } - - r = nm_acd_manager_start_probe(manager, wait_time); - g_assert_cmpint(r, ==, 0); - - g_assert(nmtst_main_loop_run(loop, 2000)); - - for (i = 0; info->addresses[i]; i++) { - gboolean val; - char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - - val = nm_acd_manager_check_address(manager, info->addresses[i]); - if (val == info->expected_result[i]) - continue; - - if (wait_time == WAIT_TIME_OPTIMISTIC) { - /* probably we just had a glitch and the system took longer than - * expected. Re-verify with a large timeout this time. */ - wait_time = 1000; - goto again; - } - - g_error("expected check for address #%d (%s) to %s, but it didn't", - i, - _nm_utils_inet4_ntop(info->addresses[i], sbuf), - info->expected_result[i] ? "detect no duplicated" : "detect a duplicate"); - } -} - -static void -test_acd_probe_1(test_fixture *fixture, gconstpointer user_data) -{ - TestInfo info = {.addresses = {ADDR1, ADDR2, ADDR3}, - .peer_addresses = {ADDR4}, - .expected_result = {TRUE, TRUE, TRUE}}; - - test_acd_common(fixture, &info); -} - -static void -test_acd_probe_2(test_fixture *fixture, gconstpointer user_data) -{ - TestInfo info = {.addresses = {ADDR1, ADDR2, ADDR3, ADDR4}, - .peer_addresses = {ADDR3, ADDR2}, - .expected_result = {TRUE, FALSE, FALSE, TRUE}}; - - test_acd_common(fixture, &info); -} - -static void -test_acd_announce(test_fixture *fixture, gconstpointer user_data) -{ - nm_auto_free_acdmgr NMAcdManager *manager = NULL; - nm_auto_unref_gmainloop GMainLoop *loop = NULL; - int r; - - if (_skip_acd_test()) - return; - - manager = - nm_acd_manager_new(fixture->ifindex0, fixture->hwaddr0, fixture->hwaddr0_len, NULL, NULL); - g_assert(manager != NULL); - - g_assert(nm_acd_manager_add_address(manager, ADDR1)); - g_assert(nm_acd_manager_add_address(manager, ADDR2)); - - loop = g_main_loop_new(NULL, FALSE); - r = nm_acd_manager_announce_addresses(manager); - g_assert_cmpint(r, ==, 0); - g_assert(!nmtst_main_loop_run(loop, 200)); -} - -static void -fixture_teardown(test_fixture *fixture, gconstpointer user_data) -{ - nm_platform_link_delete(NM_PLATFORM_GET, fixture->ifindex0); - nm_platform_link_delete(NM_PLATFORM_GET, fixture->ifindex1); -} - -NMTstpSetupFunc const _nmtstp_setup_platform_func = nm_linux_platform_setup; - -void -_nmtstp_init_tests(int *argc, char ***argv) -{ - nmtst_init_with_logging(argc, argv, NULL, "ALL"); -} - -void -_nmtstp_setup_tests(void) -{ - g_test_add("/acd/probe/1", - test_fixture, - NULL, - fixture_setup, - test_acd_probe_1, - fixture_teardown); - g_test_add("/acd/probe/2", - test_fixture, - NULL, - fixture_setup, - test_acd_probe_2, - fixture_teardown); - g_test_add("/acd/announce", - test_fixture, - NULL, - fixture_setup, - test_acd_announce, - fixture_teardown); -} diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c deleted file mode 100644 index 5c912b7d..00000000 --- a/src/devices/tests/test-lldp.c +++ /dev/null @@ -1,1296 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <fcntl.h> -#include <linux/if_tun.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include "devices/nm-lldp-listener.h" -#include "systemd/nm-sd.h" - -#include "platform/tests/test-common.h" - -#include "nm-test-utils-core.h" - -/*****************************************************************************/ - -static GVariant * -get_lldp_neighbor(GVariant * neighbors, - int chassis_id_type, - const char *chassis_id, - int port_id_type, - const char *port_id) -{ - GVariantIter iter; - GVariant * variant; - GVariant * result = NULL; - - nmtst_assert_variant_is_of_type(neighbors, G_VARIANT_TYPE("aa{sv}")); - - g_assert(chassis_id_type >= -1 && chassis_id_type <= G_MAXUINT8); - g_assert(port_id_type >= -1 && port_id_type <= G_MAXUINT8); - - g_variant_iter_init(&iter, neighbors); - while (g_variant_iter_next(&iter, "@a{sv}", &variant)) { - gs_unref_variant GVariant *v_chassis_id_type = NULL; - gs_unref_variant GVariant *v_chassis_id = NULL; - gs_unref_variant GVariant *v_port_id_type = NULL; - gs_unref_variant GVariant *v_port_id = NULL; - - v_chassis_id_type = - g_variant_lookup_value(variant, NM_LLDP_ATTR_CHASSIS_ID_TYPE, G_VARIANT_TYPE_UINT32); - g_assert(v_chassis_id_type); - - v_chassis_id = - g_variant_lookup_value(variant, NM_LLDP_ATTR_CHASSIS_ID, G_VARIANT_TYPE_STRING); - g_assert(v_chassis_id); - - v_port_id_type = - g_variant_lookup_value(variant, NM_LLDP_ATTR_PORT_ID_TYPE, G_VARIANT_TYPE_UINT32); - g_assert(v_port_id_type); - - v_port_id = g_variant_lookup_value(variant, NM_LLDP_ATTR_PORT_ID, G_VARIANT_TYPE_STRING); - g_assert(v_port_id); - - if (nm_streq(g_variant_get_string(v_chassis_id, NULL), chassis_id) - && nm_streq(g_variant_get_string(v_port_id, NULL), port_id) - && NM_IN_SET(chassis_id_type, -1, g_variant_get_uint32(v_chassis_id_type)) - && NM_IN_SET(port_id_type, -1, g_variant_get_uint32(v_port_id_type))) { - g_assert(!result); - result = variant; - } else - g_variant_unref(variant); - } - - return result; -} - -typedef struct { - int ifindex; - int fd; - guint8 mac[ETH_ALEN]; -} TestRecvFixture; - -typedef struct { - gsize frame_len; - const uint8_t *frame; - const char * as_variant; -} TestRecvFrame; -#define TEST_RECV_FRAME_DEFINE(name, _as_variant, ...) \ - static const guint8 _##name##_v[] = {__VA_ARGS__}; \ - static const TestRecvFrame name = { \ - .as_variant = _as_variant, \ - .frame_len = sizeof(_##name##_v), \ - .frame = _##name##_v, \ - } - -typedef struct { - guint expected_num_called; - gsize frames_len; - const TestRecvFrame *frames[10]; - void (*check)(GMainLoop *loop, NMLldpListener *listener); -} TestRecvData; -#define TEST_RECV_DATA_DEFINE(name, _expected_num_called, _check, ...) \ - static const TestRecvData name = { \ - .expected_num_called = _expected_num_called, \ - .check = _check, \ - .frames_len = NM_NARG(__VA_ARGS__), \ - .frames = {__VA_ARGS__}, \ - } - -#define TEST_IFNAME "nm-tap-test0" - -TEST_RECV_FRAME_DEFINE( - _test_recv_data0_frame0, - "{'raw': <[byte 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x88, " - "0xcc, 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x04, 0x04, 0x05, 0x31, 0x2f, " - "0x33, 0x06, 0x02, 0x00, 0x78, 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x0a, 0x03, 0x53, 0x59, " - "0x53, 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00]>, 'chassis-id-type': <uint32 4>, " - "'chassis-id': <'00:01:02:03:04:05'>, 'port-id-type': <uint32 5>, 'port-id': <'1/3'>, " - "'destination': <'nearest-non-tpmr-bridge'>, 'port-description': <'Port'>, 'system-name': " - "<'SYS'>, 'system-description': <'foo'>}", - /* Ethernet header */ - 0x01, - 0x80, - 0xc2, - 0x00, - 0x00, - 0x03, /* Destination MAC */ - 0x01, - 0x02, - 0x03, - 0x04, - 0x05, - 0x06, /* Source MAC */ - 0x88, - 0xcc, /* Ethertype */ - /* LLDP mandatory TLVs */ - 0x02, - 0x07, - 0x04, - 0x00, - 0x01, - 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */ - 0x03, - 0x04, - 0x05, - 0x04, - 0x04, - 0x05, - 0x31, - 0x2f, - 0x33, /* Port: interface name, "1/3" */ - 0x06, - 0x02, - 0x00, - 0x78, /* TTL: 120 seconds */ - /* LLDP optional TLVs */ - 0x08, - 0x04, - 0x50, - 0x6f, - 0x72, - 0x74, /* Port Description: "Port" */ - 0x0a, - 0x03, - 0x53, - 0x59, - 0x53, /* System Name: "SYS" */ - 0x0c, - 0x04, - 0x66, - 0x6f, - 0x6f, - 0x00, /* System Description: "foo" (NULL-terminated) */ - 0x00, - 0x00 /* End Of LLDPDU */ -); - -static void -_test_recv_data0_check_do(GMainLoop *loop, NMLldpListener *listener, const TestRecvFrame *frame) -{ - GVariant * neighbors, *attr; - gs_unref_variant GVariant *neighbor = NULL; - - neighbors = nm_lldp_listener_get_neighbors(listener); - nmtst_assert_variant_is_of_type(neighbors, G_VARIANT_TYPE("aa{sv}")); - g_assert_cmpint(g_variant_n_children(neighbors), ==, 1); - - neighbor = get_lldp_neighbor(neighbors, - SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, - "00:01:02:03:04:05", - SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME, - "1/3"); - g_assert(neighbor); - g_assert_cmpint(g_variant_n_children(neighbor), ==, 1 + 4 + 4); - - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_RAW, G_VARIANT_TYPE_BYTESTRING); - nmtst_assert_variant_bytestring(attr, frame->frame, frame->frame_len); - nm_clear_g_variant(&attr); - - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_PORT_DESCRIPTION, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string(attr, "Port"); - nm_clear_g_variant(&attr); - - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_SYSTEM_NAME, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string(attr, "SYS"); - nm_clear_g_variant(&attr); - - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_DESTINATION, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string(attr, NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE); - nm_clear_g_variant(&attr); - - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string(attr, "foo"); - nm_clear_g_variant(&attr); -} - -static void -_test_recv_data0_check(GMainLoop *loop, NMLldpListener *listener) -{ - _test_recv_data0_check_do(loop, listener, &_test_recv_data0_frame0); -} - -TEST_RECV_DATA_DEFINE(_test_recv_data0, 1, _test_recv_data0_check, &_test_recv_data0_frame0); -TEST_RECV_DATA_DEFINE(_test_recv_data0_twice, - 1, - _test_recv_data0_check, - &_test_recv_data0_frame0, - &_test_recv_data0_frame0); - -TEST_RECV_FRAME_DEFINE( - _test_recv_data1_frame0, - /* lldp.detailed.pcap from - * https://wiki.wireshark.org/SampleCaptures#Link_Layer_Discovery_Protocol_.28LLDP.29 */ - "{'raw': <[byte 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0, 0x88, " - "0xcc, 0x02, 0x07, 0x04, 0x00, 0x01, 0x30, 0xf9, 0xad, 0xa0, 0x04, 0x04, 0x05, 0x31, 0x2f, " - "0x31, 0x06, 0x02, 0x00, 0x78, 0x08, 0x17, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, " - "0x30, 0x2d, 0x34, 0x38, 0x2d, 0x50, 0x6f, 0x72, 0x74, 0x20, 0x31, 0x30, 0x30, 0x31, 0x00, " - "0x0a, 0x0d, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x00, " - "0x0c, 0x4c, 0x53, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x33, 0x30, 0x30, 0x2d, 0x34, 0x38, 0x20, " - "0x2d, 0x20, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x37, 0x2e, 0x34, 0x65, 0x2e, " - "0x31, 0x20, 0x28, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x20, 0x35, 0x29, 0x20, 0x62, 0x79, 0x20, " - "0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, " - "0x30, 0x35, 0x2f, 0x32, 0x37, 0x2f, 0x30, 0x35, 0x20, 0x30, 0x34, 0x3a, 0x35, 0x33, 0x3a, " - "0x31, 0x31, 0x00, 0x0e, 0x04, 0x00, 0x14, 0x00, 0x14, 0x10, 0x0e, 0x07, 0x06, 0x00, 0x01, " - "0x30, 0xf9, 0xad, 0xa0, 0x02, 0x00, 0x00, 0x03, 0xe9, 0x00, 0xfe, 0x07, 0x00, 0x12, 0x0f, " - "0x02, 0x07, 0x01, 0x00, 0xfe, 0x09, 0x00, 0x12, 0x0f, 0x01, 0x03, 0x6c, 0x00, 0x00, 0x10, " - "0xfe, 0x09, 0x00, 0x12, 0x0f, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x00, 0x12, " - "0x0f, 0x04, 0x05, 0xf2, 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, 0x01, 0xe8, 0xfe, 0x07, 0x00, " - "0x80, 0xc2, 0x02, 0x01, 0x00, 0x00, 0xfe, 0x16, 0x00, 0x80, 0xc2, 0x03, 0x01, 0xe8, 0x0f, " - "0x76, 0x32, 0x2d, 0x30, 0x34, 0x38, 0x38, 0x2d, 0x30, 0x33, 0x2d, 0x30, 0x35, 0x30, 0x35, " - "0xfe, 0x05, 0x00, 0x80, 0xc2, 0x04, 0x00, 0x00, 0x00]>, 'chassis-id-type': <uint32 4>, " - "'chassis-id': <'00:01:30:F9:AD:A0'>, 'port-id-type': <uint32 5>, 'port-id': <'1/1'>, " - "'destination': <'nearest-bridge'>, 'port-description': <'Summit300-48-Port 1001'>, " - "'system-name': <'Summit300-48'>, 'system-description': <'Summit300-48 - Version 7.4e.1 (Build " - "5) by Release_Master 05/27/05 04:53:11'>, 'system-capabilities': <uint32 20>, " - "'management-addresses': <[{'address-subtype': <uint32 6>, 'address': <[byte 0x00, 0x01, 0x30, " - "0xf9, 0xad, 0xa0]>, 'interface-number-subtype': <uint32 2>, 'interface-number': <uint32 " - "1001>}]>, 'ieee-802-1-pvid': <uint32 488>, 'ieee-802-1-ppvid': <uint32 0>, " - "'ieee-802-1-ppvid-flags': <uint32 1>, 'ieee-802-1-ppvids': <[{'ppvid': <uint32 0>, 'flags': " - "<uint32 1>}]>, 'ieee-802-1-vid': <uint32 488>, 'ieee-802-1-vlan-name': <'v2-0488-03-0505'>, " - "'ieee-802-1-vlans': <[{'vid': <uint32 488>, 'name': <'v2-0488-03-0505'>}]>, " - "'ieee-802-3-mac-phy-conf': <{'autoneg': <uint32 3>, 'pmd-autoneg-cap': <uint32 27648>, " - "'operational-mau-type': <uint32 16>}>, 'ieee-802-3-power-via-mdi': <{'mdi-power-support': " - "<uint32 7>, 'pse-power-pair': <uint32 1>, 'power-class': <uint32 0>}>, " - "'ieee-802-3-max-frame-size': <uint32 1522>}", - /* ethernet header */ - 0x01, - 0x80, - 0xc2, - 0x00, - 0x00, - 0x0e, /* destination mac */ - 0x00, - 0x01, - 0x30, - 0xf9, - 0xad, - 0xa0, /* source mac */ - 0x88, - 0xcc, /* ethernet type */ - - 0x02, - 0x07, - 0x04, - 0x00, - 0x01, - 0x30, /* Chassis Subtype */ - 0xf9, - 0xad, - 0xa0, - 0x04, - 0x04, - 0x05, - 0x31, - 0x2f, - 0x31, /* Port Subtype */ - 0x06, - 0x02, - 0x00, - 0x78, /* Time To Live */ - 0x08, - 0x17, - 0x53, - 0x75, - 0x6d, - 0x6d, /* Port Description */ - 0x69, - 0x74, - 0x33, - 0x30, - 0x30, - 0x2d, - 0x34, - 0x38, - 0x2d, - 0x50, - 0x6f, - 0x72, - 0x74, - 0x20, - 0x31, - 0x30, - 0x30, - 0x31, - 0x00, - 0x0a, - 0x0d, - 0x53, - 0x75, - 0x6d, - 0x6d, /* System Name */ - 0x69, - 0x74, - 0x33, - 0x30, - 0x30, - 0x2d, - 0x34, - 0x38, - 0x00, - 0x0c, - 0x4c, - 0x53, - 0x75, - 0x6d, - 0x6d, /* System Description */ - 0x69, - 0x74, - 0x33, - 0x30, - 0x30, - 0x2d, - 0x34, - 0x38, - 0x20, - 0x2d, - 0x20, - 0x56, - 0x65, - 0x72, - 0x73, - 0x69, - 0x6f, - 0x6e, - 0x20, - 0x37, - 0x2e, - 0x34, - 0x65, - 0x2e, - 0x31, - 0x20, - 0x28, - 0x42, - 0x75, - 0x69, - 0x6c, - 0x64, - 0x20, - 0x35, - 0x29, - 0x20, - 0x62, - 0x79, - 0x20, - 0x52, - 0x65, - 0x6c, - 0x65, - 0x61, - 0x73, - 0x65, - 0x5f, - 0x4d, - 0x61, - 0x73, - 0x74, - 0x65, - 0x72, - 0x20, - 0x30, - 0x35, - 0x2f, - 0x32, - 0x37, - 0x2f, - 0x30, - 0x35, - 0x20, - 0x30, - 0x34, - 0x3a, - 0x35, - 0x33, - 0x3a, - 0x31, - 0x31, - 0x00, - 0x0e, - 0x04, - 0x00, - 0x14, - 0x00, - 0x14, /* Capabilities */ - 0x10, - 0x0e, - 0x07, - 0x06, - 0x00, - 0x01, /* Management Address */ - 0x30, - 0xf9, - 0xad, - 0xa0, - 0x02, - 0x00, - 0x00, - 0x03, - 0xe9, - 0x00, - 0xfe, - 0x07, - 0x00, - 0x12, - 0x0f, - 0x02, /* IEEE 802.3 - Power Via MDI */ - 0x07, - 0x01, - 0x00, - 0xfe, - 0x09, - 0x00, - 0x12, - 0x0f, - 0x01, /* IEEE 802.3 - MAC/PHY Configuration/Status */ - 0x03, - 0x6c, - 0x00, - 0x00, - 0x10, - 0xfe, - 0x09, - 0x00, - 0x12, - 0x0f, - 0x03, /* IEEE 802.3 - Link Aggregation */ - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0xfe, - 0x06, - 0x00, - 0x12, - 0x0f, - 0x04, /* IEEE 802.3 - Maximum Frame Size */ - 0x05, - 0xf2, - 0xfe, - 0x06, - 0x00, - 0x80, - 0xc2, - 0x01, /* IEEE 802.1 - Port VLAN ID */ - 0x01, - 0xe8, - 0xfe, - 0x07, - 0x00, - 0x80, - 0xc2, - 0x02, /* IEEE 802.1 - Port and Protocol VLAN ID */ - 0x01, - 0x00, - 0x00, - 0xfe, - 0x16, - 0x00, - 0x80, - 0xc2, - 0x03, /* IEEE 802.1 - VLAN Name */ - 0x01, - 0xe8, - 0x0f, - 0x76, - 0x32, - 0x2d, - 0x30, - 0x34, - 0x38, - 0x38, - 0x2d, - 0x30, - 0x33, - 0x2d, - 0x30, - 0x35, - 0x30, - 0x35, - 0xfe, - 0x05, - 0x00, - 0x80, - 0xc2, - 0x04, /* IEEE 802.1 - Protocol Identity */ - 0x00, - 0x00, - 0x00 /* End of LLDPDU */ -); - -static void -_test_recv_data1_check(GMainLoop *loop, NMLldpListener *listener) -{ - GVariant * neighbors, *attr, *child; - gs_unref_variant GVariant *neighbor = NULL; - guint v_uint = 0; - const char * v_str = NULL; - - neighbors = nm_lldp_listener_get_neighbors(listener); - nmtst_assert_variant_is_of_type(neighbors, G_VARIANT_TYPE("aa{sv}")); - g_assert_cmpint(g_variant_n_children(neighbors), ==, 1); - - neighbor = get_lldp_neighbor(neighbors, - SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS, - "00:01:30:F9:AD:A0", - SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME, - "1/1"); - g_assert(neighbor); - g_assert_cmpint(g_variant_n_children(neighbor), ==, 1 + 4 + 16); - - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_RAW, G_VARIANT_TYPE_BYTESTRING); - nmtst_assert_variant_bytestring(attr, - _test_recv_data1_frame0.frame, - _test_recv_data1_frame0.frame_len); - nm_clear_g_variant(&attr); - - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_DESTINATION, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string(attr, NM_LLDP_DEST_NEAREST_BRIDGE); - nm_clear_g_variant(&attr); - - /* unsupported: Time To Live */ - - /* Port Description */ - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_PORT_DESCRIPTION, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string(attr, "Summit300-48-Port 1001"); - nm_clear_g_variant(&attr); - - /* System Name */ - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_SYSTEM_NAME, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string(attr, "Summit300-48"); - nm_clear_g_variant(&attr); - - /* System Description */ - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string( - attr, - "Summit300-48 - Version 7.4e.1 (Build 5) by Release_Master 05/27/05 04:53:11"); - nm_clear_g_variant(&attr); - - /* Capabilities */ - attr = - g_variant_lookup_value(neighbor, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, G_VARIANT_TYPE_UINT32); - nmtst_assert_variant_uint32(attr, 20); - nm_clear_g_variant(&attr); - - /* Management Address */ - attr = g_variant_lookup_value(neighbor, - NM_LLDP_ATTR_MANAGEMENT_ADDRESSES, - G_VARIANT_TYPE("aa{sv}")); - g_assert(attr); - g_assert_cmpuint(g_variant_n_children(attr), ==, 1); - child = g_variant_get_child_value(attr, 0); - g_assert(child); - g_assert(g_variant_lookup(child, "interface-number", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 1001); - g_assert(g_variant_lookup(child, "interface-number-subtype", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 2); - g_assert(g_variant_lookup(child, "address-subtype", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 6); - nm_clear_g_variant(&child); - nm_clear_g_variant(&attr); - - /* IEEE 802.3 - Power Via MDI */ - attr = g_variant_lookup_value(neighbor, - NM_LLDP_ATTR_IEEE_802_3_POWER_VIA_MDI, - G_VARIANT_TYPE_VARDICT); - g_assert(attr); - g_assert(g_variant_lookup(attr, "mdi-power-support", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 7); - g_assert(g_variant_lookup(attr, "pse-power-pair", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 1); - g_assert(g_variant_lookup(attr, "power-class", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 0); - nm_clear_g_variant(&attr); - - /* IEEE 802.3 - MAC/PHY Configuration/Status */ - attr = g_variant_lookup_value(neighbor, - NM_LLDP_ATTR_IEEE_802_3_MAC_PHY_CONF, - G_VARIANT_TYPE_VARDICT); - g_assert(attr); - g_assert(g_variant_lookup(attr, "autoneg", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 3); - g_assert(g_variant_lookup(attr, "pmd-autoneg-cap", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 0x6c00); - g_assert(g_variant_lookup(attr, "operational-mau-type", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 16); - nm_clear_g_variant(&attr); - - /* unsupported: IEEE 802.3 - Link Aggregation */ - - /* Maximum Frame Size */ - attr = g_variant_lookup_value(neighbor, - NM_LLDP_ATTR_IEEE_802_3_MAX_FRAME_SIZE, - G_VARIANT_TYPE_UINT32); - nmtst_assert_variant_uint32(attr, 1522); - nm_clear_g_variant(&attr); - - /* IEEE 802.1 - Port VLAN ID */ - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_PVID, G_VARIANT_TYPE_UINT32); - nmtst_assert_variant_uint32(attr, 488); - nm_clear_g_variant(&attr); - - /* IEEE 802.1 - Port and Protocol VLAN ID */ - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVID, G_VARIANT_TYPE_UINT32); - nmtst_assert_variant_uint32(attr, 0); - nm_clear_g_variant(&attr); - attr = g_variant_lookup_value(neighbor, - NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, - G_VARIANT_TYPE_UINT32); - nmtst_assert_variant_uint32(attr, 1); - nm_clear_g_variant(&attr); - - /* new PPVID attributes */ - attr = - g_variant_lookup_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_PPVIDS, G_VARIANT_TYPE("aa{sv}")); - g_assert_cmpuint(g_variant_n_children(attr), ==, 1); - child = g_variant_get_child_value(attr, 0); - g_assert(child); - g_assert(g_variant_lookup(child, "ppvid", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 0); - g_assert(g_variant_lookup(child, "flags", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 1); - nm_clear_g_variant(&child); - nm_clear_g_variant(&attr); - - /* IEEE 802.1 - VLAN Name */ - attr = - g_variant_lookup_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, G_VARIANT_TYPE_STRING); - nmtst_assert_variant_string(attr, "v2-0488-03-0505"); - nm_clear_g_variant(&attr); - attr = g_variant_lookup_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_VID, G_VARIANT_TYPE_UINT32); - nmtst_assert_variant_uint32(attr, 488); - nm_clear_g_variant(&attr); - - /* new VLAN attributes */ - attr = - g_variant_lookup_value(neighbor, NM_LLDP_ATTR_IEEE_802_1_VLANS, G_VARIANT_TYPE("aa{sv}")); - g_assert_cmpuint(g_variant_n_children(attr), ==, 1); - child = g_variant_get_child_value(attr, 0); - g_assert(child); - g_assert(g_variant_lookup(child, "vid", "u", &v_uint)); - g_assert_cmpint(v_uint, ==, 488); - g_assert(g_variant_lookup(child, "name", "&s", &v_str)); - g_assert_cmpstr(v_str, ==, "v2-0488-03-0505"); - nm_clear_g_variant(&child); - nm_clear_g_variant(&attr); - - /* unsupported: IEEE 802.1 - Protocol Identity */ -} - -TEST_RECV_DATA_DEFINE(_test_recv_data1, 1, _test_recv_data1_check, &_test_recv_data1_frame0); - -TEST_RECV_FRAME_DEFINE( - _test_recv_data2_frame0_ttl1, - "{'raw': <[byte 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x88, " - "0xcc, 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x04, 0x04, 0x05, 0x31, 0x2f, " - "0x33, 0x06, 0x02, 0x00, 0x01, 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, 0x0a, 0x03, 0x53, 0x59, " - "0x53, 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, 0x00, 0x00]>, 'chassis-id-type': <uint32 4>, " - "'chassis-id': <'00:01:02:03:04:05'>, 'port-id-type': <uint32 5>, 'port-id': <'1/3'>, " - "'destination': <'nearest-non-tpmr-bridge'>, 'port-description': <'Port'>, 'system-name': " - "<'SYS'>, 'system-description': <'foo'>}", - /* Ethernet header */ - 0x01, - 0x80, - 0xc2, - 0x00, - 0x00, - 0x03, /* Destination MAC */ - 0x01, - 0x02, - 0x03, - 0x04, - 0x05, - 0x06, /* Source MAC */ - 0x88, - 0xcc, /* Ethertype */ - /* LLDP mandatory TLVs */ - 0x02, - 0x07, - 0x04, - 0x00, - 0x01, - 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */ - 0x03, - 0x04, - 0x05, - 0x04, - 0x04, - 0x05, - 0x31, - 0x2f, - 0x33, /* Port: interface name, "1/3" */ - 0x06, - 0x02, - 0x00, - 0x01, /* TTL: 1 seconds */ - /* LLDP optional TLVs */ - 0x08, - 0x04, - 0x50, - 0x6f, - 0x72, - 0x74, /* Port Description: "Port" */ - 0x0a, - 0x03, - 0x53, - 0x59, - 0x53, /* System Name: "SYS" */ - 0x0c, - 0x04, - 0x66, - 0x6f, - 0x6f, - 0x00, /* System Description: "foo" (NULL-terminated) */ - 0x00, - 0x00 /* End Of LLDPDU */ -); - -static void -_test_recv_data2_ttl1_check(GMainLoop *loop, NMLldpListener *listener) -{ - gulong notify_id; - GVariant *neighbors; - - _test_recv_data0_check_do(loop, listener, &_test_recv_data2_frame0_ttl1); - - /* wait for signal. */ - notify_id = g_signal_connect(listener, - "notify::" NM_LLDP_LISTENER_NEIGHBORS, - nmtst_main_loop_quit_on_notify, - loop); - if (!nmtst_main_loop_run(loop, 5000)) - g_assert_not_reached(); - nm_clear_g_signal_handler(listener, ¬ify_id); - - neighbors = nm_lldp_listener_get_neighbors(listener); - nmtst_assert_variant_is_of_type(neighbors, G_VARIANT_TYPE("aa{sv}")); - g_assert_cmpint(g_variant_n_children(neighbors), ==, 0); -} - -TEST_RECV_DATA_DEFINE(_test_recv_data2_ttl1, - 1, - _test_recv_data2_ttl1_check, - &_test_recv_data2_frame0_ttl1); - -static void -_test_recv_fixture_setup(TestRecvFixture *fixture, gconstpointer user_data) -{ - const NMPlatformLink *link; - nm_auto_close int fd = -1; - - fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC); - if (fd == -1) { - g_test_skip("Unable to open /dev/net/tun"); - fixture->ifindex = 0; - return; - } - - if (nmtst_get_rand_bool()) { - const NMPlatformLnkTun lnk = { - .type = IFF_TAP, - .pi = FALSE, - .vnet_hdr = FALSE, - .multi_queue = FALSE, - .persist = FALSE, - }; - - nm_close(nm_steal_fd(&fd)); - - link = nmtstp_link_tun_add(NM_PLATFORM_GET, FALSE, TEST_IFNAME, &lnk, &fd); - g_assert(link); - nmtstp_link_set_updown(NM_PLATFORM_GET, -1, link->ifindex, TRUE); - link = nmtstp_assert_wait_for_link(NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TUN, 0); - } else { - int s; - struct ifreq ifr = {}; - - ifr.ifr_flags = IFF_TAP | IFF_NO_PI; - nm_utils_ifname_cpy(ifr.ifr_name, TEST_IFNAME); - g_assert(ioctl(fd, TUNSETIFF, &ifr) >= 0); - - /* Bring the interface up */ - s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); - g_assert(s >= 0); - ifr.ifr_flags |= IFF_UP; - g_assert(ioctl(s, SIOCSIFFLAGS, &ifr) >= 0); - nm_close(s); - - link = nmtstp_assert_wait_for_link(NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TUN, 100); - } - - fixture->ifindex = link->ifindex; - fixture->fd = nm_steal_fd(&fd); - memcpy(fixture->mac, link->l_address.data, ETH_ALEN); -} - -typedef struct { - int num_called; -} TestRecvCallbackInfo; - -static void -lldp_neighbors_changed(NMLldpListener *lldp_listener, GParamSpec *pspec, gpointer user_data) -{ - TestRecvCallbackInfo *info = user_data; - - info->num_called++; -} - -static void -test_recv(TestRecvFixture *fixture, gconstpointer user_data) -{ - const TestRecvData *data = user_data; - gs_unref_object NMLldpListener *listener = NULL; - GMainLoop * loop; - TestRecvCallbackInfo info = {}; - gsize i_frames; - gulong notify_id; - GError * error = NULL; - guint sd_id; - - if (fixture->ifindex == 0) { - g_test_skip("Tun device not available"); - return; - } - - listener = nm_lldp_listener_new(); - g_assert(listener != NULL); - g_assert(nm_lldp_listener_start(listener, fixture->ifindex, &error)); - g_assert_no_error(error); - - notify_id = g_signal_connect(listener, - "notify::" NM_LLDP_LISTENER_NEIGHBORS, - (GCallback) lldp_neighbors_changed, - &info); - loop = g_main_loop_new(NULL, FALSE); - sd_id = nm_sd_event_attach_default(); - - for (i_frames = 0; i_frames < data->frames_len; i_frames++) { - const TestRecvFrame *f = data->frames[i_frames]; - - g_assert(write(fixture->fd, f->frame, f->frame_len) == f->frame_len); - } - - if (nmtst_main_loop_run(loop, 500)) - g_assert_not_reached(); - - g_assert_cmpint(info.num_called, ==, data->expected_num_called); - - nm_clear_g_signal_handler(listener, ¬ify_id); - - data->check(loop, listener); - - nm_clear_g_source(&sd_id); - nm_clear_pointer(&loop, g_main_loop_unref); -} - -static void -_test_recv_fixture_teardown(TestRecvFixture *fixture, gconstpointer user_data) -{ - if (fixture->ifindex) - nm_platform_link_delete(NM_PLATFORM_GET, fixture->ifindex); -} - -/*****************************************************************************/ - -static void -test_parse_frames(gconstpointer test_data) -{ - const TestRecvFrame *frame = test_data; - gs_unref_variant GVariant *v_neighbor = NULL; - gs_unref_variant GVariant *attr = NULL; - gs_free char * as_variant = NULL; - - v_neighbor = nmtst_lldp_parse_from_raw(frame->frame, frame->frame_len); - g_assert(v_neighbor); - - attr = g_variant_lookup_value(v_neighbor, NM_LLDP_ATTR_RAW, G_VARIANT_TYPE_BYTESTRING); - nmtst_assert_variant_bytestring(attr, frame->frame, frame->frame_len); - nm_clear_g_variant(&attr); - - as_variant = g_variant_print(v_neighbor, TRUE); - g_assert(as_variant); - g_assert_cmpstr(frame->as_variant, ==, as_variant); -} - -/*****************************************************************************/ - -TEST_RECV_FRAME_DEFINE( - _test_parse_frames_3, - /* https://github.com/the-tcpdump-group/tcpdump/blob/c4f8796bf8bec740621a360eded236d8991ea00f/tests/lldp_mudurl.pcap */ - "{'raw': <[byte 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, 0x00, 0x23, 0x54, 0xc2, 0x57, 0x02, 0x88, " - "0xcc, 0x02, 0x07, 0x04, 0x00, 0x23, 0x54, 0xc2, 0x57, 0x02, 0x04, 0x07, 0x03, 0x00, 0x23, " - "0x54, 0xc2, 0x57, 0x02, 0x06, 0x02, 0x00, 0x78, 0x0a, 0x1c, 0x75, 0x70, 0x73, 0x74, 0x61, " - "0x69, 0x72, 0x73, 0x2e, 0x6f, 0x66, 0x63, 0x6f, 0x75, 0x72, 0x73, 0x65, 0x69, 0x6d, 0x72, " - "0x69, 0x67, 0x68, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x0c, 0x5c, 0x55, 0x62, 0x75, 0x6e, 0x74, " - "0x75, 0x20, 0x31, 0x34, 0x2e, 0x30, 0x34, 0x2e, 0x35, 0x20, 0x4c, 0x54, 0x53, 0x20, 0x4c, " - "0x69, 0x6e, 0x75, 0x78, 0x20, 0x33, 0x2e, 0x31, 0x33, 0x2e, 0x30, 0x2d, 0x31, 0x30, 0x36, " - "0x2d, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x20, 0x23, 0x31, 0x35, 0x33, 0x2d, 0x55, " - "0x62, 0x75, 0x6e, 0x74, 0x75, 0x20, 0x53, 0x4d, 0x50, 0x20, 0x54, 0x75, 0x65, 0x20, 0x44, " - "0x65, 0x63, 0x20, 0x36, 0x20, 0x31, 0x35, 0x3a, 0x34, 0x35, 0x3a, 0x31, 0x33, 0x20, 0x55, " - "0x54, 0x43, 0x20, 0x32, 0x30, 0x31, 0x36, 0x20, 0x69, 0x36, 0x38, 0x36, 0x0e, 0x04, 0x00, " - "0x9c, 0x00, 0x08, 0x10, 0x0c, 0x05, 0x01, 0x3e, 0x0c, 0xad, 0x72, 0x02, 0x00, 0x00, 0x00, " - "0x02, 0x00, 0x10, 0x18, 0x11, 0x02, 0x20, 0x01, 0x08, 0xa8, 0x10, 0x06, 0x00, 0x04, 0x02, " - "0x23, 0x54, 0xff, 0xfe, 0xc2, 0x57, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x04, " - "0x65, 0x74, 0x68, 0x30, 0xfe, 0x09, 0x00, 0x12, 0x0f, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, " - "0xfe, 0x09, 0x00, 0x12, 0x0f, 0x01, 0x03, 0xec, 0xc3, 0x00, 0x10, 0xfe, 0x40, 0x00, 0x00, " - "0x5e, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x69, 0x6d, 0x72, 0x69, 0x67, " - "0x68, 0x74, 0x2e, 0x6d, 0x75, 0x64, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, " - "0x63, 0x6f, 0x6d, 0x2f, 0x2e, 0x77, 0x65, 0x6c, 0x6c, 0x2d, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, " - "0x2f, 0x6d, 0x75, 0x64, 0x2f, 0x76, 0x31, 0x2f, 0x76, 0x6f, 0x6d, 0x69, 0x74, 0x76, 0x32, " - "0x2e, 0x30, 0x00, 0x00]>, 'chassis-id-type': <uint32 4>, 'chassis-id': <'00:23:54:C2:57:02'>, " - "'port-id-type': <uint32 3>, 'port-id': <'00:23:54:C2:57:02'>, 'destination': " - "<'nearest-bridge'>, 'port-description': <'eth0'>, 'system-name': " - "<'upstairs.ofcourseimright.com'>, 'system-description': <'Ubuntu 14.04.5 LTS Linux " - "3.13.0-106-generic #153-Ubuntu SMP Tue Dec 6 15:45:13 UTC 2016 i686'>, 'system-capabilities': " - "<uint32 156>, 'management-addresses': <[{'address-subtype': <uint32 1>, 'address': <[byte " - "0x3e, 0x0c, 0xad, 0x72]>, 'interface-number-subtype': <uint32 2>, 'interface-number': <uint32 " - "2>}, {'address-subtype': <uint32 2>, 'address': <[byte 0x20, 0x01, 0x08, 0xa8, 0x10, 0x06, " - "0x00, 0x04, 0x02, 0x23, 0x54, 0xff, 0xfe, 0xc2, 0x57, 0x02]>, 'interface-number-subtype': " - "<uint32 2>, 'interface-number': <uint32 2>}]>, 'ieee-802-3-mac-phy-conf': <{'autoneg': " - "<uint32 3>, 'pmd-autoneg-cap': <uint32 60611>, 'operational-mau-type': <uint32 16>}>, " - "'mud-url': <'https://imright.mud.example.com/.well-known/mud/v1/vomitv2.0'>}", - 0x01, - 0x80, - 0xc2, - 0x00, - 0x00, - 0x0e, /* ethernet destination */ - 0x00, - 0x23, - 0x54, - 0xc2, - 0x57, - 0x02, /* ethernet source */ - 0x88, - 0xcc, /* ethernet type */ - - 0x02, - 0x07, - 0x04, - 0x00, - 0x23, - 0x54, - 0xc2, - 0x57, - 0x02, - 0x04, - 0x07, - 0x03, - 0x00, - 0x23, - 0x54, - 0xc2, - 0x57, - 0x02, - 0x06, - 0x02, - 0x00, - 0x78, - 0x0a, - 0x1c, - 0x75, - 0x70, - 0x73, - 0x74, - 0x61, - 0x69, - 0x72, - 0x73, - 0x2e, - 0x6f, - 0x66, - 0x63, - 0x6f, - 0x75, - 0x72, - 0x73, - 0x65, - 0x69, - 0x6d, - 0x72, - 0x69, - 0x67, - 0x68, - 0x74, - 0x2e, - 0x63, - 0x6f, - 0x6d, - 0x0c, - 0x5c, - 0x55, - 0x62, - 0x75, - 0x6e, - 0x74, - 0x75, - 0x20, - 0x31, - 0x34, - 0x2e, - 0x30, - 0x34, - 0x2e, - 0x35, - 0x20, - 0x4c, - 0x54, - 0x53, - 0x20, - 0x4c, - 0x69, - 0x6e, - 0x75, - 0x78, - 0x20, - 0x33, - 0x2e, - 0x31, - 0x33, - 0x2e, - 0x30, - 0x2d, - 0x31, - 0x30, - 0x36, - 0x2d, - 0x67, - 0x65, - 0x6e, - 0x65, - 0x72, - 0x69, - 0x63, - 0x20, - 0x23, - 0x31, - 0x35, - 0x33, - 0x2d, - 0x55, - 0x62, - 0x75, - 0x6e, - 0x74, - 0x75, - 0x20, - 0x53, - 0x4d, - 0x50, - 0x20, - 0x54, - 0x75, - 0x65, - 0x20, - 0x44, - 0x65, - 0x63, - 0x20, - 0x36, - 0x20, - 0x31, - 0x35, - 0x3a, - 0x34, - 0x35, - 0x3a, - 0x31, - 0x33, - 0x20, - 0x55, - 0x54, - 0x43, - 0x20, - 0x32, - 0x30, - 0x31, - 0x36, - 0x20, - 0x69, - 0x36, - 0x38, - 0x36, - 0x0e, - 0x04, - 0x00, - 0x9c, - 0x00, - 0x08, - 0x10, - 0x0c, - 0x05, - 0x01, - 0x3e, - 0x0c, - 0xad, - 0x72, - 0x02, - 0x00, - 0x00, - 0x00, - 0x02, - 0x00, - 0x10, - 0x18, - 0x11, - 0x02, - 0x20, - 0x01, - 0x08, - 0xa8, - 0x10, - 0x06, - 0x00, - 0x04, - 0x02, - 0x23, - 0x54, - 0xff, - 0xfe, - 0xc2, - 0x57, - 0x02, - 0x02, - 0x00, - 0x00, - 0x00, - 0x02, - 0x00, - 0x08, - 0x04, - 0x65, - 0x74, - 0x68, - 0x30, - 0xfe, - 0x09, - 0x00, - 0x12, - 0x0f, - 0x03, - 0x01, - 0x00, - 0x00, - 0x00, - 0x00, - 0xfe, - 0x09, - 0x00, - 0x12, - 0x0f, - 0x01, - 0x03, - 0xec, - 0xc3, - 0x00, - 0x10, - 0xfe, - 0x40, - 0x00, - 0x00, - 0x5e, - 0x01, - 0x68, - 0x74, - 0x74, - 0x70, - 0x73, - 0x3a, - 0x2f, - 0x2f, - 0x69, - 0x6d, - 0x72, - 0x69, - 0x67, - 0x68, - 0x74, - 0x2e, - 0x6d, - 0x75, - 0x64, - 0x2e, - 0x65, - 0x78, - 0x61, - 0x6d, - 0x70, - 0x6c, - 0x65, - 0x2e, - 0x63, - 0x6f, - 0x6d, - 0x2f, - 0x2e, - 0x77, - 0x65, - 0x6c, - 0x6c, - 0x2d, - 0x6b, - 0x6e, - 0x6f, - 0x77, - 0x6e, - 0x2f, - 0x6d, - 0x75, - 0x64, - 0x2f, - 0x76, - 0x31, - 0x2f, - 0x76, - 0x6f, - 0x6d, - 0x69, - 0x74, - 0x76, - 0x32, - 0x2e, - - 0x30, - 0x00, - 0x00, /* ethernet trailer */ -); - -/*****************************************************************************/ - -NMTstpSetupFunc const _nmtstp_setup_platform_func = nm_linux_platform_setup; - -void -_nmtstp_init_tests(int *argc, char ***argv) -{ - nmtst_init_assert_logging(argc, argv, "WARN", "ALL"); -} - -void -_nmtstp_setup_tests(void) -{ -#define _TEST_ADD_RECV(testpath, testdata) \ - g_test_add(testpath, \ - TestRecvFixture, \ - testdata, \ - _test_recv_fixture_setup, \ - test_recv, \ - _test_recv_fixture_teardown) - _TEST_ADD_RECV("/lldp/recv/0", &_test_recv_data0); - _TEST_ADD_RECV("/lldp/recv/0_twice", &_test_recv_data0_twice); - _TEST_ADD_RECV("/lldp/recv/1", &_test_recv_data1); - _TEST_ADD_RECV("/lldp/recv/2_ttl1", &_test_recv_data2_ttl1); - - g_test_add_data_func("/lldp/parse-frames/0", &_test_recv_data0_frame0, test_parse_frames); - g_test_add_data_func("/lldp/parse-frames/1", &_test_recv_data1_frame0, test_parse_frames); - g_test_add_data_func("/lldp/parse-frames/2", &_test_recv_data2_frame0_ttl1, test_parse_frames); - g_test_add_data_func("/lldp/parse-frames/3", &_test_parse_frames_3, test_parse_frames); -} diff --git a/src/devices/wifi/meson.build b/src/devices/wifi/meson.build deleted file mode 100644 index 00404c71..00000000 --- a/src/devices/wifi/meson.build +++ /dev/null @@ -1,67 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -iwd_sources = files() -if enable_iwd - iwd_sources += files( - 'nm-device-iwd.c', - 'nm-iwd-manager.c', - ) -endif - -libnm_wifi_base = static_library( - 'nm-wifi-base', - sources: files( - 'nm-device-olpc-mesh.c', - 'nm-device-wifi-p2p.c', - 'nm-device-wifi.c', - 'nm-wifi-ap.c', - 'nm-wifi-common.c', - 'nm-wifi-p2p-peer.c', - 'nm-wifi-utils.c', - ) + iwd_sources, - dependencies: daemon_nm_default_dep, - c_args: daemon_c_flags, -) - -libnm_wifi_base_dep = declare_dependency( - link_with: libnm_wifi_base, -) - -libnm_device_plugin_wifi = shared_module( - 'nm-device-plugin-wifi', - sources: files( - 'nm-wifi-factory.c', - ), - dependencies: [ daemon_nm_default_dep, libnm_wifi_base_dep ], - c_args: daemon_c_flags, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_plugindir, -) - -core_plugins += libnm_device_plugin_wifi - -test( - 'check-local-devices-wifi', - check_exports, - args: [libnm_device_plugin_wifi.full_path(), linker_script_devices], -) - -if enable_tests - test_unit = 'test-devices-wifi' - - exe = executable( - test_unit, - 'tests/' + test_unit + '.c', - dependencies: [ libnetwork_manager_test_dep, libnm_wifi_base_dep ], - c_args: test_c_flags, - ) - - test( - test_unit, - test_script, - args: test_args + [exe.full_path()], - timeout: default_test_timeout, - ) -endif diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c deleted file mode 100644 index 64ac3de7..00000000 --- a/src/devices/wifi/nm-device-iwd.c +++ /dev/null @@ -1,2702 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Intel Corporation - */ - -#include "nm-default.h" - -#include "nm-device-iwd.h" - -#include "devices/nm-device-private.h" -#include "devices/nm-device.h" -#include "nm-act-request.h" -#include "nm-config.h" -#include "nm-core-internal.h" -#include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" -#include "nm-iwd-manager.h" -#include "nm-libnm-core-intern/nm-common-macros.h" -#include "nm-setting-8021x.h" -#include "nm-setting-connection.h" -#include "nm-setting-wireless-security.h" -#include "nm-setting-wireless.h" -#include "nm-std-aux/nm-dbus-compat.h" -#include "nm-utils.h" -#include "nm-wifi-common.h" -#include "nm-wifi-utils.h" -#include "settings/nm-settings-connection.h" -#include "settings/nm-settings.h" -#include "supplicant/nm-supplicant-types.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceIwd); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIwd, - PROP_MODE, - PROP_BITRATE, - PROP_ACCESS_POINTS, - PROP_ACTIVE_ACCESS_POINT, - PROP_CAPABILITIES, - PROP_SCANNING, - PROP_LAST_SCAN, ); - -typedef struct { - GDBusObject * dbus_obj; - GDBusProxy * dbus_device_proxy; - GDBusProxy * dbus_station_proxy; - GDBusProxy * dbus_ap_proxy; - GDBusProxy * dbus_adhoc_proxy; - CList aps_lst_head; - NMWifiAP * current_ap; - GCancellable * cancellable; - NMDeviceWifiCapabilities capabilities; - NMActRequestGetSecretsCallId *wifi_secrets_id; - guint periodic_scan_id; - bool enabled : 1; - bool can_scan : 1; - bool can_connect : 1; - bool scanning : 1; - bool scan_requested : 1; - bool act_mode_switch : 1; - gint64 last_scan; -} NMDeviceIwdPrivate; - -struct _NMDeviceIwd { - NMDevice parent; - NMDeviceIwdPrivate _priv; -}; - -struct _NMDeviceIwdClass { - NMDeviceClass parent; -}; - -/*****************************************************************************/ - -G_DEFINE_TYPE(NMDeviceIwd, nm_device_iwd, NM_TYPE_DEVICE) - -#define NM_DEVICE_IWD_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceIwd, NM_IS_DEVICE_IWD, NMDevice) - -/*****************************************************************************/ - -static void schedule_periodic_scan(NMDeviceIwd *self, gboolean initial_scan); - -static gboolean check_scanning_prohibited(NMDeviceIwd *self, gboolean periodic); - -/*****************************************************************************/ - -static void -_ap_dump(NMDeviceIwd *self, NMLogLevel log_level, const NMWifiAP *ap, const char *prefix) -{ - char buf[1024]; - - buf[0] = '\0'; - _NMLOG(log_level, - LOGD_WIFI_SCAN, - "wifi-ap: %-7s %s", - prefix, - nm_wifi_ap_to_string(ap, buf, sizeof(buf), 0)); -} - -/* Callers ensure we're not removing current_ap */ -static void -ap_add_remove(NMDeviceIwd *self, - gboolean is_adding, /* or else is removing */ - NMWifiAP * ap, - gboolean recheck_available_connections) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - if (is_adding) { - g_object_ref(ap); - ap->wifi_device = NM_DEVICE(self); - c_list_link_tail(&priv->aps_lst_head, &ap->aps_lst); - nm_dbus_object_export(NM_DBUS_OBJECT(ap)); - _ap_dump(self, LOGL_DEBUG, ap, "added"); - nm_device_wifi_emit_signal_access_point(NM_DEVICE(self), ap, TRUE); - } else { - ap->wifi_device = NULL; - c_list_unlink(&ap->aps_lst); - _ap_dump(self, LOGL_DEBUG, ap, "removed"); - } - - _notify(self, PROP_ACCESS_POINTS); - - if (!is_adding) { - nm_device_wifi_emit_signal_access_point(NM_DEVICE(self), ap, FALSE); - nm_dbus_object_clear_and_unexport(&ap); - } - - nm_device_emit_recheck_auto_activate(NM_DEVICE(self)); - if (recheck_available_connections) - nm_device_recheck_available_connections(NM_DEVICE(self)); -} - -static void -set_current_ap(NMDeviceIwd *self, NMWifiAP *new_ap, gboolean recheck_available_connections) -{ - NMDeviceIwdPrivate *priv; - NMWifiAP * old_ap; - - g_return_if_fail(NM_IS_DEVICE_IWD(self)); - - priv = NM_DEVICE_IWD_GET_PRIVATE(self); - old_ap = priv->current_ap; - - if (old_ap == new_ap) - return; - - if (new_ap) - priv->current_ap = g_object_ref(new_ap); - else - priv->current_ap = NULL; - - if (old_ap) { - if (nm_wifi_ap_get_fake(old_ap)) - ap_add_remove(self, FALSE, old_ap, recheck_available_connections); - g_object_unref(old_ap); - } - - _notify(self, PROP_ACTIVE_ACCESS_POINT); - _notify(self, PROP_MODE); -} - -static void -remove_all_aps(NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMWifiAP * ap, *ap_safe; - - if (c_list_is_empty(&priv->aps_lst_head)) - return; - - set_current_ap(self, NULL, FALSE); - - c_list_for_each_entry_safe (ap, ap_safe, &priv->aps_lst_head, aps_lst) - ap_add_remove(self, FALSE, ap, FALSE); - - nm_device_emit_recheck_auto_activate(NM_DEVICE(self)); - nm_device_recheck_available_connections(NM_DEVICE(self)); -} - -static NM80211ApSecurityFlags -ap_security_flags_from_network_type(const char *type) -{ - NM80211ApSecurityFlags flags; - - if (nm_streq(type, "psk")) - flags = NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (nm_streq(type, "8021x")) - flags = NM_802_11_AP_SEC_KEY_MGMT_802_1X; - else - return NM_802_11_AP_SEC_NONE; - - flags |= NM_802_11_AP_SEC_PAIR_CCMP; - flags |= NM_802_11_AP_SEC_GROUP_CCMP; - return flags; -} - -static void -insert_ap_from_network(NMDeviceIwd *self, - GHashTable * aps, - const char * path, - gint64 last_seen_msec, - int16_t signal, - uint32_t ap_id) -{ - gs_unref_object GDBusProxy *network_proxy = NULL; - gs_unref_variant GVariant *name_value = NULL; - gs_unref_variant GVariant *type_value = NULL; - nm_auto_ref_string NMRefString *bss_path = NULL; - const char * name; - const char * type; - NMSupplicantBssInfo bss_info; - uint8_t bssid[6]; - NMWifiAP * ap; - gs_unref_bytes GBytes *ssid = NULL; - - bss_path = nm_ref_string_new(path); - - if (g_hash_table_lookup(aps, path)) { - _LOGD(LOGD_WIFI, "Duplicate network at %s", path); - return; - } - - network_proxy = - nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), path, NM_IWD_NETWORK_INTERFACE); - if (!network_proxy) - return; - - name_value = g_dbus_proxy_get_cached_property(network_proxy, "Name"); - type_value = g_dbus_proxy_get_cached_property(network_proxy, "Type"); - if (!name_value || !g_variant_is_of_type(name_value, G_VARIANT_TYPE_STRING) || !type_value - || !g_variant_is_of_type(type_value, G_VARIANT_TYPE_STRING)) - return; - - name = g_variant_get_string(name_value, NULL); - type = g_variant_get_string(type_value, NULL); - - if (nm_streq(type, "wep")) { - /* WEP not supported */ - return; - } - - /* What we get from IWD are networks, or ESSs, that may contain - * multiple APs, or BSSs, each. We don't get information about any - * specific BSSs within an ESS but we can safely present each ESS - * as an individual BSS to NM, which will be seen as ESSs comprising - * a single BSS each. NM won't be able to handle roaming but IWD - * already does that. We fake the BSSIDs as they don't play any - * role either. - */ - bssid[0] = 0x00; - bssid[1] = 0x01; - bssid[2] = 0x02; - bssid[3] = ap_id >> 16; - bssid[4] = ap_id >> 8; - bssid[5] = ap_id; - - ssid = g_bytes_new(name, NM_MIN(32u, strlen(name))); - - bss_info = (NMSupplicantBssInfo){ - .bss_path = bss_path, - .last_seen_msec = last_seen_msec, - .bssid_valid = TRUE, - .mode = NM_802_11_MODE_INFRA, - .rsn_flags = ap_security_flags_from_network_type(type), - .ssid = ssid, - .signal_percent = nm_wifi_utils_level_to_quality(signal / 100), - .frequency = 2417, - .max_rate = 65000, - }; - memcpy(bss_info.bssid, bssid, sizeof(bssid)); - - ap = nm_wifi_ap_new_from_properties(&bss_info); - - nm_assert(bss_path == nm_wifi_ap_get_supplicant_path(ap)); - - g_hash_table_insert(aps, bss_path, ap); -} - -static void -get_ordered_networks_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMDeviceIwd * self = user_data; - NMDeviceIwdPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *variant = NULL; - GVariantIter * networks; - const char * path, *name, *type; - int16_t signal; - NMWifiAP * ap, *ap_safe, *new_ap; - gboolean changed = FALSE; - GHashTableIter ap_iter; - gs_unref_hashtable GHashTable *new_aps = NULL; - gboolean compat; - const char * return_sig; - static uint32_t ap_id = 0; - gint64 last_seen_msec; - - variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); - if (!variant) { - _LOGE(LOGD_WIFI, "Station.GetOrderedNetworks failed: %s", error->message); - return; - } - - priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - /* Depending on whether we're using the Station interface or the Device - * interface for compatibility with IWD <= 0.7, the return signature of - * GetOrderedNetworks will be different. - */ - compat = priv->dbus_station_proxy == priv->dbus_device_proxy; - return_sig = compat ? "(a(osns))" : "(a(on))"; - - if (!g_variant_is_of_type(variant, G_VARIANT_TYPE(return_sig))) { - _LOGE(LOGD_WIFI, - "Station.GetOrderedNetworks returned type %s instead of %s", - g_variant_get_type_string(variant), - return_sig); - return; - } - - new_aps = g_hash_table_new_full(nm_direct_hash, NULL, NULL, g_object_unref); - - g_variant_get(variant, return_sig, &networks); - - last_seen_msec = nm_utils_get_monotonic_timestamp_msec(); - if (compat) { - while (g_variant_iter_next(networks, "(&o&sn&s)", &path, &name, &signal, &type)) - insert_ap_from_network(self, new_aps, path, last_seen_msec, signal, ap_id++); - } else { - while (g_variant_iter_next(networks, "(&on)", &path, &signal)) - insert_ap_from_network(self, new_aps, path, last_seen_msec, signal, ap_id++); - } - - g_variant_iter_free(networks); - - c_list_for_each_entry_safe (ap, ap_safe, &priv->aps_lst_head, aps_lst) { - new_ap = g_hash_table_lookup(new_aps, nm_wifi_ap_get_supplicant_path(ap)); - if (new_ap) { - if (nm_wifi_ap_set_strength(ap, nm_wifi_ap_get_strength(new_ap))) { - _ap_dump(self, LOGL_TRACE, ap, "updated"); - changed = TRUE; - } - g_hash_table_remove(new_aps, nm_wifi_ap_get_supplicant_path(ap)); - continue; - } - - if (ap == priv->current_ap) { - /* Normally IWD will prevent the current AP from being - * removed from the list and set a low signal strength, - * but just making sure. - */ - continue; - } - - ap_add_remove(self, FALSE, ap, FALSE); - changed = TRUE; - } - - g_hash_table_iter_init(&ap_iter, new_aps); - while (g_hash_table_iter_next(&ap_iter, NULL, (gpointer) &ap)) { - ap_add_remove(self, TRUE, ap, FALSE); - g_hash_table_iter_remove(&ap_iter); - changed = TRUE; - } - - if (changed) { - nm_device_emit_recheck_auto_activate(NM_DEVICE(self)); - nm_device_recheck_available_connections(NM_DEVICE(self)); - } -} - -static void -update_aps(NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - if (!priv->cancellable) - priv->cancellable = g_cancellable_new(); - - g_dbus_proxy_call(priv->dbus_station_proxy, - "GetOrderedNetworks", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 2000, - priv->cancellable, - get_ordered_networks_cb, - self); -} - -static void -send_disconnect(NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - g_dbus_proxy_call(priv->dbus_station_proxy, - "Disconnect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - NULL, - NULL); -} - -static void -wifi_secrets_cancel(NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - if (priv->wifi_secrets_id) - nm_act_request_cancel_secrets(NULL, priv->wifi_secrets_id); - nm_assert(!priv->wifi_secrets_id); -} - -static void -cleanup_association_attempt(NMDeviceIwd *self, gboolean disconnect) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - wifi_secrets_cancel(self); - - set_current_ap(self, NULL, TRUE); - - if (disconnect && priv->dbus_station_proxy) - send_disconnect(self); -} - -static void -reset_mode(NMDeviceIwd * self, - GCancellable * cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - g_dbus_proxy_call( - priv->dbus_device_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new("(ssv)", NM_IWD_DEVICE_INTERFACE, "Mode", g_variant_new_string("station")), - G_DBUS_CALL_FLAGS_NONE, - 2000, - cancellable, - callback, - user_data); -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - if (!priv->dbus_obj) - return; - - cleanup_association_attempt(self, TRUE); - priv->act_mode_switch = FALSE; - - if (!priv->dbus_station_proxy) - reset_mode(self, NULL, NULL, NULL); -} - -static void -disconnect_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - gs_unref_object NMDeviceIwd *self = NULL; - NMDeviceDeactivateCallback callback; - gpointer callback_user_data; - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; - - nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data); - - variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); - callback(NM_DEVICE(self), error, callback_user_data); -} - -static void -disconnect_cb_on_idle(gpointer user_data, GCancellable *cancellable) -{ - gs_unref_object NMDeviceIwd *self = NULL; - NMDeviceDeactivateCallback callback; - gpointer callback_user_data; - gs_free_error GError *cancelled_error = NULL; - - nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data); - - g_cancellable_set_error_if_cancelled(cancellable, &cancelled_error); - callback(NM_DEVICE(self), cancelled_error, callback_user_data); -} - -static void -deactivate_async(NMDevice * device, - GCancellable * cancellable, - NMDeviceDeactivateCallback callback, - gpointer callback_user_data) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - gpointer user_data; - - nm_assert(G_IS_CANCELLABLE(cancellable)); - nm_assert(callback); - - user_data = nm_utils_user_data_pack(g_object_ref(self), callback, callback_user_data); - - if (!priv->dbus_obj) { - nm_utils_invoke_on_idle(cancellable, disconnect_cb_on_idle, user_data); - return; - } - - cleanup_association_attempt(self, FALSE); - priv->act_mode_switch = FALSE; - - if (priv->dbus_station_proxy) { - g_dbus_proxy_call(priv->dbus_station_proxy, - "Disconnect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - disconnect_cb, - user_data); - } else - reset_mode(self, cancellable, disconnect_cb, user_data); -} - -static gboolean -is_connection_known_network(NMConnection *connection) -{ - NMSettingWireless * s_wireless; - NMIwdNetworkSecurity security; - gboolean security_ok; - GBytes * ssid; - gs_free char * ssid_utf8 = NULL; - - s_wireless = nm_connection_get_setting_wireless(connection); - if (!s_wireless) - return FALSE; - - ssid = nm_setting_wireless_get_ssid(s_wireless); - if (!ssid) - 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, security); -} - -static gboolean -is_ap_known_network(NMWifiAP *ap) -{ - gs_unref_object GDBusProxy *network_proxy = NULL; - gs_unref_variant GVariant *known_network = NULL; - - network_proxy = - nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), - nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)), - NM_IWD_NETWORK_INTERFACE); - if (!network_proxy) - return FALSE; - - known_network = g_dbus_proxy_get_cached_property(network_proxy, "KnownNetwork"); - return nm_g_variant_is_of_type(known_network, G_VARIANT_TYPE_OBJECT_PATH); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate * priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMSettingWireless * s_wireless; - const char * mac; - const char *const * mac_blacklist; - int i; - const char * perm_hw_addr; - const char * mode; - NMIwdNetworkSecurity security; - gboolean mapped; - - if (!NM_DEVICE_CLASS(nm_device_iwd_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_wireless = nm_connection_get_setting_wireless(connection); - - perm_hw_addr = nm_device_get_permanent_hw_address(device); - mac = nm_setting_wireless_get_mac_address(s_wireless); - if (perm_hw_addr) { - if (mac && !nm_utils_hwaddr_matches(mac, -1, perm_hw_addr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device MAC address does not match the profile"); - return FALSE; - } - - /* Check for MAC address blacklist */ - mac_blacklist = nm_setting_wireless_get_mac_address_blacklist(s_wireless); - for (i = 0; mac_blacklist[i]; i++) { - nm_assert(nm_utils_hwaddr_valid(mac_blacklist[i], ETH_ALEN)); - - if (nm_utils_hwaddr_matches(mac_blacklist[i], -1, perm_hw_addr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "MAC address blacklisted"); - return FALSE; - } - } - } else if (mac) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has no valid MAC address as required by profile"); - return FALSE; - } - - security = nm_wifi_connection_get_iwd_security(connection, &mapped); - if (!mapped) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "connection authentication type not supported by IWD backend"); - return FALSE; - } - - mode = nm_setting_wireless_get_mode(s_wireless); - - /* Hidden SSIDs only supported in client mode */ - if (nm_setting_wireless_get_hidden(s_wireless) - && !NM_IN_STRSET(mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { - nm_utils_error_set_literal( - error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "non-infrastructure hidden networks not supported by the IWD backend"); - return FALSE; - } - - if (NM_IN_STRSET(mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { - /* 8021x networks can only be used if they've been provisioned on the IWD side and - * thus are Known Networks. - */ - if (security == 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 connections must have IWD provisioning files"); - return FALSE; - } - } else if (!NM_IN_SET(security, - NM_IWD_NETWORK_SECURITY_NONE, - NM_IWD_NETWORK_SECURITY_PSK)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "IWD backend only supports Open, PSK and 802.1x network " - "authentication in Infrastructure mode"); - return FALSE; - } - } else if (nm_streq(mode, NM_SETTING_WIRELESS_MODE_AP)) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not support Access Point mode"); - return FALSE; - } - - if (!NM_IN_SET(security, NM_IWD_NETWORK_SECURITY_PSK)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "IWD backend only supports PSK authentication in AP mode"); - return FALSE; - } - } else if (nm_streq(mode, NM_SETTING_WIRELESS_MODE_ADHOC)) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device does not support Ad-Hoc mode"); - return FALSE; - } - - if (!NM_IN_SET(security, NM_IWD_NETWORK_SECURITY_NONE, NM_IWD_NETWORK_SECURITY_PSK)) { - nm_utils_error_set_literal( - error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "IWD backend only supports Open and PSK authentication in Ad-Hoc mode"); - return FALSE; - } - } else { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "%s type profiles not supported by IWD backend"); - return FALSE; - } - - return TRUE; -} - -static gboolean -check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMSettingWireless * s_wifi; - const char * mode; - NMWifiAP * ap = NULL; - - s_wifi = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wifi, FALSE); - - /* a connection that is available for a certain @specific_object, MUST - * also be available in general (without @specific_object). */ - - if (specific_object) { - ap = nm_wifi_ap_lookup_for_device(NM_DEVICE(self), specific_object); - if (!ap) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "requested access point not found"); - return FALSE; - } - if (!nm_wifi_ap_check_compatible(ap, connection)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "requested access point is not compatible with profile"); - return FALSE; - } - } - - /* AP and Ad-Hoc connections can be activated independent of the scan list */ - mode = nm_setting_wireless_get_mode(s_wifi); - if (NM_IN_STRSET(mode, NM_SETTING_WIRELESS_MODE_AP, NM_SETTING_WIRELESS_MODE_ADHOC)) - return TRUE; - - if (NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) - return TRUE; - - if (!ap) - ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection); - - if (!ap) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "no compatible access point found"); - return FALSE; - } - - /* 8021x networks can only be used if they've been provisioned on the IWD side and - * thus are Known Networks. - */ - if (nm_wifi_connection_get_iwd_security(connection, NULL) == NM_IWD_NETWORK_SECURITY_8021X) { - if (!is_ap_known_network(ap)) { - nm_utils_error_set_literal( - error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "802.1x network is not an IWD Known Network (missing provisioning file?)"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMSettingWireless * s_wifi; - gs_free char * ssid_utf8 = NULL; - NMWifiAP * ap; - GBytes * ssid; - GBytes * setting_ssid = NULL; - gboolean hidden = FALSE; - const char * mode; - - s_wifi = nm_connection_get_setting_wireless(connection); - - mode = s_wifi ? nm_setting_wireless_get_mode(s_wifi) : NULL; - - if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP)) { - if (!nm_setting_verify(NM_SETTING(s_wifi), connection, error)) - return FALSE; - ap = NULL; - } else if (!specific_object) { - /* If not given a specific object, we need at minimum an SSID */ - if (!s_wifi) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wireless' setting is required if no AP path was given."); - return FALSE; - } - - setting_ssid = nm_setting_wireless_get_ssid(s_wifi); - if (!setting_ssid || g_bytes_get_size(setting_ssid) == 0) { - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wireless' setting with a valid SSID is required if no AP path was given."); - return FALSE; - } - - /* Find a compatible AP in the scan list */ - ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection); - if (!ap) { - /* If we still don't have an AP, then the WiFI settings needs to be - * fully specified by the client. Might not be able to find an AP - * if the network isn't broadcasting the SSID for example. - */ - if (!nm_setting_verify(NM_SETTING(s_wifi), connection, error)) - return FALSE; - - hidden = TRUE; - } - } else { - ap = nm_wifi_ap_lookup_for_device(NM_DEVICE(self), specific_object); - if (!ap) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND, - "The access point %s was not in the scan list.", - specific_object); - return FALSE; - } - } - - /* Add a wifi setting if one doesn't exist yet */ - if (!s_wifi) { - s_wifi = (NMSettingWireless *) nm_setting_wireless_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wifi)); - } - - ssid = nm_setting_wireless_get_ssid(s_wifi); - if (!ssid && ap) - ssid = nm_wifi_ap_get_ssid(ap); - - if (!ssid) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wireless' setting with a valid SSID is required."); - return FALSE; - } - - if (ap) { - if (!nm_wifi_ap_complete_connection(ap, - connection, - nm_wifi_utils_is_manf_default_ssid(ssid), - error)) - return FALSE; - } - - ssid_utf8 = _nm_utils_ssid_to_utf8(ssid); - nm_utils_complete_generic( - nm_device_get_platform(device), - connection, - NM_SETTING_WIRELESS_SETTING_NAME, - existing_connections, - ssid_utf8, - ssid_utf8, - NULL, - nm_setting_wireless_get_mac_address(s_wifi) ? NULL : nm_device_get_iface(device), - TRUE); - - if (hidden) - g_object_set(s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); - - 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) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMDeviceState state = nm_device_get_state(device); - - /* Available if either the device is UP and in station mode - * or in AP/Ad-Hoc modes while activating or activated. Device - * may be temporarily DOWN while activating or deactivating and - * we don't want it to be marked unavailable because of this. - * - * For reference: - * We call nm_device_queue_recheck_available whenever - * priv->enabled changes or priv->dbus_station_proxy changes. - */ - return priv->dbus_obj && priv->enabled - && (priv->dbus_station_proxy - || (state >= NM_DEVICE_STATE_CONFIG && state <= NM_DEVICE_STATE_DEACTIVATING)); -} - -static gboolean -get_autoconnect_allowed(NMDevice *device) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(NM_DEVICE_IWD(device)); - - return priv->can_connect; -} - -static gboolean -can_auto_connect(NMDevice *device, NMSettingsConnection *sett_conn, char **specific_object) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMConnection * connection; - NMSettingWireless * s_wifi; - NMWifiAP * ap; - const char * mode; - guint64 timestamp = 0; - - nm_assert(!specific_object || !*specific_object); - - if (!NM_DEVICE_CLASS(nm_device_iwd_parent_class)->can_auto_connect(device, sett_conn, NULL)) - return FALSE; - - connection = nm_settings_connection_get_connection(sett_conn); - - s_wifi = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wifi, FALSE); - - /* Don't auto-activate AP or Ad-Hoc connections. - * Note the wpa_supplicant backend has the opposite policy. - */ - mode = nm_setting_wireless_get_mode(s_wifi); - if (mode && g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0) - return FALSE; - - /* Don't autoconnect to networks that have been tried at least once - * but haven't been successful, since these are often accidental choices - * from the menu and the user may not know the password. - */ - if (nm_settings_connection_get_timestamp(sett_conn, ×tamp)) { - if (timestamp == 0) - return FALSE; - } - - ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection); - if (ap) { - /* All good; connection is usable */ - NM_SET_OUT(specific_object, g_strdup(nm_dbus_object_get_path(NM_DBUS_OBJECT(ap)))); - return TRUE; - } - - return FALSE; -} - -const CList * -_nm_device_iwd_get_aps(NMDeviceIwd *self) -{ - return &NM_DEVICE_IWD_GET_PRIVATE(self)->aps_lst_head; -} - -static void -scan_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMDeviceIwd * self = user_data; - NMDeviceIwdPrivate *priv; - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; - - variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); - if (!variant && nm_utils_error_is_cancelled(error)) - return; - - priv = NM_DEVICE_IWD_GET_PRIVATE(self); - priv->scan_requested = FALSE; - priv->last_scan = nm_utils_get_monotonic_timestamp_msec(); - _notify(self, PROP_LAST_SCAN); - - /* On success, priv->scanning becomes true right before or right - * after this callback, so the next automatic scan will be - * scheduled when priv->scanning goes back to false. On error, - * schedule a retry now. - */ - if (error && !priv->scanning) - schedule_periodic_scan(self, FALSE); -} - -static void -dbus_request_scan_cb(NMDevice * device, - GDBusMethodInvocation *context, - NMAuthSubject * subject, - GError * error, - gpointer user_data) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv; - gs_unref_variant GVariant *scan_options = user_data; - - if (error) { - g_dbus_method_invocation_return_gerror(context, error); - return; - } - - if (check_scanning_prohibited(self, FALSE)) { - g_dbus_method_invocation_return_error_literal(context, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed at this time"); - return; - } - - priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - if (!priv->can_scan) { - g_dbus_method_invocation_return_error_literal(context, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed while unavailable"); - return; - } - - if (scan_options) { - gs_unref_variant GVariant *val = g_variant_lookup_value(scan_options, "ssids", NULL); - - if (val) { - g_dbus_method_invocation_return_error_literal(context, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "'ssid' scan option not supported"); - return; - } - } - - if (!priv->scanning && !priv->scan_requested) { - g_dbus_proxy_call(priv->dbus_station_proxy, - "Scan", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - scan_cb, - self); - priv->scan_requested = TRUE; - } - - g_dbus_method_invocation_return_value(context, NULL); -} - -void -_nm_device_iwd_request_scan(NMDeviceIwd *self, GVariant *options, GDBusMethodInvocation *invocation) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - - if (!priv->can_scan) { - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed while unavailable"); - return; - } - - nm_device_auth_request(device, - invocation, - NULL, - NM_AUTH_PERMISSION_WIFI_SCAN, - TRUE, - NULL, - dbus_request_scan_cb, - nm_g_variant_ref(options)); -} - -static gboolean -check_scanning_prohibited(NMDeviceIwd *self, gboolean periodic) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - g_return_val_if_fail(priv->dbus_obj != NULL, TRUE); - - switch (nm_device_get_state(NM_DEVICE(self))) { - case NM_DEVICE_STATE_UNKNOWN: - case NM_DEVICE_STATE_UNMANAGED: - case NM_DEVICE_STATE_UNAVAILABLE: - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_CONFIG: - case NM_DEVICE_STATE_NEED_AUTH: - case NM_DEVICE_STATE_IP_CONFIG: - case NM_DEVICE_STATE_IP_CHECK: - case NM_DEVICE_STATE_SECONDARIES: - case NM_DEVICE_STATE_DEACTIVATING: - /* Prohibit scans when unusable or activating */ - return TRUE; - case NM_DEVICE_STATE_DISCONNECTED: - case NM_DEVICE_STATE_FAILED: - case NM_DEVICE_STATE_ACTIVATED: - break; - } - - /* Prohibit scans if IWD is busy */ - return !priv->can_scan; -} - -/* - * try_reply_agent_request - * - * Check if the connection settings already have the secrets corresponding - * to the IWD agent method that was invoked. If they do, send the method reply - * with the appropriate secrets. Otherwise, return the missing secret's setting - * name and key so the caller can send a NM secrets request with this data. - * Return TRUE in either case, return FALSE if an error is detected. - */ -static gboolean -try_reply_agent_request(NMDeviceIwd * self, - NMConnection * connection, - GDBusMethodInvocation *invocation, - const char ** setting_name, - const char ** setting_key, - gboolean * replied) -{ - const char * method_name = g_dbus_method_invocation_get_method_name(invocation); - NMSettingWirelessSecurity *s_wireless_sec; - NMSetting8021x * s_8021x; - - s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - s_8021x = nm_connection_get_setting_802_1x(connection); - - *replied = FALSE; - - if (nm_streq(method_name, "RequestPassphrase")) { - const char *psk; - - if (!s_wireless_sec) - return FALSE; - - psk = nm_setting_wireless_security_get_psk(s_wireless_sec); - if (psk) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the PSK to the IWD Agent"); - - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", psk)); - *replied = TRUE; - return TRUE; - } - - *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; - *setting_key = NM_SETTING_WIRELESS_SECURITY_PSK; - return TRUE; - } else if (nm_streq(method_name, "RequestPrivateKeyPassphrase")) { - const char *password; - - if (!s_8021x) - return FALSE; - - password = nm_setting_802_1x_get_private_key_password(s_8021x); - if (password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the private key password to the IWD Agent"); - - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); - *replied = TRUE; - return TRUE; - } - - *setting_name = NM_SETTING_802_1X_SETTING_NAME; - *setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD; - return TRUE; - } else if (nm_streq(method_name, "RequestUserNameAndPassword")) { - const char *identity, *password; - - if (!s_8021x) - return FALSE; - - identity = nm_setting_802_1x_get_identity(s_8021x); - password = nm_setting_802_1x_get_password(s_8021x); - if (identity && password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the username and password to the IWD Agent"); - - g_dbus_method_invocation_return_value(invocation, - g_variant_new("(ss)", identity, password)); - *replied = TRUE; - return TRUE; - } - - *setting_name = NM_SETTING_802_1X_SETTING_NAME; - if (!identity) - *setting_key = NM_SETTING_802_1X_IDENTITY; - else - *setting_key = NM_SETTING_802_1X_PASSWORD; - return TRUE; - } else if (nm_streq(method_name, "RequestUserPassword")) { - const char *password; - - if (!s_8021x) - return FALSE; - - password = nm_setting_802_1x_get_password(s_8021x); - if (password) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Returning the user password to the IWD Agent"); - - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", password)); - *replied = TRUE; - return TRUE; - } - - *setting_name = NM_SETTING_802_1X_SETTING_NAME; - *setting_key = NM_SETTING_802_1X_PASSWORD; - return TRUE; - } else - return FALSE; -} - -static void wifi_secrets_get_one(NMDeviceIwd * self, - const char * setting_name, - NMSecretAgentGetSecretsFlags flags, - const char * setting_key, - GDBusMethodInvocation * invocation); - -static void -wifi_secrets_cb(NMActRequest * req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * s_connection, - GError * error, - gpointer user_data) -{ - NMDeviceIwd * self; - NMDeviceIwdPrivate * priv; - NMDevice * device; - GDBusMethodInvocation * invocation; - const char * setting_name; - const char * setting_key; - gboolean replied; - NMSecretAgentGetSecretsFlags get_secret_flags = - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - - nm_utils_user_data_unpack(user_data, &self, &invocation); - - g_return_if_fail(NM_IS_DEVICE_IWD(self)); - - priv = NM_DEVICE_IWD_GET_PRIVATE(self); - device = NM_DEVICE(self); - - g_return_if_fail(priv->wifi_secrets_id == call_id); - - priv->wifi_secrets_id = NULL; - - if (nm_utils_error_is_cancelled(error)) { - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "NM secrets request cancelled"); - return; - } - - g_return_if_fail(req == nm_device_get_act_request(device)); - g_return_if_fail(nm_act_request_get_settings_connection(req) == s_connection); - - if (nm_device_get_state(device) != NM_DEVICE_STATE_NEED_AUTH) - goto secrets_error; - - if (error) { - _LOGW(LOGD_WIFI, "%s", error->message); - goto secrets_error; - } - - if (!try_reply_agent_request(self, - nm_act_request_get_applied_connection(req), - invocation, - &setting_name, - &setting_key, - &replied)) - goto secrets_error; - - if (replied) { - /* Change state back to what it was before NEED_AUTH */ - nm_device_state_changed(device, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); - return; - } - - if (nm_settings_connection_get_timestamp(nm_act_request_get_settings_connection(req), NULL)) - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - - /* Request further secrets if we still need something */ - wifi_secrets_get_one(self, setting_name, get_secret_flags, setting_key, invocation); - return; - -secrets_error: - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "NM secrets request failed"); - /* Now wait for the Connect callback to update device state */ -} - -static void -wifi_secrets_get_one(NMDeviceIwd * self, - const char * setting_name, - NMSecretAgentGetSecretsFlags flags, - const char * setting_key, - GDBusMethodInvocation * invocation) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMActRequest * req; - - wifi_secrets_cancel(self); - - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv->wifi_secrets_id = nm_act_request_get_secrets(req, - TRUE, - setting_name, - flags, - NM_MAKE_STRV(setting_key), - wifi_secrets_cb, - nm_utils_user_data_pack(self, invocation)); -} - -static void -network_connect_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMDeviceIwd * self = user_data; - NMDevice * device = NM_DEVICE(self); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; - NMConnection * connection; - NMSettingWireless * s_wifi; - GBytes * ssid; - gs_free char * ssid_utf8 = NULL; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED; - GVariant * value; - - variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); - if (!variant) { - gs_free char *dbus_error = NULL; - - /* Connection failed; radio problems or if the network wasn't - * open, the passwords or certificates may be wrong. - */ - - _LOGE(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Network.Connect failed: %s", - error->message); - - if (nm_utils_error_is_cancelled(error)) - return; - - if (!NM_IN_SET(nm_device_get_state(device), - NM_DEVICE_STATE_CONFIG, - NM_DEVICE_STATE_NEED_AUTH)) - return; - - connection = nm_device_get_applied_connection(device); - if (!connection) - goto failed; - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) - dbus_error = g_dbus_error_get_remote_error(error); - - if (nm_streq0(dbus_error, "net.connman.iwd.Failed")) { - nm_connection_clear_secrets(connection); - - /* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */ - reason = NM_DEVICE_STATE_REASON_NO_SECRETS; - } else if (nm_streq0(dbus_error, "net.connman.iwd.Aborted")) { - /* If agent call was cancelled we'd be getting a net.connman.iwd.Aborted */ - reason = NM_DEVICE_STATE_REASON_NO_SECRETS; - } - - goto failed; - } - - nm_assert(nm_device_get_state(device) == NM_DEVICE_STATE_CONFIG); - - connection = nm_device_get_applied_connection(device); - if (!connection) - goto failed; - - s_wifi = nm_connection_get_setting_wireless(connection); - if (!s_wifi) - goto failed; - - ssid = nm_setting_wireless_get_ssid(s_wifi); - if (!ssid) - goto failed; - - ssid_utf8 = _nm_utils_ssid_to_utf8(ssid); - - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. Connected to '%s'.", - ssid_utf8); - nm_device_activate_schedule_stage3_ip_config_start(device); - - return; - -failed: - /* Call Disconnect to make sure IWD's autoconnect is disabled */ - cleanup_association_attempt(self, TRUE); - - nm_device_queue_state(device, NM_DEVICE_STATE_FAILED, reason); - - value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State"); - if (!priv->can_connect && nm_streq0(get_variant_state(value), "disconnected")) { - priv->can_connect = true; - nm_device_emit_recheck_auto_activate(device); - } - g_variant_unref(value); -} - -static void -act_failed_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMDeviceIwd * self = user_data; - NMDevice * device = NM_DEVICE(self); - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; - - variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); - if (!variant && nm_utils_error_is_cancelled(error)) - return; - - /* Change state to FAILED unless already done by state_changed - * which may have been triggered by the station interface - * appearing on DBus. - */ - if (nm_device_get_state(device) == NM_DEVICE_STATE_CONFIG) - nm_device_queue_state(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); -} - -static void -act_start_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMDeviceIwd * self = user_data; - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; - NMSettingWireless * s_wireless; - GBytes * ssid; - gs_free char * ssid_utf8 = NULL; - - variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); - if (!variant) { - _LOGE(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Network.Connect failed: %s", - error->message); - - if (nm_utils_error_is_cancelled(error)) - return; - - if (!NM_IN_SET(nm_device_get_state(device), NM_DEVICE_STATE_CONFIG)) - return; - - goto error; - } - - nm_assert(nm_device_get_state(device) == NM_DEVICE_STATE_CONFIG); - - s_wireless = nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRELESS); - if (!s_wireless) - goto error; - - ssid = nm_setting_wireless_get_ssid(s_wireless); - if (!ssid) - goto error; - - ssid_utf8 = _nm_utils_ssid_to_utf8(ssid); - - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. Started '%s'.", - ssid_utf8); - - nm_device_activate_schedule_stage3_ip_config_start(device); - return; - -error: - reset_mode(self, priv->cancellable, act_failed_cb, self); -} - -/* Check if we're activating an AP/AdHoc connection and if the target - * DBus interface has appeared already. If so proceed to call Start or - * StartOpen on that interface. - */ -static void -act_check_interface(NMDeviceIwd *self) -{ - NMDeviceIwdPrivate * priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMSettingWireless * s_wireless; - NMSettingWirelessSecurity *s_wireless_sec; - GDBusProxy * proxy = NULL; - GBytes * ssid; - gs_free char * ssid_utf8 = NULL; - const char * mode; - - if (!priv->act_mode_switch) - return; - - s_wireless = - (NMSettingWireless *) nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRELESS); - - mode = nm_setting_wireless_get_mode(s_wireless); - if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP)) - proxy = priv->dbus_ap_proxy; - else if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_ADHOC)) - proxy = priv->dbus_adhoc_proxy; - - if (!proxy) - return; - - priv->act_mode_switch = FALSE; - - if (!NM_IN_SET(nm_device_get_state(device), NM_DEVICE_STATE_CONFIG)) - return; - - ssid = nm_setting_wireless_get_ssid(s_wireless); - if (!ssid) - goto failed; - - ssid_utf8 = _nm_utils_ssid_to_utf8(ssid); - - s_wireless_sec = (NMSettingWirelessSecurity *) nm_device_get_applied_setting( - device, - NM_TYPE_SETTING_WIRELESS_SECURITY); - - if (!s_wireless_sec) { - g_dbus_proxy_call(proxy, - "StartOpen", - g_variant_new("(s)", ssid_utf8), - G_DBUS_CALL_FLAGS_NONE, - G_MAXINT, - priv->cancellable, - act_start_cb, - self); - } else { - const char *psk = nm_setting_wireless_security_get_psk(s_wireless_sec); - - if (!psk) { - _LOGE(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) No PSK for '%s'.", ssid_utf8); - goto failed; - } - - g_dbus_proxy_call(proxy, - "Start", - g_variant_new("(ss)", ssid_utf8, psk), - G_DBUS_CALL_FLAGS_NONE, - G_MAXINT, - priv->cancellable, - act_start_cb, - self); - } - - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) Called Start('%s').", ssid_utf8); - return; - -failed: - reset_mode(self, priv->cancellable, act_failed_cb, self); -} - -static void -act_set_mode_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMDeviceIwd * self = user_data; - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; - - variant = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), res, &error); - if (!variant) { - _LOGE(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Setting Device.Mode failed: %s", - error->message); - - if (nm_utils_error_is_cancelled(error)) - return; - - if (!NM_IN_SET(nm_device_get_state(device), NM_DEVICE_STATE_CONFIG) - || !priv->act_mode_switch) - return; - - priv->act_mode_switch = FALSE; - nm_device_queue_state(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return; - } - - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) IWD Device.Mode set successfully"); - - act_check_interface(self); -} - -static void -act_set_mode(NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - const char * iwd_mode; - const char * mode; - NMSettingWireless * s_wireless; - - s_wireless = - (NMSettingWireless *) nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRELESS); - mode = nm_setting_wireless_get_mode(s_wireless); - - /* We need to first set interface mode (Device.Mode) to ap or ad-hoc. - * We can't directly queue a call to the Start/StartOpen method on - * the DBus interface that's going to be created after the property - * set call returns. - */ - iwd_mode = nm_streq(mode, NM_SETTING_WIRELESS_MODE_AP) ? "ap" : "ad-hoc"; - - if (!priv->cancellable) - priv->cancellable = g_cancellable_new(); - - g_dbus_proxy_call( - priv->dbus_device_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new("(ssv)", NM_IWD_DEVICE_INTERFACE, "Mode", g_variant_new("s", iwd_mode)), - G_DBUS_CALL_FLAGS_NONE, - 2000, - priv->cancellable, - act_set_mode_cb, - self); - priv->act_mode_switch = TRUE; -} - -static void -act_psk_cb(NMActRequest * req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * s_connection, - GError * error, - gpointer user_data) -{ - NMDeviceIwd * self = user_data; - NMDeviceIwdPrivate *priv; - NMDevice * device; - - if (nm_utils_error_is_cancelled(error)) - return; - - priv = NM_DEVICE_IWD_GET_PRIVATE(self); - device = NM_DEVICE(self); - - g_return_if_fail(priv->wifi_secrets_id == call_id); - priv->wifi_secrets_id = NULL; - - g_return_if_fail(req == nm_device_get_act_request(device)); - g_return_if_fail(nm_act_request_get_settings_connection(req) == s_connection); - - if (nm_device_get_state(device) != NM_DEVICE_STATE_NEED_AUTH) - goto secrets_error; - - if (error) { - _LOGW(LOGD_WIFI, "%s", error->message); - goto secrets_error; - } - - _LOGD(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) missing PSK request completed"); - - /* Change state back to what it was before NEED_AUTH */ - nm_device_state_changed(device, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); - act_set_mode(self); - return; - -secrets_error: - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - cleanup_association_attempt(self, FALSE); -} - -static void -set_powered(NMDeviceIwd *self, gboolean powered) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - g_dbus_proxy_call( - priv->dbus_device_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new("(ssv)", NM_IWD_DEVICE_INTERFACE, "Powered", g_variant_new("b", powered)), - G_DBUS_CALL_FLAGS_NONE, - 2000, - NULL, - NULL, - NULL); -} - -/*****************************************************************************/ - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMWifiAP * ap = NULL; - gs_unref_object NMWifiAP *ap_fake = NULL; - NMActRequest * req; - NMConnection * connection; - NMSettingWireless * s_wireless; - const char * mode; - const char * ap_path; - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - connection = nm_act_request_get_applied_connection(req); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_wireless = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wireless, NM_ACT_STAGE_RETURN_FAILURE); - - /* AP mode never uses a specific object or existing scanned AP */ - mode = nm_setting_wireless_get_mode(s_wireless); - if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP)) - goto add_new; - - ap_path = nm_active_connection_get_specific_object(NM_ACTIVE_CONNECTION(req)); - ap = ap_path ? nm_wifi_ap_lookup_for_device(NM_DEVICE(self), ap_path) : NULL; - if (ap) { - set_current_ap(self, ap, TRUE); - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection); - if (ap) { - nm_active_connection_set_specific_object(NM_ACTIVE_CONNECTION(req), - nm_dbus_object_get_path(NM_DBUS_OBJECT(ap))); - set_current_ap(self, ap, TRUE); - return NM_ACT_STAGE_RETURN_SUCCESS; - } - - if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_INFRA)) { - /* Hidden networks not supported at this time */ - return NM_ACT_STAGE_RETURN_FAILURE; - } - -add_new: - /* If the user is trying to connect to an AP that NM doesn't yet know about - * (hidden network or something) or starting a Hotspot, create an fake AP - * from the security settings in the connection. This "fake" AP gets used - * until the real one is found in the scan list (Ad-Hoc or Hidden), or until - * the device is deactivated (Ad-Hoc or Hotspot). - */ - ap_fake = nm_wifi_ap_new_fake_from_connection(connection); - if (!ap_fake) - g_return_val_if_reached(NM_ACT_STAGE_RETURN_FAILURE); - - if (nm_wifi_ap_is_hotspot(ap_fake)) - nm_wifi_ap_set_address(ap_fake, nm_device_get_hw_address(device)); - - g_object_freeze_notify(G_OBJECT(self)); - ap_add_remove(self, TRUE, ap_fake, FALSE); - g_object_thaw_notify(G_OBJECT(self)); - set_current_ap(self, ap_fake, FALSE); - nm_active_connection_set_specific_object(NM_ACTIVE_CONNECTION(req), - nm_dbus_object_get_path(NM_DBUS_OBJECT(ap_fake))); - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMActRequest * req; - NMConnection * connection; - NMSettingWireless * s_wireless; - const char * mode; - - req = nm_device_get_act_request(device); - connection = nm_act_request_get_applied_connection(req); - s_wireless = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wireless, NM_ACT_STAGE_RETURN_FAILURE); - - mode = nm_setting_wireless_get_mode(s_wireless); - - if (NM_IN_STRSET(mode, NULL, NM_SETTING_WIRELESS_MODE_INFRA)) { - gs_unref_object GDBusProxy *network_proxy = NULL; - NMWifiAP * ap = priv->current_ap; - - if (!ap) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out_fail; - } - - /* 802.1x networks that are not IWD Known Networks will definitely - * fail, for other combinations we will let the Connect call fail - * or ask us for any missing secrets through the Agent. - */ - if (nm_connection_get_setting_802_1x(connection) && !is_ap_known_network(ap)) { - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) access point '%s' has 802.1x security but is not configured " - "in IWD.", - nm_connection_get_id(connection)); - - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - goto out_fail; - } - - if (!is_connection_known_network(connection) - && nm_setting_wireless_get_hidden(s_wireless)) { - gs_free char *ssid_str = NULL; - - /* Use Station.ConnectHiddenNetwork method instead of Network proxy. */ - ssid_str = _nm_utils_ssid_to_utf8(nm_setting_wireless_get_ssid(s_wireless)); - g_dbus_proxy_call(priv->dbus_station_proxy, - "ConnectHiddenNetwork", - g_variant_new("(s)", ssid_str), - G_DBUS_CALL_FLAGS_NONE, - G_MAXINT, - priv->cancellable, - network_connect_cb, - self); - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (!nm_wifi_ap_get_supplicant_path(ap)) { - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) network is provisioned but dbus supplicant path for AP " - "unknown"); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out_fail; - } - - network_proxy = nm_iwd_manager_get_dbus_interface( - nm_iwd_manager_get(), - nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap)), - NM_IWD_NETWORK_INTERFACE); - if (!network_proxy) { - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) could not get Network interface proxy for %s", - nm_ref_string_get_str(nm_wifi_ap_get_supplicant_path(ap))); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out_fail; - } - - if (!priv->cancellable) - priv->cancellable = g_cancellable_new(); - - /* Call Network.Connect. No timeout because IWD already handles - * timeouts. - */ - g_dbus_proxy_call(network_proxy, - "Connect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - G_MAXINT, - priv->cancellable, - network_connect_cb, - self); - - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (NM_IN_STRSET(mode, NM_SETTING_WIRELESS_MODE_AP, NM_SETTING_WIRELESS_MODE_ADHOC)) { - NMSettingWirelessSecurity *s_wireless_sec; - - s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - if (s_wireless_sec && !nm_setting_wireless_security_get_psk(s_wireless_sec)) { - /* PSK is missing from the settings, have to request it */ - - wifi_secrets_cancel(self); - - priv->wifi_secrets_id = - nm_act_request_get_secrets(req, - TRUE, - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION, - NM_MAKE_STRV(NM_SETTING_WIRELESS_SECURITY_PSK), - act_psk_cb, - self); - nm_device_state_changed(device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); - } else - act_set_mode(self); - - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - _LOGW(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) iwd cannot handle mode %s", mode); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - -out_fail: - cleanup_association_attempt(self, FALSE); - return NM_ACT_STAGE_RETURN_FAILURE; -} - -static guint32 -get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - return nm_device_get_configured_mtu_from_connection(device, - NM_TYPE_SETTING_WIRELESS, - out_source); -} - -static gboolean -periodic_scan_timeout_cb(gpointer user_data) -{ - NMDeviceIwd * self = user_data; - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - priv->periodic_scan_id = 0; - - if (priv->scanning || priv->scan_requested) - return FALSE; - - g_dbus_proxy_call(priv->dbus_station_proxy, - "Scan", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - scan_cb, - self); - priv->scan_requested = TRUE; - - return FALSE; -} - -static void -schedule_periodic_scan(NMDeviceIwd *self, gboolean initial_scan) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - GVariant * value; - gboolean disconnected = TRUE; - guint interval; - - if (priv->can_scan) { - value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State"); - disconnected = nm_streq0(get_variant_state(value), "disconnected"); - g_variant_unref(value); - } - - /* Start scan immediately after a disconnect, mode change or - * device UP, otherwise wait 10 seconds. When connected, update - * AP list mainly on UI requests. - * - * (initial_scan && disconnected) override priv->scanning below - * because of an IWD quirk where a device will often be in the - * autoconnect state and scanning at the time of our initial_scan, - * but our logic will then send it a Disconnect() causing IWD to - * exit autoconnect and interrupt the ongoing scan, meaning that - * we still want a new scan ASAP. - */ - if (!priv->can_scan || !disconnected || priv->scan_requested || priv->scanning) - interval = -1; - else if (initial_scan) - interval = 0; - else if (!priv->periodic_scan_id) - interval = 10; - else - return; - - nm_clear_g_source(&priv->periodic_scan_id); - - if (interval != (guint) -1) - priv->periodic_scan_id = g_timeout_add_seconds(interval, periodic_scan_timeout_cb, self); -} - -static void -set_can_scan(NMDeviceIwd *self, gboolean can_scan) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - if (priv->can_scan == can_scan) - return; - - priv->can_scan = can_scan; - - schedule_periodic_scan(self, TRUE); -} - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - switch (new_state) { - case NM_DEVICE_STATE_UNMANAGED: - break; - case NM_DEVICE_STATE_UNAVAILABLE: - /* - * If the device is enabled and the IWD manager is ready, - * transition to DISCONNECTED because the device is now - * ready to use. - */ - if (priv->enabled && priv->dbus_station_proxy) { - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } - break; - case NM_DEVICE_STATE_NEED_AUTH: - break; - case NM_DEVICE_STATE_IP_CHECK: - break; - case NM_DEVICE_STATE_ACTIVATED: - break; - case NM_DEVICE_STATE_FAILED: - break; - case NM_DEVICE_STATE_DISCONNECTED: - break; - default: - break; - } -} - -static gboolean -get_enabled(NMDevice *device) -{ - return NM_DEVICE_IWD_GET_PRIVATE(device)->enabled; -} - -static void -set_enabled(NMDevice *device, gboolean enabled) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(device); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMDeviceState state; - - enabled = !!enabled; - - if (priv->enabled == enabled) - return; - - priv->enabled = enabled; - - _LOGD(LOGD_WIFI, "device now %s", enabled ? "enabled" : "disabled"); - - state = nm_device_get_state(device); - if (state < NM_DEVICE_STATE_UNAVAILABLE) { - _LOGD(LOGD_WIFI, "(%s): device blocked by UNMANAGED state", enabled ? "enable" : "disable"); - return; - } - - if (priv->dbus_obj) - set_powered(self, enabled); - - if (enabled) { - if (state != NM_DEVICE_STATE_UNAVAILABLE) - _LOGW(LOGD_CORE, "not in expected unavailable state!"); - - if (priv->dbus_station_proxy) { - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } - } else { - nm_device_state_changed(device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NONE); - } -} - -static gboolean -can_reapply_change(NMDevice * device, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error) -{ - NMDeviceClass *device_class; - - /* Only handle wireless setting here, delegate other settings to parent class */ - if (nm_streq(setting_name, NM_SETTING_WIRELESS_SETTING_NAME)) { - return nm_device_hash_check_invalid_keys( - diffs, - NM_SETTING_WIRELESS_SETTING_NAME, - error, - NM_SETTING_WIRELESS_SEEN_BSSIDS, /* ignored */ - NM_SETTING_WIRELESS_MTU); /* reapplied with IP config */ - } - - device_class = NM_DEVICE_CLASS(nm_device_iwd_parent_class); - return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(object); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - const char ** list; - - switch (prop_id) { - case PROP_MODE: - if (!priv->current_ap) - g_value_set_uint(value, NM_802_11_MODE_UNKNOWN); - else if (nm_wifi_ap_is_hotspot(priv->current_ap)) - g_value_set_uint(value, NM_802_11_MODE_AP); - else - g_value_set_uint(value, nm_wifi_ap_get_mode(priv->current_ap)); - - break; - case PROP_BITRATE: - g_value_set_uint(value, 65000); - break; - case PROP_CAPABILITIES: - g_value_set_uint(value, priv->capabilities); - break; - case PROP_ACCESS_POINTS: - list = nm_wifi_aps_get_paths(&priv->aps_lst_head, TRUE); - g_value_take_boxed(value, nm_utils_strv_make_deep_copied(list)); - break; - case PROP_ACTIVE_ACCESS_POINT: - nm_dbus_utils_g_value_set_object_path(value, priv->current_ap); - break; - case PROP_SCANNING: - g_value_set_boolean(value, priv->scanning); - break; - case PROP_LAST_SCAN: - g_value_set_int64( - value, - priv->last_scan > 0 - ? nm_utils_monotonic_timestamp_as_boottime(priv->last_scan, NM_UTILS_NSEC_PER_MSEC) - : (gint64) -1); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -state_changed(NMDeviceIwd *self, const char *new_state) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMDeviceState dev_state = nm_device_get_state(device); - gboolean iwd_connection = FALSE; - gboolean can_connect = priv->can_connect; - - _LOGI(LOGD_DEVICE | LOGD_WIFI, "new IWD device state is %s", new_state); - - if (dev_state >= NM_DEVICE_STATE_CONFIG && dev_state <= NM_DEVICE_STATE_ACTIVATED) - iwd_connection = TRUE; - - /* Don't allow scanning while connecting, disconnecting or roaming */ - set_can_scan(self, NM_IN_STRSET(new_state, "connected", "disconnected")); - - priv->can_connect = FALSE; - - if (NM_IN_STRSET(new_state, "connecting", "connected", "roaming")) { - /* If we were connecting, do nothing, the confirmation of - * a connection success is handled in the Device.Connect - * method return callback. Otherwise, IWD must have connected - * without Network Manager's will so for simplicity force a - * disconnect. - */ - if (iwd_connection) - return; - - _LOGW(LOGD_DEVICE | LOGD_WIFI, "Unsolicited connection success, asking IWD to disconnect"); - send_disconnect(self); - } else if (NM_IN_STRSET(new_state, "disconnecting", "disconnected")) { - /* Call Disconnect on the IWD device object to make sure it - * disables its own autoconnect. - */ - send_disconnect(self); - - /* - * If IWD is still handling the Connect call, let our Connect - * callback for the dbus method handle the failure. The main - * reason we can't handle the failure here is because the method - * callback will have more information on the specific failure - * reason. - */ - if (NM_IN_SET(dev_state, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_NEED_AUTH)) - return; - - if (iwd_connection) - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - } else if (!nm_streq(new_state, "unknown")) { - _LOGE(LOGD_WIFI, "State %s unknown", new_state); - return; - } - - /* Don't allow new connection until iwd exits disconnecting and no - * Connect callback is pending. - */ - if (NM_IN_STRSET(new_state, "disconnected")) { - priv->can_connect = TRUE; - if (!can_connect) - nm_device_emit_recheck_auto_activate(device); - } -} - -static void -scanning_changed(NMDeviceIwd *self, gboolean new_scanning) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - if (new_scanning == priv->scanning) - return; - - priv->scanning = new_scanning; - - _notify(self, PROP_SCANNING); - - if (!priv->scanning) { - update_aps(self); - - if (!priv->scan_requested) - schedule_periodic_scan(self, FALSE); - } -} - -static void -station_properties_changed(GDBusProxy *proxy, - GVariant * changed_properties, - GStrv invalidate_properties, - gpointer user_data) -{ - NMDeviceIwd *self = user_data; - const char * new_str; - gboolean new_bool; - - if (g_variant_lookup(changed_properties, "State", "&s", &new_str)) - state_changed(self, new_str); - - if (g_variant_lookup(changed_properties, "Scanning", "b", &new_bool)) - scanning_changed(self, new_bool); -} - -static void -ap_adhoc_properties_changed(GDBusProxy *proxy, - GVariant * changed_properties, - GStrv invalidate_properties, - gpointer user_data) -{ - NMDeviceIwd *self = user_data; - gboolean new_bool; - - if (g_variant_lookup(changed_properties, "Started", "b", &new_bool)) - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "IWD AP/AdHoc state is now %s", - new_bool ? "Started" : "Stopped"); -} - -static void -powered_changed(NMDeviceIwd *self, gboolean new_powered) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - GDBusInterface * interface; - GVariant * value; - - nm_device_queue_recheck_available(NM_DEVICE(self), - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - - interface = - new_powered ? g_dbus_object_get_interface(priv->dbus_obj, NM_IWD_AP_INTERFACE) : NULL; - - if (priv->dbus_ap_proxy) { - g_signal_handlers_disconnect_by_func(priv->dbus_ap_proxy, - ap_adhoc_properties_changed, - self); - g_clear_object(&priv->dbus_ap_proxy); - } - - if (interface) { - priv->dbus_ap_proxy = G_DBUS_PROXY(interface); - g_signal_connect(priv->dbus_ap_proxy, - "g-properties-changed", - G_CALLBACK(ap_adhoc_properties_changed), - self); - - if (priv->act_mode_switch) - act_check_interface(self); - else - reset_mode(self, NULL, NULL, NULL); - } - - interface = - new_powered ? g_dbus_object_get_interface(priv->dbus_obj, NM_IWD_ADHOC_INTERFACE) : NULL; - - if (priv->dbus_adhoc_proxy) { - g_signal_handlers_disconnect_by_func(priv->dbus_adhoc_proxy, - ap_adhoc_properties_changed, - self); - g_clear_object(&priv->dbus_adhoc_proxy); - } - - if (interface) { - priv->dbus_adhoc_proxy = G_DBUS_PROXY(interface); - g_signal_connect(priv->dbus_adhoc_proxy, - "g-properties-changed", - G_CALLBACK(ap_adhoc_properties_changed), - self); - - if (priv->act_mode_switch) - act_check_interface(self); - else - reset_mode(self, NULL, NULL, NULL); - } - - /* We expect one of the three interfaces to always be present when - * device is Powered so if AP and AdHoc are not present we should - * be in station mode. - */ - if (new_powered && !priv->dbus_ap_proxy && !priv->dbus_adhoc_proxy) { - interface = g_dbus_object_get_interface(priv->dbus_obj, NM_IWD_STATION_INTERFACE); - if (!interface) { - /* No Station interface on the device object. Check if the - * "State" property is present on the Device interface, that - * would mean we're dealing with an IWD version from before the - * Device/Station split (0.7 or earlier) and we can easily - * handle that by making priv->dbus_device_proxy and - * priv->dbus_station_proxy both point at the Device interface. - */ - value = g_dbus_proxy_get_cached_property(priv->dbus_device_proxy, "State"); - if (value) { - g_variant_unref(value); - interface = g_object_ref(G_DBUS_INTERFACE(priv->dbus_device_proxy)); - } else { - _LOGE(LOGD_WIFI, - "Interface %s not found on obj %s", - NM_IWD_STATION_INTERFACE, - g_dbus_object_get_object_path(priv->dbus_obj)); - interface = NULL; - } - } - } else - interface = NULL; - - if (priv->dbus_station_proxy) { - g_signal_handlers_disconnect_by_func(priv->dbus_station_proxy, - station_properties_changed, - self); - g_clear_object(&priv->dbus_station_proxy); - } - - if (interface) { - priv->dbus_station_proxy = G_DBUS_PROXY(interface); - g_signal_connect(priv->dbus_station_proxy, - "g-properties-changed", - G_CALLBACK(station_properties_changed), - self); - - value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "Scanning"); - priv->scanning = get_variant_boolean(value, "Scanning"); - g_variant_unref(value); - - value = g_dbus_proxy_get_cached_property(priv->dbus_station_proxy, "State"); - state_changed(self, get_variant_state(value)); - g_variant_unref(value); - - update_aps(self); - } else { - set_can_scan(self, FALSE); - priv->scanning = FALSE; - priv->scan_requested = FALSE; - priv->can_connect = FALSE; - cleanup_association_attempt(self, FALSE); - remove_all_aps(self); - } -} - -static void -device_properties_changed(GDBusProxy *proxy, - GVariant * changed_properties, - GStrv invalidate_properties, - gpointer user_data) -{ - NMDeviceIwd *self = user_data; - gboolean new_bool; - - if (g_variant_lookup(changed_properties, "Powered", "b", &new_bool)) - powered_changed(self, new_bool); -} - -void -nm_device_iwd_set_dbus_object(NMDeviceIwd *self, GDBusObject *object) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - GDBusInterface * interface; - gs_unref_variant GVariant *value = NULL; - gs_unref_object GDBusProxy *adapter_proxy = NULL; - GVariantIter * iter; - const char * mode; - gboolean powered; - NMDeviceWifiCapabilities capabilities; - - if (!nm_g_object_ref_set(&priv->dbus_obj, object)) - return; - - if (priv->dbus_device_proxy) { - g_signal_handlers_disconnect_by_func(priv->dbus_device_proxy, - device_properties_changed, - self); - g_clear_object(&priv->dbus_device_proxy); - - powered_changed(self, FALSE); - - priv->act_mode_switch = FALSE; - } - - if (!object) - return; - - interface = g_dbus_object_get_interface(object, NM_IWD_DEVICE_INTERFACE); - if (!interface) { - _LOGE(LOGD_WIFI, - "Interface %s not found on obj %s", - NM_IWD_DEVICE_INTERFACE, - g_dbus_object_get_object_path(object)); - g_clear_object(&priv->dbus_obj); - return; - } - - priv->dbus_device_proxy = G_DBUS_PROXY(interface); - - g_signal_connect(priv->dbus_device_proxy, - "g-properties-changed", - G_CALLBACK(device_properties_changed), - self); - - /* Parse list of interface modes supported by adapter (wiphy) */ - - value = g_dbus_proxy_get_cached_property(priv->dbus_device_proxy, "Adapter"); - if (!value || !g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH)) { - nm_log_warn(LOGD_DEVICE | LOGD_WIFI, "Adapter property not cached or not an object path"); - goto error; - } - - adapter_proxy = nm_iwd_manager_get_dbus_interface(nm_iwd_manager_get(), - g_variant_get_string(value, NULL), - NM_IWD_WIPHY_INTERFACE); - if (!adapter_proxy) { - nm_log_warn(LOGD_DEVICE | LOGD_WIFI, "Can't get DBus proxy for IWD Adapter for IWD Device"); - goto error; - } - - g_variant_unref(value); - value = g_dbus_proxy_get_cached_property(adapter_proxy, "SupportedModes"); - if (!value || !g_variant_is_of_type(value, G_VARIANT_TYPE_STRING_ARRAY)) { - nm_log_warn(LOGD_DEVICE | LOGD_WIFI, - "SupportedModes property not cached or not a string array"); - goto error; - } - - capabilities = NM_WIFI_DEVICE_CAP_CIPHER_CCMP | NM_WIFI_DEVICE_CAP_RSN; - - g_variant_get(value, "as", &iter); - while (g_variant_iter_next(iter, "&s", &mode)) { - if (nm_streq(mode, "ap")) - capabilities |= NM_WIFI_DEVICE_CAP_AP; - else if (nm_streq(mode, "ad-hoc")) - capabilities |= NM_WIFI_DEVICE_CAP_ADHOC; - } - g_variant_iter_free(iter); - - if (priv->capabilities != capabilities) { - priv->capabilities = capabilities; - _notify(self, PROP_CAPABILITIES); - } - - g_variant_unref(value); - value = g_dbus_proxy_get_cached_property(priv->dbus_device_proxy, "Powered"); - powered = get_variant_boolean(value, "Powered"); - - if (powered != priv->enabled) - set_powered(self, priv->enabled); - else if (powered) - powered_changed(self, TRUE); - - return; - -error: - g_signal_handlers_disconnect_by_func(priv->dbus_device_proxy, device_properties_changed, self); - g_clear_object(&priv->dbus_device_proxy); -} - -gboolean -nm_device_iwd_agent_query(NMDeviceIwd *self, GDBusMethodInvocation *invocation) -{ - NMActRequest * req; - const char * setting_name; - const char * setting_key; - gboolean replied; - NMSecretAgentGetSecretsFlags get_secret_flags = - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - - req = nm_device_get_act_request(NM_DEVICE(self)); - if (!req) - return FALSE; - - if (!try_reply_agent_request(self, - nm_act_request_get_applied_connection(req), - invocation, - &setting_name, - &setting_key, - &replied)) - return FALSE; - - if (replied) - return TRUE; - - /* Normally require new secrets every time IWD asks for them. - * IWD only queries us if it has not saved the secrets (e.g. by policy) - * or a previous attempt has failed with current secrets so it wants - * a fresh set. However if this is a new connection it may include - * all of the needed settings already so allow using these, too. - * Connection timestamp is set after activation or after first - * activation failure (to 0). - */ - if (nm_settings_connection_get_timestamp(nm_act_request_get_settings_connection(req), NULL)) - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_NO_SECRETS); - wifi_secrets_get_one(self, setting_name, get_secret_flags, setting_key, invocation); - - return TRUE; -} - -/*****************************************************************************/ - -static const char * -get_type_description(NMDevice *device) -{ - nm_assert(NM_IS_DEVICE_IWD(device)); - - return "wifi"; -} - -/*****************************************************************************/ - -static void -nm_device_iwd_init(NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - c_list_init(&priv->aps_lst_head); - - /* Make sure the manager is running */ - (void) nm_iwd_manager_get(); -} - -NMDevice * -nm_device_iwd_new(const char *iface) -{ - return g_object_new(NM_TYPE_DEVICE_IWD, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "802.11 Wi-Fi", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_WIFI, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_WIFI, - NM_DEVICE_RFKILL_TYPE, - RFKILL_TYPE_WLAN, - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceIwd * self = NM_DEVICE_IWD(object); - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE(self); - - nm_clear_g_cancellable(&priv->cancellable); - - nm_device_iwd_set_dbus_object(self, NULL); - - G_OBJECT_CLASS(nm_device_iwd_parent_class)->dispose(object); - - nm_assert(c_list_is_empty(&priv->aps_lst_head)); -} - -static void -nm_device_iwd_class_init(NMDeviceIwdClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->get_property = get_property; - object_class->dispose = dispose; - - dbus_object_class->interface_infos = - NM_DBUS_INTERFACE_INFOS(&nm_interface_info_device_wireless); - - device_class->connection_type_supported = NM_SETTING_WIRELESS_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_WIRELESS_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_WIFI); - - device_class->can_auto_connect = can_auto_connect; - device_class->is_available = is_available; - device_class->get_autoconnect_allowed = get_autoconnect_allowed; - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - device_class->get_enabled = get_enabled; - device_class->set_enabled = set_enabled; - device_class->get_type_description = get_type_description; - - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->get_configured_mtu = get_configured_mtu; - device_class->deactivate = deactivate; - device_class->deactivate_async = deactivate_async; - device_class->can_reapply_change = can_reapply_change; - - device_class->state_changed = device_state_changed; - - obj_properties[PROP_MODE] = g_param_spec_uint(NM_DEVICE_IWD_MODE, - "", - "", - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_AP, - NM_802_11_MODE_INFRA, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BITRATE] = g_param_spec_uint(NM_DEVICE_IWD_BITRATE, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ACCESS_POINTS] = - g_param_spec_boxed(NM_DEVICE_IWD_ACCESS_POINTS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ACTIVE_ACCESS_POINT] = - g_param_spec_string(NM_DEVICE_IWD_ACTIVE_ACCESS_POINT, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_CAPABILITIES] = - g_param_spec_uint(NM_DEVICE_IWD_CAPABILITIES, - "", - "", - 0, - G_MAXUINT32, - NM_WIFI_DEVICE_CAP_NONE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SCANNING] = g_param_spec_boolean(NM_DEVICE_IWD_SCANNING, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LAST_SCAN] = g_param_spec_int64(NM_DEVICE_IWD_LAST_SCAN, - "", - "", - -1, - G_MAXINT64, - -1, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/wifi/nm-device-iwd.h b/src/devices/wifi/nm-device-iwd.h deleted file mode 100644 index e364beaf..00000000 --- a/src/devices/wifi/nm-device-iwd.h +++ /dev/null @@ -1,47 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Intel Corporation - */ - -#ifndef __NETWORKMANAGER_DEVICE_IWD_H__ -#define __NETWORKMANAGER_DEVICE_IWD_H__ - -#include "devices/nm-device.h" -#include "nm-wifi-ap.h" -#include "nm-device-wifi.h" - -#define NM_TYPE_DEVICE_IWD (nm_device_iwd_get_type()) -#define NM_DEVICE_IWD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_IWD, NMDeviceIwd)) -#define NM_DEVICE_IWD_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_IWD, NMDeviceIwdClass)) -#define NM_IS_DEVICE_IWD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_IWD)) -#define NM_IS_DEVICE_IWD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_IWD)) -#define NM_DEVICE_IWD_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_IWD, NMDeviceIwdClass)) - -#define NM_DEVICE_IWD_MODE NM_DEVICE_WIFI_MODE -#define NM_DEVICE_IWD_BITRATE NM_DEVICE_WIFI_BITRATE -#define NM_DEVICE_IWD_ACCESS_POINTS NM_DEVICE_WIFI_ACCESS_POINTS -#define NM_DEVICE_IWD_ACTIVE_ACCESS_POINT NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT -#define NM_DEVICE_IWD_CAPABILITIES NM_DEVICE_WIFI_CAPABILITIES -#define NM_DEVICE_IWD_SCANNING NM_DEVICE_WIFI_SCANNING -#define NM_DEVICE_IWD_LAST_SCAN NM_DEVICE_WIFI_LAST_SCAN - -typedef struct _NMDeviceIwd NMDeviceIwd; -typedef struct _NMDeviceIwdClass NMDeviceIwdClass; - -GType nm_device_iwd_get_type(void); - -NMDevice *nm_device_iwd_new(const char *iface); - -void nm_device_iwd_set_dbus_object(NMDeviceIwd *device, GDBusObject *object); - -gboolean nm_device_iwd_agent_query(NMDeviceIwd *device, GDBusMethodInvocation *invocation); - -const CList *_nm_device_iwd_get_aps(NMDeviceIwd *self); - -void _nm_device_iwd_request_scan(NMDeviceIwd * self, - GVariant * options, - GDBusMethodInvocation *invocation); - -#endif /* __NETWORKMANAGER_DEVICE_IWD_H__ */ diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c deleted file mode 100644 index 22e94a6d..00000000 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ /dev/null @@ -1,551 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Dan Williams <dcbw@redhat.com> - * Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * Daniel Drake <dsd@laptop.org> - * Copyright (C) 2005 - 2014 Red Hat, Inc. - * Copyright (C) 2008 Collabora Ltd. - * Copyright (C) 2009 One Laptop per Child - */ - -#include "nm-default.h" - -#include "nm-device-olpc-mesh.h" - -#include <netinet/in.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <signal.h> -#include <unistd.h> -#include <sys/ioctl.h> - -#include "devices/nm-device.h" -#include "nm-device-wifi.h" -#include "devices/nm-device-private.h" -#include "nm-utils.h" -#include "NetworkManagerUtils.h" -#include "nm-act-request.h" -#include "nm-setting-connection.h" -#include "nm-setting-olpc-mesh.h" -#include "nm-manager.h" -#include "platform/nm-platform.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceOlpcMesh); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceOlpcMesh, PROP_COMPANION, PROP_ACTIVE_CHANNEL, ); - -typedef struct { - NMDevice * companion; - NMManager *manager; - bool stage1_waiting : 1; -} NMDeviceOlpcMeshPrivate; - -struct _NMDeviceOlpcMesh { - NMDevice parent; - NMDeviceOlpcMeshPrivate _priv; -}; - -struct _NMDeviceOlpcMeshClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE) - -#define NM_DEVICE_OLPC_MESH_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceOlpcMesh, NM_IS_DEVICE_OLPC_MESH, NMDevice) - -/*****************************************************************************/ - -static gboolean -get_autoconnect_allowed(NMDevice *device) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(device); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - /* We can't even connect if we don't have a companion yet. */ - if (!priv->companion) - return FALSE; - - /* We must not attempt to autoconnect when the companion is connected or - * connecting, * because we'd tear down its connection. */ - if (nm_device_get_state(priv->companion) > NM_DEVICE_STATE_DISCONNECTED) - return FALSE; - - return TRUE; -} - -#define DEFAULT_SSID "olpc-mesh" - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingOlpcMesh *s_mesh; - - s_mesh = nm_connection_get_setting_olpc_mesh(connection); - if (!s_mesh) { - s_mesh = (NMSettingOlpcMesh *) nm_setting_olpc_mesh_new(); - nm_connection_add_setting(connection, NM_SETTING(s_mesh)); - } - - if (!nm_setting_olpc_mesh_get_ssid(s_mesh)) { - gs_unref_bytes GBytes *ssid = NULL; - - ssid = g_bytes_new_static(DEFAULT_SSID, NM_STRLEN(DEFAULT_SSID)); - g_object_set(G_OBJECT(s_mesh), NM_SETTING_OLPC_MESH_SSID, ssid, NULL); - } - - if (!nm_setting_olpc_mesh_get_dhcp_anycast_address(s_mesh)) { - const char *anycast = "c0:27:c0:27:c0:27"; - - g_object_set(G_OBJECT(s_mesh), NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, anycast, NULL); - } - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_OLPC_MESH_SETTING_NAME, - existing_connections, - NULL, - _("Mesh"), - NULL, - NULL, - FALSE); /* No IPv6 by default */ - - return TRUE; -} - -/*****************************************************************************/ - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(device); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - /* disconnect companion device, if it is connected */ - if (nm_device_get_act_request(NM_DEVICE(priv->companion))) { - _LOGI(LOGD_OLPC, "disconnecting companion device %s", nm_device_get_iface(priv->companion)); - /* FIXME: VPN stuff here is a bug; but we can't really change API now... */ - nm_device_state_changed(NM_DEVICE(priv->companion), - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - _LOGI(LOGD_OLPC, "companion %s disconnected", nm_device_get_iface(priv->companion)); - } - - /* wait with continuing configuration until the companion device is done scanning */ - if (nm_device_wifi_get_scanning(NM_DEVICE_WIFI(priv->companion))) { - priv->stage1_waiting = TRUE; - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - priv->stage1_waiting = FALSE; - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static gboolean -_mesh_set_channel(NMDeviceOlpcMesh *self, guint32 channel) -{ - NMPlatform *platform; - int ifindex = nm_device_get_ifindex(NM_DEVICE(self)); - guint32 old_channel; - - platform = nm_device_get_platform(NM_DEVICE(self)); - old_channel = nm_platform_mesh_get_channel(platform, ifindex); - - if (channel == 0) - channel = old_channel; - - /* We want to call this even if the channel number is the same, - * because that actually starts the mesh with the configured mesh ID. */ - if (!nm_platform_mesh_set_channel(platform, ifindex, channel)) - return FALSE; - - if (old_channel != channel) - _notify(self, PROP_ACTIVE_CHANNEL); - - return TRUE; -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(device); - NMSettingOlpcMesh *s_mesh; - GBytes * ssid; - const char * anycast_addr; - gboolean success; - - s_mesh = nm_device_get_applied_setting(device, NM_TYPE_SETTING_OLPC_MESH); - g_return_val_if_fail(s_mesh, NM_ACT_STAGE_RETURN_FAILURE); - - ssid = nm_setting_olpc_mesh_get_ssid(s_mesh); - - nm_device_take_down(NM_DEVICE(self), TRUE); - success = nm_platform_mesh_set_ssid(nm_device_get_platform(device), - nm_device_get_ifindex(device), - g_bytes_get_data(ssid, NULL), - g_bytes_get_size(ssid)); - nm_device_bring_up(NM_DEVICE(self), TRUE, NULL); - if (!success) { - _LOGW(LOGD_WIFI, "Unable to set the mesh ID"); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - anycast_addr = nm_setting_olpc_mesh_get_dhcp_anycast_address(s_mesh); - nm_device_set_dhcp_anycast_address(device, anycast_addr); - - if (!_mesh_set_channel(self, nm_setting_olpc_mesh_get_channel(s_mesh))) { - _LOGW(LOGD_WIFI, "Unable to set the mesh channel"); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH(device); - - if (!NM_DEVICE_OLPC_MESH_GET_PRIVATE(self)->companion) { - _LOGD(LOGD_WIFI, "not available because companion not found"); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -companion_cleanup(NMDeviceOlpcMesh *self) -{ - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - if (priv->companion) { - nm_device_wifi_scanning_prohibited_track(NM_DEVICE_WIFI(priv->companion), self, FALSE); - g_signal_handlers_disconnect_by_data(priv->companion, self); - g_clear_object(&priv->companion); - } - _notify(self, PROP_COMPANION); -} - -static void -companion_notify_cb(NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_data) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(user_data); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - nm_assert(NM_IS_DEVICE_WIFI(companion)); - nm_assert(priv->companion == (gpointer) companion); - - if (!priv->stage1_waiting) - return; - - if (!nm_device_wifi_get_scanning(NM_DEVICE_WIFI(companion))) { - priv->stage1_waiting = FALSE; - nm_device_activate_schedule_stage1_device_prepare(NM_DEVICE(self), FALSE); - } -} - -/* disconnect from mesh if someone starts using the companion */ -static void -companion_state_changed_cb(NMDeviceWifi * companion, - NMDeviceState state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH(user_data); - NMDeviceState self_state = nm_device_get_state(NM_DEVICE(self)); - - if (old_state > NM_DEVICE_STATE_DISCONNECTED && state <= NM_DEVICE_STATE_DISCONNECTED) { - nm_device_emit_recheck_auto_activate(NM_DEVICE(self)); - } - - if (self_state < NM_DEVICE_STATE_PREPARE || self_state > NM_DEVICE_STATE_ACTIVATED - || state < NM_DEVICE_STATE_PREPARE || state > NM_DEVICE_STATE_ACTIVATED) - return; - - _LOGD(LOGD_OLPC, "disconnecting mesh due to companion connectivity"); - /* FIXME: VPN stuff here is a bug; but we can't really change API now... */ - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_USER_REQUESTED); -} - -static gboolean -companion_autoconnect_allowed_cb(NMDeviceWifi *companion, gpointer user_data) -{ - NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH(user_data); - NMDeviceState state = nm_device_get_state(NM_DEVICE(self)); - - /* Don't allow the companion to autoconnect while a mesh connection is - * active */ - return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_ACTIVATED); -} - -static gboolean -check_companion(NMDeviceOlpcMesh *self, NMDevice *other) -{ - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - const char * my_addr, *their_addr; - - if (!NM_IS_DEVICE_WIFI(other)) - return FALSE; - - my_addr = nm_device_get_hw_address(NM_DEVICE(self)); - their_addr = nm_device_get_hw_address(other); - if (!nm_utils_hwaddr_matches(my_addr, -1, their_addr, -1)) - return FALSE; - - nm_assert(priv->companion == NULL); - priv->companion = g_object_ref(other); - - _LOGI(LOGD_OLPC, "found companion Wi-Fi device %s", nm_device_get_iface(other)); - - g_signal_connect(G_OBJECT(other), - NM_DEVICE_STATE_CHANGED, - G_CALLBACK(companion_state_changed_cb), - self); - - g_signal_connect(G_OBJECT(other), - "notify::" NM_DEVICE_WIFI_SCANNING, - G_CALLBACK(companion_notify_cb), - self); - - g_signal_connect(G_OBJECT(other), - NM_DEVICE_AUTOCONNECT_ALLOWED, - G_CALLBACK(companion_autoconnect_allowed_cb), - self); - - _notify(self, PROP_COMPANION); - - return TRUE; -} - -static void -device_added_cb(NMManager *manager, NMDevice *other, gpointer user_data) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(user_data); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - if (!priv->companion && check_companion(self, other)) { - nm_device_queue_recheck_available(NM_DEVICE(self), - NM_DEVICE_STATE_REASON_NONE, - NM_DEVICE_STATE_REASON_NONE); - nm_device_remove_pending_action(NM_DEVICE(self), - NM_PENDING_ACTION_WAITING_FOR_COMPANION, - FALSE); - } -} - -static void -device_removed_cb(NMManager *manager, NMDevice *other, gpointer user_data) -{ - NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH(user_data); - - if (other == NM_DEVICE_OLPC_MESH_GET_PRIVATE(self)->companion) - companion_cleanup(self); -} - -static void -find_companion(NMDeviceOlpcMesh *self) -{ - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - const CList * tmp_lst; - NMDevice * candidate; - - if (priv->companion) - return; - - nm_device_add_pending_action(NM_DEVICE(self), NM_PENDING_ACTION_WAITING_FOR_COMPANION, TRUE); - - /* Try to find the companion if it's already known to the NMManager */ - nm_manager_for_each_device (priv->manager, candidate, tmp_lst) { - if (check_companion(self, candidate)) { - nm_device_queue_recheck_available(NM_DEVICE(self), - NM_DEVICE_STATE_REASON_NONE, - NM_DEVICE_STATE_REASON_NONE); - nm_device_remove_pending_action(NM_DEVICE(self), - NM_PENDING_ACTION_WAITING_FOR_COMPANION, - TRUE); - break; - } - } -} - -static void -state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(device); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - if (new_state == NM_DEVICE_STATE_UNAVAILABLE) - find_companion(self); - - if (priv->companion) { - gboolean temporarily_prohibited = FALSE; - - if (new_state >= NM_DEVICE_STATE_PREPARE && new_state <= NM_DEVICE_STATE_IP_CONFIG) { - /* Don't allow the companion to scan while configuring the mesh interface */ - temporarily_prohibited = TRUE; - } - nm_device_wifi_scanning_prohibited_track(NM_DEVICE_WIFI(priv->companion), - self, - temporarily_prohibited); - } -} - -static guint32 -get_dhcp_timeout_for_device(NMDevice *device, int addr_family) -{ - /* shorter timeout for mesh connectivity */ - return 20; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(object); - NMDevice * device = NM_DEVICE(self); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_COMPANION: - nm_dbus_utils_g_value_set_object_path(value, priv->companion); - break; - case PROP_ACTIVE_CHANNEL: - g_value_set_uint(value, - nm_platform_mesh_get_channel(nm_device_get_platform(device), - nm_device_get_ifindex(device))); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_olpc_mesh_init(NMDeviceOlpcMesh *self) -{} - -static void -constructed(GObject *object) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(object); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - G_OBJECT_CLASS(nm_device_olpc_mesh_parent_class)->constructed(object); - - priv->manager = g_object_ref(NM_MANAGER_GET); - - g_signal_connect(priv->manager, NM_MANAGER_DEVICE_ADDED, G_CALLBACK(device_added_cb), self); - g_signal_connect(priv->manager, NM_MANAGER_DEVICE_REMOVED, G_CALLBACK(device_removed_cb), self); -} - -NMDevice * -nm_device_olpc_mesh_new(const char *iface) -{ - return (NMDevice *) g_object_new(NM_TYPE_DEVICE_OLPC_MESH, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "802.11 OLPC Mesh", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_OLPC_MESH, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_OLPC_MESH, - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceOlpcMesh * self = NM_DEVICE_OLPC_MESH(object); - NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE(self); - - companion_cleanup(self); - - if (priv->manager) { - g_signal_handlers_disconnect_by_func(priv->manager, G_CALLBACK(device_added_cb), self); - g_signal_handlers_disconnect_by_func(priv->manager, G_CALLBACK(device_removed_cb), self); - g_clear_object(&priv->manager); - } - - G_OBJECT_CLASS(nm_device_olpc_mesh_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_olpc_mesh = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_OLPC_MESH, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Companion", - "o", - NM_DEVICE_OLPC_MESH_COMPANION), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L( - "ActiveChannel", - "u", - NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_olpc_mesh_class_init(NMDeviceOlpcMeshClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->constructed = constructed; - object_class->get_property = get_property; - object_class->dispose = dispose; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_olpc_mesh); - - device_class->connection_type_supported = NM_SETTING_OLPC_MESH_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_OLPC_MESH_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_OLPC_MESH); - - device_class->get_autoconnect_allowed = get_autoconnect_allowed; - device_class->complete_connection = complete_connection; - device_class->is_available = is_available; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->state_changed = state_changed; - device_class->get_dhcp_timeout_for_device = get_dhcp_timeout_for_device; - - obj_properties[PROP_COMPANION] = g_param_spec_string(NM_DEVICE_OLPC_MESH_COMPANION, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ACTIVE_CHANNEL] = - g_param_spec_uint(NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/wifi/nm-device-olpc-mesh.h b/src/devices/wifi/nm-device-olpc-mesh.h deleted file mode 100644 index d31c86fb..00000000 --- a/src/devices/wifi/nm-device-olpc-mesh.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Dan Williams <dcbw@redhat.com> - * Sjoerd Simons <sjoerd.simons@collabora.co.uk> - * Daniel Drake <dsd@laptop.org> - * Copyright (C) 2005 Red Hat, Inc. - * Copyright (C) 2008 Collabora Ltd. - * Copyright (C) 2009 One Laptop per Child - */ - -#ifndef __NETWORKMANAGER_DEVICE_OLPC_MESH_H__ -#define __NETWORKMANAGER_DEVICE_OLPC_MESH_H__ - -#include "devices/nm-device.h" - -#define NM_TYPE_DEVICE_OLPC_MESH (nm_device_olpc_mesh_get_type()) -#define NM_DEVICE_OLPC_MESH(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMesh)) -#define NM_DEVICE_OLPC_MESH_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass)) -#define NM_IS_DEVICE_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_OLPC_MESH)) -#define NM_IS_DEVICE_OLPC_MESH_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_OLPC_MESH)) -#define NM_DEVICE_OLPC_MESH_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass)) - -#define NM_DEVICE_OLPC_MESH_COMPANION "companion" -#define NM_DEVICE_OLPC_MESH_BITRATE "bitrate" -#define NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL "active-channel" - -typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; -typedef struct _NMDeviceOlpcMeshClass NMDeviceOlpcMeshClass; - -GType nm_device_olpc_mesh_get_type(void); - -NMDevice *nm_device_olpc_mesh_new(const char *iface); - -#endif /* __NETWORKMANAGER_DEVICE_OLPC_MESH_H__ */ diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c deleted file mode 100644 index 2e5317fd..00000000 --- a/src/devices/wifi/nm-device-wifi-p2p.c +++ /dev/null @@ -1,1280 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-wifi-p2p.h" - -#include <sys/socket.h> - -#include "supplicant/nm-supplicant-manager.h" -#include "supplicant/nm-supplicant-interface.h" - -#include "NetworkManagerUtils.h" -#include "devices/nm-device-private.h" -#include "nm-act-request.h" -#include "nm-core-internal.h" -#include "nm-glib-aux/nm-ref-string.h" -#include "nm-ip4-config.h" -#include "nm-manager.h" -#include "nm-manager.h" -#include "nm-setting-wifi-p2p.h" -#include "nm-utils.h" -#include "nm-wifi-p2p-peer.h" -#include "platform/nm-platform.h" -#include "platform/nmp-object.h" -#include "settings/nm-settings.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceWifiP2P); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceWifiP2P, PROP_PEERS, ); - -typedef struct { - NMSupplicantManager *sup_mgr; - - /* NOTE: In theory management and group ifaces could be identical. However, - * in practice, this cannot happen currently as NMDeviceWifiP2P is only - * created for existing non-P2P interfaces. - * (i.e. a single standalone P2P interface is not supported at this point) - */ - NMSupplicantInterface *mgmt_iface; - NMSupplicantInterface *group_iface; - - CList peers_lst_head; - - guint find_peer_timeout_id; - guint sup_timeout_id; - guint peer_dump_id; - guint peer_missing_id; - - bool is_waiting_for_supplicant : 1; -} NMDeviceWifiP2PPrivate; - -struct _NMDeviceWifiP2P { - NMDevice parent; - NMDeviceWifiP2PPrivate _priv; -}; - -struct _NMDeviceWifiP2PClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceWifiP2P, nm_device_wifi_p2p, NM_TYPE_DEVICE) - -#define NM_DEVICE_WIFI_P2P_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceWifiP2P, NM_IS_DEVICE_WIFI_P2P, NMDevice) - -/*****************************************************************************/ - -static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p; -static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_added; -static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_removed; - -static void supplicant_group_interface_release(NMDeviceWifiP2P *self); -static void supplicant_interfaces_release(NMDeviceWifiP2P *self, gboolean set_is_waiting); - -/*****************************************************************************/ - -static void -_peer_dump(NMDeviceWifiP2P * self, - NMLogLevel log_level, - const NMWifiP2PPeer *peer, - const char * prefix, - gint32 now_s) -{ - char buf[1024]; - - _NMLOG(log_level, - LOGD_WIFI_SCAN, - "wifi-peer: %-7s %s", - prefix, - nm_wifi_p2p_peer_to_string(peer, buf, sizeof(buf), now_s)); -} - -static gboolean -peer_list_dump(gpointer user_data) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(user_data); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - priv->peer_dump_id = 0; - - if (_LOGD_ENABLED(LOGD_WIFI_SCAN)) { - NMWifiP2PPeer *peer; - gint32 now_s = nm_utils_get_monotonic_timestamp_sec(); - - _LOGD(LOGD_WIFI_SCAN, "P2P Peers: [now:%u]", now_s); - c_list_for_each_entry (peer, &priv->peers_lst_head, peers_lst) - _peer_dump(self, LOGL_DEBUG, peer, "dump", now_s); - } - return G_SOURCE_REMOVE; -} - -static void -schedule_peer_list_dump(NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - if (!priv->peer_dump_id && _LOGD_ENABLED(LOGD_WIFI_SCAN)) - priv->peer_dump_id = g_timeout_add_seconds(1, peer_list_dump, self); -} - -/*****************************************************************************/ - -static void -_set_is_waiting_for_supplicant(NMDeviceWifiP2P *self, gboolean is_waiting) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - if (priv->is_waiting_for_supplicant == (!!is_waiting)) - return; - - priv->is_waiting_for_supplicant = is_waiting; - - if (is_waiting) - nm_device_add_pending_action(NM_DEVICE(self), - NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, - TRUE); - else - nm_device_remove_pending_action(NM_DEVICE(self), - NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, - TRUE); -} - -/*****************************************************************************/ - -static gboolean -check_connection_peer_joined(NMDeviceWifiP2P *device) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(device); - NMConnection * conn = nm_device_get_applied_connection(NM_DEVICE(device)); - NMWifiP2PPeer * peer; - const char * group; - const char *const * groups; - - if (!conn || !priv->group_iface) - return FALSE; - - /* Comparing the object path found on the group_iface with the peers - * found on the mgmt_iface is legal. */ - group = nm_supplicant_interface_get_p2p_group_path(priv->group_iface); - if (!group) - return FALSE; - - /* NOTE: We currently only support connections to a specific peer */ - peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, conn); - if (!peer) - return FALSE; - - groups = nm_wifi_p2p_peer_get_groups(peer); - if (!groups || !g_strv_contains(groups, group)) - return FALSE; - - return TRUE; -} - -static gboolean -disconnect_on_connection_peer_missing_cb(gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(device); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - _LOGW(LOGD_WIFI, "Peer requested in connection is missing for too long, failing connection."); - - priv->peer_missing_id = 0; - - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND); - return FALSE; -} - -static void -update_disconnect_on_connection_peer_missing(NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - NMDeviceState state; - - state = nm_device_get_state(NM_DEVICE(self)); - if (state < NM_DEVICE_STATE_IP_CONFIG || state > NM_DEVICE_STATE_ACTIVATED) { - nm_clear_g_source(&priv->peer_missing_id); - return; - } - - if (check_connection_peer_joined(self)) { - if (nm_clear_g_source(&priv->peer_missing_id)) - _LOGD(LOGD_WIFI, "Peer requested in connection is joined, removing timeout"); - return; - } - - if (priv->peer_missing_id == 0) { - _LOGD(LOGD_WIFI, "Peer requested in connection is missing, adding timeout"); - priv->peer_missing_id = - g_timeout_add_seconds(5, disconnect_on_connection_peer_missing_cb, self); - } -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(device); - NMDeviceWifiP2PPrivate * priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - NMSupplicantInterfaceState supplicant_state; - - if (!priv->mgmt_iface) - return FALSE; - - supplicant_state = nm_supplicant_interface_get_state(priv->mgmt_iface); - return nm_supplicant_interface_state_is_operational(supplicant_state); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - if (!NM_DEVICE_CLASS(nm_device_wifi_p2p_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - /* TODO: Allow limitting the interface using the HW-address? */ - - /* We don't need to check anything else here. The P2P device will only - * exists if we are able to establish a P2P connection, and there should - * be no further restrictions necessary. - */ - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(device); - gs_free char * setting_name = NULL; - NMSettingWifiP2P *s_wifi_p2p; - NMWifiP2PPeer * peer; - const char * setting_peer; - - s_wifi_p2p = - NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)); - - if (!specific_object) { - /* If not given a specific object, we need at minimum a peer address */ - if (!s_wifi_p2p) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A '%s' setting is required if no Peer path was given", - NM_SETTING_WIFI_P2P_SETTING_NAME); - return FALSE; - } - - setting_peer = nm_setting_wifi_p2p_get_peer(s_wifi_p2p); - if (!setting_peer) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A '%s' setting with a valid Peer is required if no Peer path was given", - NM_SETTING_WIFI_P2P_SETTING_NAME); - return FALSE; - } - - } else { - peer = nm_wifi_p2p_peer_lookup_for_device(NM_DEVICE(self), specific_object); - if (!peer) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND, - "The P2P peer %s is unknown", - specific_object); - return FALSE; - } - - setting_peer = nm_wifi_p2p_peer_get_address(peer); - g_return_val_if_fail(setting_peer, FALSE); - } - - /* Add a Wi-Fi P2P setting if one doesn't exist yet */ - if (!s_wifi_p2p) { - s_wifi_p2p = NM_SETTING_WIFI_P2P(nm_setting_wifi_p2p_new()); - nm_connection_add_setting(connection, NM_SETTING(s_wifi_p2p)); - } - - g_object_set(G_OBJECT(s_wifi_p2p), NM_SETTING_WIFI_P2P_PEER, setting_peer, NULL); - - setting_name = g_strdup_printf("Wi-Fi P2P Peer %s", setting_peer); - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_WIFI_P2P_SETTING_NAME, - existing_connections, - setting_name, - setting_name, - NULL, - NULL, - TRUE); - - return TRUE; -} - -/* - * supplicant_find_timeout_cb - * - * Called when the supplicant has been unable to find the peer we want to connect to. - */ -static gboolean -supplicant_find_timeout_cb(gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(user_data); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - priv->find_peer_timeout_id = 0; - - nm_supplicant_interface_p2p_cancel_connect(priv->mgmt_iface); - - if (nm_device_is_activating(device)) { - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi-p2p) could not find peer, failing activation"); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_PEER_NOT_FOUND); - } - - return G_SOURCE_REMOVE; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(device); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - NMConnection * connection; - NMSettingWifiP2P * s_wifi_p2p; - NMWifiP2PPeer * peer; - - if (!priv->mgmt_iface) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_wifi_p2p = - NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)); - g_return_val_if_fail(s_wifi_p2p, NM_ACT_STAGE_RETURN_FAILURE); - - peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection); - if (!peer) { - /* Set up a timeout on the find attempt and run a find for the same period of time */ - if (priv->find_peer_timeout_id == 0) { - priv->find_peer_timeout_id = - g_timeout_add_seconds(10, supplicant_find_timeout_cb, self); - - nm_supplicant_interface_p2p_start_find(priv->mgmt_iface, 10); - } - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -/* - * supplicant_connection_timeout_cb - * - * Called when the supplicant has been unable to connect to a peer - * within a specified period of time. - */ -static gboolean -supplicant_connection_timeout_cb(gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(user_data); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - priv->sup_timeout_id = 0; - - nm_supplicant_interface_p2p_cancel_connect(priv->mgmt_iface); - - if (nm_device_is_activating(device)) { - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi-p2p) connecting took too long, failing activation"); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); - } - - return G_SOURCE_REMOVE; -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(device); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - NMConnection * connection; - NMSettingWifiP2P * s_wifi_p2p; - NMWifiP2PPeer * peer; - GBytes * wfd_ies; - - if (nm_clear_g_source(&priv->find_peer_timeout_id)) - nm_assert_not_reached(); - - if (!priv->mgmt_iface) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - connection = nm_device_get_applied_connection(device); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - nm_assert( - NM_IS_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P))); - - /* The prepare stage ensures that the peer has been found */ - peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection); - if (!peer) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PEER_NOT_FOUND); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - /* Set the WFD IEs before trying to establish the connection. */ - s_wifi_p2p = - NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)); - wfd_ies = nm_setting_wifi_p2p_get_wfd_ies(s_wifi_p2p); - nm_supplicant_manager_set_wfd_ies(priv->sup_mgr, wfd_ies); - - /* TODO: Grab secrets if we don't have them yet! */ - - /* TODO: Fix "pbc" being hardcoded here! */ - nm_supplicant_interface_p2p_connect(priv->mgmt_iface, - nm_wifi_p2p_peer_get_supplicant_path(peer), - "pbc", - NULL); - - /* Set up a timeout on the connect attempt */ - if (priv->sup_timeout_id == 0) { - priv->sup_timeout_id = g_timeout_add_seconds(45, supplicant_connection_timeout_cb, self); - } - - /* We'll get stage3 started when the P2P group has been started */ - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static void -emit_signal_p2p_peer_add_remove(NMDeviceWifiP2P *device, - NMWifiP2PPeer * peer, - gboolean is_added /* or else is_removed */) -{ - nm_dbus_object_emit_signal(NM_DBUS_OBJECT(device), - &interface_info_device_wifi_p2p, - is_added ? &nm_signal_info_wifi_p2p_peer_added - : &nm_signal_info_wifi_p2p_peer_removed, - "(o)", - nm_dbus_object_get_path(NM_DBUS_OBJECT(peer))); -} - -static void -peer_add_remove(NMDeviceWifiP2P *self, - gboolean is_adding, /* or else removing */ - NMWifiP2PPeer * peer, - gboolean recheck_available_connections) -{ - NMDevice * device = NM_DEVICE(self); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - if (is_adding) { - g_object_ref(peer); - peer->wifi_device = device; - c_list_link_tail(&priv->peers_lst_head, &peer->peers_lst); - nm_dbus_object_export(NM_DBUS_OBJECT(peer)); - _peer_dump(self, LOGL_DEBUG, peer, "added", 0); - - emit_signal_p2p_peer_add_remove(self, peer, TRUE); - } else { - peer->wifi_device = NULL; - c_list_unlink(&peer->peers_lst); - _peer_dump(self, LOGL_DEBUG, peer, "removed", 0); - } - - _notify(self, PROP_PEERS); - - if (!is_adding) { - emit_signal_p2p_peer_add_remove(self, peer, FALSE); - nm_dbus_object_clear_and_unexport(&peer); - } - - if (is_adding) { - /* If we are in prepare state, then we are currently runnign a find - * to search for the requested peer. */ - if (priv->find_peer_timeout_id != 0) { - NMConnection *connection; - - nm_assert(nm_device_get_state(device) == NM_DEVICE_STATE_PREPARE); - - connection = nm_device_get_applied_connection(device); - nm_assert(NM_IS_CONNECTION(connection)); - - peer = nm_wifi_p2p_peers_find_first_compatible(&priv->peers_lst_head, connection); - if (peer) { - /* A peer for the connection was found, cancel the timeout and go to configure state. */ - nm_clear_g_source(&priv->find_peer_timeout_id); - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); - } - } - - /* TODO: We may want to re-check auto-activation here, otherwise it will never work. */ - } - - update_disconnect_on_connection_peer_missing(self); -} - -static void -remove_all_peers(NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - NMWifiP2PPeer * peer; - - if (c_list_is_empty(&priv->peers_lst_head)) - return; - - while ((peer = c_list_first_entry(&priv->peers_lst_head, NMWifiP2PPeer, peers_lst))) - peer_add_remove(self, FALSE, peer, FALSE); - - nm_device_recheck_available_connections(NM_DEVICE(self)); -} - -/*****************************************************************************/ - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - gboolean indicate_addressing_running; - NMConnection *connection; - const char * method; - - connection = nm_device_get_applied_connection(device); - - method = nm_utils_get_ip_config_method(connection, addr_family); - - if (addr_family == AF_INET) - indicate_addressing_running = NM_IN_STRSET(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - else { - indicate_addressing_running = NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP); - } - - if (indicate_addressing_running) - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - TRUE); - - return NM_DEVICE_CLASS(nm_device_wifi_p2p_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(device); - int ifindex = nm_device_get_ip_ifindex(device); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - nm_clear_g_source(&priv->find_peer_timeout_id); - nm_clear_g_source(&priv->sup_timeout_id); - nm_clear_g_source(&priv->peer_missing_id); - - if (priv->mgmt_iface) - nm_supplicant_interface_p2p_cancel_connect(priv->mgmt_iface); - - if (priv->group_iface) - nm_supplicant_interface_p2p_disconnect(priv->group_iface); - - /* Clear any critical protocol notification in the Wi-Fi stack */ - if (ifindex > 0) - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), - ifindex, - FALSE); -} - -static guint32 -get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - *out_source = NM_DEVICE_MTU_SOURCE_NONE; - return 0; -} - -static const char * -get_auto_ip_config_method(NMDevice *device, int addr_family) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(device); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - /* Override the AUTO method to mean shared if we are group owner. */ - if (priv->group_iface && nm_supplicant_interface_get_p2p_group_owner(priv->group_iface)) { - if (addr_family == AF_INET) - return NM_SETTING_IP4_CONFIG_METHOD_SHARED; - - if (addr_family == AF_INET6) - return NM_SETTING_IP6_CONFIG_METHOD_SHARED; - } - - return NULL; -} - -static gboolean -unmanaged_on_quit(NMDevice *self) -{ - return TRUE; -} - -static void -supplicant_iface_state_cb(NMSupplicantInterface *iface, - int new_state_i, - int old_state_i, - int disconnect_reason, - gpointer user_data) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(user_data); - NMDevice * device = NM_DEVICE(self); - NMSupplicantInterfaceState new_state = new_state_i; - NMSupplicantInterfaceState old_state = old_state_i; - - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "supplicant management interface state: %s -> %s", - nm_supplicant_interface_state_to_string(old_state), - nm_supplicant_interface_state_to_string(new_state)); - - if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - supplicant_interfaces_release(self, TRUE); - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return; - } - - if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { - _LOGD(LOGD_WIFI, "supplicant ready"); - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - _set_is_waiting_for_supplicant(self, FALSE); - } -} - -static void -supplicant_iface_peer_changed_cb(NMSupplicantInterface *iface, - NMSupplicantPeerInfo * peer_info, - gboolean is_present, - NMDeviceWifiP2P * self) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - NMWifiP2PPeer * found_peer; - - found_peer = - nm_wifi_p2p_peers_find_by_supplicant_path(&priv->peers_lst_head, peer_info->peer_path->str); - - if (!is_present) { - if (!found_peer) - return; - - peer_add_remove(self, FALSE, found_peer, TRUE); - goto out; - } - - if (found_peer) { - if (!nm_wifi_p2p_peer_update_from_properties(found_peer, peer_info)) - return; - - update_disconnect_on_connection_peer_missing(self); - _peer_dump(self, LOGL_DEBUG, found_peer, "updated", 0); - } else { - gs_unref_object NMWifiP2PPeer *peer = NULL; - - peer = nm_wifi_p2p_peer_new_from_properties(peer_info); - peer_add_remove(self, TRUE, peer, TRUE); - } - -out: - schedule_peer_list_dump(self); -} - -static void -check_group_iface_ready(NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - if (!priv->group_iface) - return; - - if (!nm_supplicant_interface_state_is_operational( - nm_supplicant_interface_get_state(priv->group_iface))) - return; - - if (!nm_supplicant_interface_get_p2p_group_joined(priv->group_iface)) - return; - - nm_clear_g_source(&priv->sup_timeout_id); - update_disconnect_on_connection_peer_missing(self); - - nm_device_activate_schedule_stage3_ip_config_start(NM_DEVICE(self)); -} - -static void -supplicant_group_iface_is_ready(NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - _LOGD(LOGD_WIFI, "P2P Group supplicant ready"); - - if (!nm_device_set_ip_iface(NM_DEVICE(self), - nm_supplicant_interface_get_ifname(priv->group_iface))) { - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - return; - } - - _set_is_waiting_for_supplicant(self, FALSE); - check_group_iface_ready(self); -} - -static void -supplicant_group_iface_state_cb(NMSupplicantInterface *iface, - int new_state_i, - int old_state_i, - int disconnect_reason, - gpointer user_data) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(user_data); - NMSupplicantInterfaceState new_state = new_state_i; - NMSupplicantInterfaceState old_state = old_state_i; - - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "P2P Group supplicant interface state: %s -> %s", - nm_supplicant_interface_state_to_string(old_state), - nm_supplicant_interface_state_to_string(new_state)); - - if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - supplicant_group_interface_release(self); - - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - return; - } - - if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { - supplicant_group_iface_is_ready(self); - return; - } -} - -static void -supplicant_group_iface_group_finished_cb(NMSupplicantInterface *iface, - const char * iface_path, - void * user_data) -{ - NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(user_data); - - supplicant_group_interface_release(self); - - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); -} - -static void -supplicant_iface_group_joined_updated_cb(NMSupplicantInterface *iface, - GParamSpec * pspec, - void * user_data) -{ - NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(user_data); - - check_group_iface_ready(self); -} - -static void -supplicant_iface_group_started_cb(NMSupplicantInterface *iface, - NMSupplicantInterface *group_iface, - NMDeviceWifiP2P * self) -{ - NMDeviceWifiP2PPrivate * priv; - NMSupplicantInterfaceState state; - - g_return_if_fail(self); - - if (!nm_device_is_activating(NM_DEVICE(self))) { - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "P2P: WPA supplicant notified a group start but we are not trying to connect! " - "Ignoring the event."); - return; - } - - priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - supplicant_group_interface_release(self); - - priv->group_iface = g_object_ref(group_iface); - - /* We need to wait for the interface to be ready and the group - * information to be resolved. */ - g_signal_connect(priv->group_iface, - "notify::" NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED, - G_CALLBACK(supplicant_iface_group_joined_updated_cb), - self); - - g_signal_connect(priv->group_iface, - NM_SUPPLICANT_INTERFACE_STATE, - G_CALLBACK(supplicant_group_iface_state_cb), - self); - - g_signal_connect(priv->group_iface, - NM_SUPPLICANT_INTERFACE_GROUP_FINISHED, - G_CALLBACK(supplicant_group_iface_group_finished_cb), - self); - - state = nm_supplicant_interface_get_state(priv->group_iface); - if (state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { - _set_is_waiting_for_supplicant(self, TRUE); - return; - } - - supplicant_group_iface_is_ready(self); -} - -static void -supplicant_group_interface_release(NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - if (!priv->group_iface) - return; - - g_signal_handlers_disconnect_by_data(priv->group_iface, self); - - nm_supplicant_interface_p2p_disconnect(priv->group_iface); - - g_clear_object(&priv->group_iface); -} - -static void -supplicant_interfaces_release(NMDeviceWifiP2P *self, gboolean set_is_waiting) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - nm_clear_g_source(&priv->peer_dump_id); - - remove_all_peers(self); - - if (priv->mgmt_iface) { - _LOGD(LOGD_DEVICE | LOGD_WIFI, "P2P: Releasing WPA supplicant interface."); - nm_supplicant_manager_set_wfd_ies(priv->sup_mgr, NULL); - g_signal_handlers_disconnect_by_data(priv->mgmt_iface, self); - g_clear_object(&priv->mgmt_iface); - nm_clear_g_source(&priv->find_peer_timeout_id); - nm_clear_g_source(&priv->sup_timeout_id); - } - - supplicant_group_interface_release(self); - - if (set_is_waiting) - _set_is_waiting_for_supplicant(self, TRUE); -} - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(device); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - update_disconnect_on_connection_peer_missing(self); - - if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) { - /* Clean up the supplicant interface because in these states the - * device cannot be used. - * Do not clean up for the UNMANAGED to UNAVAILABLE transition which - * will happen during initialization. - */ - if (priv->mgmt_iface && old_state > new_state) - supplicant_interfaces_release(self, TRUE); - - /* TODO: More cleanup needed? */ - } - - switch (new_state) { - case NM_DEVICE_STATE_UNMANAGED: - break; - case NM_DEVICE_STATE_UNAVAILABLE: - if (!priv->mgmt_iface - || !nm_supplicant_interface_state_is_operational( - nm_supplicant_interface_get_state(priv->mgmt_iface))) - _set_is_waiting_for_supplicant(self, TRUE); - break; - case NM_DEVICE_STATE_NEED_AUTH: - /* Disconnect? */ - break; - case NM_DEVICE_STATE_IP_CHECK: - /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - FALSE); - break; - case NM_DEVICE_STATE_ACTIVATED: - //activation_success_handler (device); - break; - case NM_DEVICE_STATE_FAILED: - /* Clear any critical protocol notification in the wifi stack. - * At this point the IP device may have been removed already. */ - nm_supplicant_manager_set_wfd_ies(priv->sup_mgr, NULL); - if (nm_device_get_ip_ifindex(device) > 0) - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - FALSE); - break; - case NM_DEVICE_STATE_DISCONNECTED: - nm_supplicant_manager_set_wfd_ies(priv->sup_mgr, NULL); - break; - default: - break; - } -} - -static void -impl_device_wifi_p2p_start_find(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(obj); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - gs_unref_variant GVariant *options = NULL; - const char * opts_key; - GVariant * opts_val; - GVariantIter iter; - gint32 timeout = 30; - - g_variant_get(parameters, "(@a{sv})", &options); - - g_variant_iter_init(&iter, options); - while (g_variant_iter_next(&iter, "{&sv}", &opts_key, &opts_val)) { - _nm_unused gs_unref_variant GVariant *opts_val_free = opts_val; - - if (nm_streq(opts_key, "timeout")) { - if (!g_variant_is_of_type(opts_val, G_VARIANT_TYPE_INT32)) { - g_dbus_method_invocation_return_error_literal( - invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_ARGUMENT, - "\"timeout\" must be an integer \"i\""); - return; - } - - timeout = g_variant_get_int32(opts_val); - if (timeout <= 0 || timeout > 600) { - g_dbus_method_invocation_return_error_literal( - invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "The timeout for a find operation needs to be in the range of 1-600s."); - return; - } - - continue; - } - - g_dbus_method_invocation_return_error(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_ARGUMENT, - "Unsupported options key \"%s\"", - opts_key); - return; - } - - if (!priv->mgmt_iface) { - g_dbus_method_invocation_return_error_literal( - invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "WPA Supplicant management interface is currently unavailable."); - return; - } - - nm_supplicant_interface_p2p_start_find(priv->mgmt_iface, timeout); - - g_dbus_method_invocation_return_value(invocation, NULL); -} - -static void -impl_device_wifi_p2p_stop_find(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(obj); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - if (!priv->mgmt_iface) { - g_dbus_method_invocation_return_error_literal( - invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ACTIVE, - "WPA Supplicant management interface is currently unavailable."); - return; - } - - nm_supplicant_interface_p2p_stop_find(priv->mgmt_iface); - - g_dbus_method_invocation_return_value(invocation, NULL); -} - -/*****************************************************************************/ - -NMSupplicantInterface * -nm_device_wifi_p2p_get_mgmt_iface(NMDeviceWifiP2P *self) -{ - g_return_val_if_fail(NM_IS_DEVICE_WIFI_P2P(self), NULL); - - return NM_DEVICE_WIFI_P2P_GET_PRIVATE(self)->mgmt_iface; -} - -void -nm_device_wifi_p2p_set_mgmt_iface(NMDeviceWifiP2P *self, NMSupplicantInterface *iface) -{ - NMDeviceWifiP2PPrivate *priv; - - g_return_if_fail(NM_IS_DEVICE_WIFI_P2P(self)); - g_return_if_fail(!iface || NM_IS_SUPPLICANT_INTERFACE(iface)); - - priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - if (priv->mgmt_iface == iface) - goto done; - - supplicant_interfaces_release(self, FALSE); - - if (!iface) - goto done; - - _LOGD(LOGD_DEVICE | LOGD_WIFI, - "P2P: WPA supplicant management interface changed to %s.", - nm_ref_string_get_str(nm_supplicant_interface_get_object_path(iface))); - - priv->mgmt_iface = g_object_ref(iface); - - g_signal_connect(priv->mgmt_iface, - NM_SUPPLICANT_INTERFACE_STATE, - G_CALLBACK(supplicant_iface_state_cb), - self); - g_signal_connect(priv->mgmt_iface, - NM_SUPPLICANT_INTERFACE_PEER_CHANGED, - G_CALLBACK(supplicant_iface_peer_changed_cb), - self); - g_signal_connect(priv->mgmt_iface, - NM_SUPPLICANT_INTERFACE_GROUP_STARTED, - G_CALLBACK(supplicant_iface_group_started_cb), - self); -done: - nm_device_queue_recheck_available(NM_DEVICE(self), - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - _set_is_waiting_for_supplicant(self, - !priv->mgmt_iface - || !nm_supplicant_interface_state_is_operational( - nm_supplicant_interface_get_state(priv->mgmt_iface))); -} - -void -nm_device_wifi_p2p_remove(NMDeviceWifiP2P *self) -{ - g_signal_emit_by_name(self, NM_DEVICE_REMOVED); -} - -/*****************************************************************************/ - -static const char * -get_type_description(NMDevice *device) -{ - return "wifi-p2p"; -} - -/*****************************************************************************/ - -static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( - "PeerAdded", - .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("peer", "o"), ), ); - -static const GDBusSignalInfo nm_signal_info_wifi_p2p_peer_removed = - NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( - "PeerRemoved", - .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("peer", "o"), ), ); - -static const NMDBusInterfaceInfoExtended interface_info_device_wifi_p2p = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_WIFI_P2P, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( - NM_DEFINE_GDBUS_METHOD_INFO_INIT( - "StartFind", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("options", "a{sv}"), ), ), - .handle = impl_device_wifi_p2p_start_find, ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED(NM_DEFINE_GDBUS_METHOD_INFO_INIT("StopFind", ), - .handle = impl_device_wifi_p2p_stop_find, ), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_wifi_p2p_peer_added, - &nm_signal_info_wifi_p2p_peer_removed, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Peers", - "ao", - NM_DEVICE_WIFI_P2P_PEERS), ), ), - .legacy_property_changed = FALSE, -}; - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(object); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - const char ** list; - - switch (prop_id) { - case PROP_PEERS: - list = nm_wifi_p2p_peers_get_paths(&priv->peers_lst_head); - g_value_take_boxed(value, nm_utils_strv_make_deep_copied(list)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_wifi_p2p_init(NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(self); - - c_list_init(&priv->peers_lst_head); - - priv->sup_mgr = g_object_ref(nm_supplicant_manager_get()); -} - -static void -constructed(GObject *object) -{ - NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P(object); - - G_OBJECT_CLASS(nm_device_wifi_p2p_parent_class)->constructed(object); - - _set_is_waiting_for_supplicant(self, TRUE); -} - -NMDeviceWifiP2P * -nm_device_wifi_p2p_new(const char *iface) -{ - return g_object_new(NM_TYPE_DEVICE_WIFI_P2P, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "802.11 Wi-Fi P2P", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_WIFI_P2P, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_WIFI, - NM_DEVICE_RFKILL_TYPE, - RFKILL_TYPE_WLAN, - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceWifiP2P * self = NM_DEVICE_WIFI_P2P(object); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(object); - - g_clear_object(&priv->sup_mgr); - - supplicant_interfaces_release(self, FALSE); - - G_OBJECT_CLASS(nm_device_wifi_p2p_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMDeviceWifiP2P * peer = NM_DEVICE_WIFI_P2P(object); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE(peer); - - nm_assert(c_list_is_empty(&priv->peers_lst_head)); - - G_OBJECT_CLASS(nm_device_wifi_p2p_parent_class)->finalize(object); -} - -static void -nm_device_wifi_p2p_class_init(NMDeviceWifiP2PClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->constructed = constructed; - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_wifi_p2p); - - device_class->connection_type_supported = NM_SETTING_WIFI_P2P_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_WIFI_P2P_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_WIFI_P2P); - device_class->get_type_description = get_type_description; - - /* Do we need compatibility checking or is the default good enough? */ - device_class->is_available = is_available; - device_class->check_connection_compatible = check_connection_compatible; - device_class->complete_connection = complete_connection; - - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->get_configured_mtu = get_configured_mtu; - device_class->get_auto_ip_config_method = get_auto_ip_config_method; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - - device_class->deactivate = deactivate; - device_class->unmanaged_on_quit = unmanaged_on_quit; - - device_class->state_changed = device_state_changed; - - obj_properties[PROP_PEERS] = g_param_spec_boxed(NM_DEVICE_WIFI_P2P_PEERS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/wifi/nm-device-wifi-p2p.h b/src/devices/wifi/nm-device-wifi-p2p.h deleted file mode 100644 index 03e49311..00000000 --- a/src/devices/wifi/nm-device-wifi-p2p.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NM_DEVICE_WIFI_P2P_H__ -#define __NM_DEVICE_WIFI_P2P_H__ - -#include "devices/nm-device.h" -#include "supplicant/nm-supplicant-interface.h" - -#define NM_TYPE_DEVICE_WIFI_P2P (nm_device_wifi_p2p_get_type()) -#define NM_DEVICE_WIFI_P2P(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2P)) -#define NM_DEVICE_WIFI_P2P_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2PClass)) -#define NM_IS_DEVICE_WIFI_P2P(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIFI_P2P)) -#define NM_IS_DEVICE_WIFI_P2P_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_WIFI_P2P)) -#define NM_DEVICE_WIFI_P2P_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_WIFI_P2P, NMDeviceWifiP2PClass)) - -#define NM_DEVICE_WIFI_P2P_PEERS "peers" -#define NM_DEVICE_WIFI_P2P_GROUPS "groups" - -typedef struct _NMDeviceWifiP2P NMDeviceWifiP2P; -typedef struct _NMDeviceWifiP2PClass NMDeviceWifiP2PClass; - -GType nm_device_wifi_p2p_get_type(void); - -NMDeviceWifiP2P *nm_device_wifi_p2p_new(const char *iface); - -NMSupplicantInterface *nm_device_wifi_p2p_get_mgmt_iface(NMDeviceWifiP2P *self); -void nm_device_wifi_p2p_set_mgmt_iface(NMDeviceWifiP2P *self, NMSupplicantInterface *iface); - -void nm_device_wifi_p2p_remove(NMDeviceWifiP2P *self); - -#endif /* __NM_DEVICE_WIFI_P2P_H__ */ diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c deleted file mode 100644 index 980916dd..00000000 --- a/src/devices/wifi/nm-device-wifi.c +++ /dev/null @@ -1,3847 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2017 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-wifi.h" - -#include <netinet/in.h> -#include <unistd.h> - -#include "nm-glib-aux/nm-ref-string.h" -#include "nm-glib-aux/nm-c-list.h" -#include "nm-device-wifi-p2p.h" -#include "nm-wifi-ap.h" -#include "nm-libnm-core-intern/nm-common-macros.h" -#include "devices/nm-device.h" -#include "devices/nm-device-private.h" -#include "nm-dbus-manager.h" -#include "nm-utils.h" -#include "NetworkManagerUtils.h" -#include "nm-act-request.h" -#include "supplicant/nm-supplicant-manager.h" -#include "supplicant/nm-supplicant-interface.h" -#include "supplicant/nm-supplicant-config.h" -#include "nm-setting-connection.h" -#include "nm-setting-wireless.h" -#include "nm-setting-wireless-security.h" -#include "nm-setting-8021x.h" -#include "nm-setting-ip4-config.h" -#include "nm-ip4-config.h" -#include "nm-setting-ip6-config.h" -#include "platform/nm-platform.h" -#include "nm-auth-utils.h" -#include "settings/nm-settings-connection.h" -#include "settings/nm-settings.h" -#include "nm-wifi-utils.h" -#include "nm-wifi-common.h" -#include "nm-core-internal.h" -#include "nm-config.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceWifi); - -#define SCAN_INTERVAL_SEC_MIN 3 -#define SCAN_INTERVAL_SEC_STEP 20 -#define SCAN_INTERVAL_SEC_MAX 120 - -#define SCAN_EXTRA_DELAY_MSEC 500 - -#define SCAN_RAND_MAC_ADDRESS_EXPIRE_SEC (5 * 60) - -#define SCAN_REQUEST_SSIDS_MAX_NUM 32u -#define SCAN_REQUEST_SSIDS_MAX_AGE_MSEC (3 * 60 * NM_UTILS_MSEC_PER_SEC) - -#define _LOGT_scan(...) _LOGT(LOGD_WIFI_SCAN, "wifi-scan: " __VA_ARGS__) - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceWifi, - PROP_MODE, - PROP_BITRATE, - PROP_ACCESS_POINTS, - PROP_ACTIVE_ACCESS_POINT, - PROP_CAPABILITIES, - PROP_SCANNING, - PROP_LAST_SCAN, ); - -enum { - P2P_DEVICE_CREATED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct { - CList aps_lst_head; - GHashTable *aps_idx_by_supplicant_path; - - CList scanning_prohibited_lst_head; - - GCancellable *scan_request_cancellable; - - GSource *scan_request_delay_source; - - NMWifiAP *current_ap; - - GHashTable *scan_request_ssids_hash; - CList scan_request_ssids_lst_head; - - NMActRequestGetSecretsCallId *wifi_secrets_id; - - NMSupplicantManager * sup_mgr; - NMSupplMgrCreateIfaceHandle *sup_create_handle; - NMSupplicantInterface * sup_iface; - - gint64 scan_last_complete_msec; - gint64 scan_periodic_next_msec; - - gint64 scan_last_request_started_at_msec; - - guint scan_kickoff_timeout_id; - - guint ap_dump_id; - - guint periodic_update_id; - - guint link_timeout_id; - guint reacquire_iface_id; - guint wps_timeout_id; - guint sup_timeout_id; /* supplicant association timeout */ - - NMDeviceWifiCapabilities capabilities; - NMSettingWirelessWakeOnWLan wowlan_restore; - - NMDeviceWifiP2P *p2p_device; - NM80211Mode mode; - - guint32 failed_iface_count; - gint32 hw_addr_scan_expire; - - guint32 rate; - - guint8 scan_periodic_interval_sec; - - bool enabled : 1; /* rfkilled or not */ - bool scan_is_scanning : 1; - bool scan_periodic_allowed : 1; - bool scan_explicit_allowed : 1; - bool scan_explicit_requested : 1; - bool ssid_found : 1; - bool hidden_probe_scan_warn : 1; - -} NMDeviceWifiPrivate; - -struct _NMDeviceWifi { - NMDevice parent; - NMDeviceWifiPrivate _priv; -}; - -struct _NMDeviceWifiClass { - NMDeviceClass parent; -}; - -/*****************************************************************************/ - -G_DEFINE_TYPE(NMDeviceWifi, nm_device_wifi, NM_TYPE_DEVICE) - -#define NM_DEVICE_WIFI_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceWifi, NM_IS_DEVICE_WIFI, NMDevice) - -/*****************************************************************************/ - -static void supplicant_iface_state_down(NMDeviceWifi *self); - -static void cleanup_association_attempt(NMDeviceWifi *self, gboolean disconnect); - -static void supplicant_iface_state(NMDeviceWifi * self, - NMSupplicantInterfaceState new_state, - NMSupplicantInterfaceState old_state, - int disconnect_reason, - gboolean is_real_signal); - -static void supplicant_iface_state_cb(NMSupplicantInterface *iface, - int new_state_i, - int old_state_i, - int disconnect_reason, - gpointer user_data); - -static void supplicant_iface_bss_changed_cb(NMSupplicantInterface *iface, - NMSupplicantBssInfo * bss_info, - gboolean is_present, - NMDeviceWifi * self); - -static void supplicant_iface_wps_credentials_cb(NMSupplicantInterface *iface, - GVariant * credentials, - NMDeviceWifi * self); - -static void supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, - GParamSpec * pspec, - NMDeviceWifi * self); - -static void supplicant_iface_notify_p2p_available(NMSupplicantInterface *iface, - GParamSpec * pspec, - NMDeviceWifi * self); - -static void periodic_update(NMDeviceWifi *self); - -static void ap_add_remove(NMDeviceWifi *self, - gboolean is_adding, - NMWifiAP * ap, - gboolean recheck_available_connections); - -static void _hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset); - -static void recheck_p2p_availability(NMDeviceWifi *self); - -static void _scan_kickoff(NMDeviceWifi *self); - -static gboolean _scan_notify_allowed(NMDeviceWifi *self, NMTernary do_kickoff); - -/*****************************************************************************/ - -typedef struct { - GBytes *ssid; - CList lst; - gint64 timestamp_msec; -} ScanRequestSsidData; - -static void -_scan_request_ssids_remove(ScanRequestSsidData *srs_data) -{ - c_list_unlink_stale(&srs_data->lst); - g_bytes_unref(srs_data->ssid); - nm_g_slice_free(srs_data); -} - -static void -_scan_request_ssids_remove_with_hash(NMDeviceWifiPrivate *priv, ScanRequestSsidData *srs_data) -{ - nm_assert(srs_data); - nm_assert(nm_g_hash_table_lookup(priv->scan_request_ssids_hash, srs_data) == srs_data); - if (!g_hash_table_remove(priv->scan_request_ssids_hash, srs_data)) - nm_assert_not_reached(); - _scan_request_ssids_remove(srs_data); -} - -static void -_scan_request_ssids_remove_all(NMDeviceWifiPrivate *priv, - gint64 cutoff_with_now_msec, - guint cutoff_at_len) -{ - ScanRequestSsidData *srs_data; - - nm_assert((!priv->scan_request_ssids_hash) - == c_list_is_empty(&priv->scan_request_ssids_lst_head)); - if (!priv->scan_request_ssids_hash) - return; - - if (cutoff_at_len == 0) { - nm_clear_pointer(&priv->scan_request_ssids_hash, g_hash_table_destroy); - while ( - (srs_data = - c_list_first_entry(&priv->scan_request_ssids_lst_head, ScanRequestSsidData, lst))) - _scan_request_ssids_remove(srs_data); - return; - } - - if (cutoff_with_now_msec != 0) { - gint64 cutoff_time_msec; - - /* remove all entries that are older than a max-age. */ - nm_assert(cutoff_with_now_msec > 0); - cutoff_time_msec = cutoff_with_now_msec - SCAN_REQUEST_SSIDS_MAX_AGE_MSEC; - while ( - (srs_data = - c_list_last_entry(&priv->scan_request_ssids_lst_head, ScanRequestSsidData, lst))) { - if (srs_data->timestamp_msec > cutoff_time_msec) - break; - _scan_request_ssids_remove_with_hash(priv, srs_data); - } - } - - if (cutoff_at_len != G_MAXUINT) { - guint i; - - /* trim the list to cutoff_at_len elements. */ - i = nm_g_hash_table_size(priv->scan_request_ssids_hash); - for (; i > cutoff_at_len; i--) { - ScanRequestSsidData *d; - - d = c_list_last_entry(&priv->scan_request_ssids_lst_head, ScanRequestSsidData, lst); - _scan_request_ssids_remove_with_hash(priv, d); - } - } - - nm_assert(nm_g_hash_table_size(priv->scan_request_ssids_hash) <= SCAN_REQUEST_SSIDS_MAX_NUM); - nm_assert(nm_g_hash_table_size(priv->scan_request_ssids_hash) - == c_list_length(&priv->scan_request_ssids_lst_head)); - if (c_list_is_empty(&priv->scan_request_ssids_lst_head)) - nm_clear_pointer(&priv->scan_request_ssids_hash, g_hash_table_destroy); -} - -static GPtrArray * -_scan_request_ssids_fetch(NMDeviceWifiPrivate *priv, gint64 now_msec) -{ - ScanRequestSsidData *srs_data; - GPtrArray * ssids; - guint len; - - _scan_request_ssids_remove_all(priv, now_msec, G_MAXUINT); - - len = nm_g_hash_table_size(priv->scan_request_ssids_hash); - if (len == 0) - return NULL; - - ssids = g_ptr_array_new_full(len, (GDestroyNotify) g_bytes_unref); - nm_clear_pointer(&priv->scan_request_ssids_hash, g_hash_table_destroy); - while ((srs_data = - c_list_first_entry(&priv->scan_request_ssids_lst_head, ScanRequestSsidData, lst))) { - g_ptr_array_add(ssids, g_steal_pointer(&srs_data->ssid)); - _scan_request_ssids_remove(srs_data); - } - return ssids; -} - -static void -_scan_request_ssids_track(NMDeviceWifiPrivate *priv, const GPtrArray *ssids) -{ - CList old_lst_head; - gint64 now_msec; - guint i; - - if (!ssids || ssids->len == 0) - return; - - now_msec = nm_utils_get_monotonic_timestamp_msec(); - - if (!priv->scan_request_ssids_hash) - priv->scan_request_ssids_hash = g_hash_table_new(nm_pgbytes_hash, nm_pgbytes_equal); - - /* Do a little dance. New elements shall keep their order as in @ssids, but all - * new elements should be sorted in the list preexisting elements of the list. - * First move the old elements away, and splice them back afterwards. */ - c_list_init(&old_lst_head); - c_list_splice(&old_lst_head, &priv->scan_request_ssids_lst_head); - - for (i = 0; i < ssids->len; i++) { - GBytes * ssid = ssids->pdata[i]; - ScanRequestSsidData *d; - - G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(ScanRequestSsidData, ssid) == 0); - d = g_hash_table_lookup(priv->scan_request_ssids_hash, &ssid); - if (!d) { - d = g_slice_new(ScanRequestSsidData); - *d = (ScanRequestSsidData){ - .lst = C_LIST_INIT(d->lst), - .timestamp_msec = now_msec, - .ssid = g_bytes_ref(ssid), - }; - g_hash_table_add(priv->scan_request_ssids_hash, d); - } else - d->timestamp_msec = now_msec; - c_list_link_tail(&priv->scan_request_ssids_lst_head, &d->lst); - } - - c_list_splice(&priv->scan_request_ssids_lst_head, &old_lst_head); - - /* Trim the excess. After our splice with old_lst_head, the list contains the new - * elements (from @ssids) at the front (in there original order), followed by older elements. */ - _scan_request_ssids_remove_all(priv, now_msec, SCAN_REQUEST_SSIDS_MAX_NUM); -} - -/*****************************************************************************/ - -void -nm_device_wifi_scanning_prohibited_track(NMDeviceWifi *self, - gpointer tag, - gboolean temporarily_prohibited) -{ - NMDeviceWifiPrivate *priv; - NMCListElem * elem; - - g_return_if_fail(NM_IS_DEVICE_WIFI(self)); - nm_assert(tag); - - priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - /* We track these with a simple CList. This would be not efficient, if - * there would be many users that need to be tracked at the same time (there - * aren't). In fact, most of the time there is no NMDeviceOlpcMesh and - * nobody tracks itself here. Optimize for that and simplicity. */ - - elem = nm_c_list_elem_find_first(&priv->scanning_prohibited_lst_head, iter, iter == tag); - - if (!temporarily_prohibited) { - if (!elem) - return; - nm_c_list_elem_free(elem); - } else { - if (elem) - return; - c_list_link_tail(&priv->scanning_prohibited_lst_head, &nm_c_list_elem_new_stale(tag)->lst); - } - - _scan_notify_allowed(self, NM_TERNARY_DEFAULT); -} - -/*****************************************************************************/ - -static void -_ap_dump(NMDeviceWifi * self, - NMLogLevel log_level, - const NMWifiAP *ap, - const char * prefix, - gint64 now_msec) -{ - char buf[1024]; - - buf[0] = '\0'; - _NMLOG(log_level, - LOGD_WIFI_SCAN, - "wifi-ap: %-7s %s", - prefix, - nm_wifi_ap_to_string(ap, buf, sizeof(buf), now_msec)); -} - -gboolean -nm_device_wifi_get_scanning(NMDeviceWifi *self) -{ - g_return_val_if_fail(NM_IS_DEVICE_WIFI(self), FALSE); - - return NM_DEVICE_WIFI_GET_PRIVATE(self)->scan_is_scanning; -} - -static gboolean -_scan_is_scanning_eval(NMDeviceWifiPrivate *priv) -{ - return priv->scan_request_cancellable || priv->scan_request_delay_source - || (priv->sup_iface && nm_supplicant_interface_get_scanning(priv->sup_iface)); -} - -static gboolean -_scan_notify_is_scanning(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - gboolean last_scan_changed = FALSE; - NMDeviceState state; - gboolean scanning; - - scanning = _scan_is_scanning_eval(priv); - if (scanning == priv->scan_is_scanning) - return FALSE; - - priv->scan_is_scanning = scanning; - - if (!scanning || priv->scan_last_complete_msec == 0) { - last_scan_changed = TRUE; - priv->scan_last_complete_msec = nm_utils_get_monotonic_timestamp_msec(); - } - - _LOGD(LOGD_WIFI, - "wifi-scan: scanning-state: %s%s", - scanning ? "scanning" : "idle", - last_scan_changed ? " (notify last-scan)" : ""); - - state = nm_device_get_state(NM_DEVICE(self)); - - if (scanning) { - /* while the device is activating/activated, we don't need the pending - * action. The pending action exists to delay startup complete, while - * activating that is already achieved via other means. */ - if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_ACTIVATED) - nm_device_add_pending_action(NM_DEVICE(self), NM_PENDING_ACTION_WIFI_SCAN, FALSE); - } - - nm_gobject_notify_together(self, PROP_SCANNING, last_scan_changed ? PROP_LAST_SCAN : PROP_0); - - _scan_kickoff(self); - - if (!_scan_is_scanning_eval(priv)) { - if (state <= NM_DEVICE_STATE_DISCONNECTED || state > NM_DEVICE_STATE_ACTIVATED) - nm_device_emit_recheck_auto_activate(NM_DEVICE(self)); - nm_device_remove_pending_action(NM_DEVICE(self), NM_PENDING_ACTION_WIFI_SCAN, FALSE); - } - - return TRUE; -} - -static gboolean -_scan_notify_allowed(NMDeviceWifi *self, NMTernary do_kickoff) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - gboolean explicit_allowed; - gboolean periodic_allowed; - NMDeviceState state; - gboolean changed = FALSE; - - state = nm_device_get_state(NM_DEVICE(self)); - - explicit_allowed = FALSE; - periodic_allowed = FALSE; - - if (!c_list_is_empty(&priv->scanning_prohibited_lst_head)) { - /* something prohibits scanning. */ - } else if (NM_IN_SET(priv->mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_AP)) { - /* Don't scan when a an AP or Ad-Hoc connection is active as it will - * disrupt connected clients or peers. */ - } else if (NM_IN_SET(state, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_FAILED)) { - /* Can always scan when disconnected */ - explicit_allowed = TRUE; - periodic_allowed = TRUE; - } else if (NM_IN_SET(state, NM_DEVICE_STATE_ACTIVATED)) { - /* Prohibit periodic scans when connected; we ask the supplicant to - * background scan for us, unless the connection is locked to a specific - * BSSID (in which case scanning is effectively disabled). */ - periodic_allowed = FALSE; - - /* Prohibit scans if the supplicant is busy */ - if (priv->sup_iface) { - explicit_allowed = !NM_IN_SET(nm_supplicant_interface_get_state(priv->sup_iface), - NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING, - NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED, - NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, - NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE); - } else - explicit_allowed = FALSE; - } - - if (explicit_allowed != priv->scan_explicit_allowed - || periodic_allowed != priv->scan_periodic_allowed) { - priv->scan_periodic_allowed = periodic_allowed; - priv->scan_explicit_allowed = explicit_allowed; - _LOGT_scan("scan-periodic-allowed=%d, scan-explicit-allowed=%d", - periodic_allowed, - explicit_allowed); - changed = TRUE; - } - - if (do_kickoff == NM_TERNARY_TRUE || (do_kickoff == NM_TERNARY_DEFAULT && changed)) - _scan_kickoff(self); - - return changed; -} - -static void -supplicant_iface_notify_scanning_cb(NMSupplicantInterface *iface, - GParamSpec * pspec, - NMDeviceWifi * self) -{ - _scan_notify_is_scanning(self); -} - -static gboolean -unmanaged_on_quit(NMDevice *self) -{ - /* Wi-Fi devices cannot be assumed and are always taken down. - * However, also when being disconnected, we scan and thus - * set the MAC address to a random value. - * - * We must restore the original MAC address when quitting, thus - * signal to unmanage the device. */ - return TRUE; -} - -static void -supplicant_interface_acquire_cb(NMSupplicantManager * supplicant_manager, - NMSupplMgrCreateIfaceHandle *handle, - NMSupplicantInterface * iface, - GError * error, - gpointer user_data) -{ - NMDeviceWifi * self = user_data; - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - if (nm_utils_error_is_cancelled(error)) - return; - - nm_assert(priv->sup_create_handle == handle); - - priv->sup_create_handle = NULL; - - if (error) { - _LOGE(LOGD_WIFI, "Couldn't initialize supplicant interface: %s", error->message); - supplicant_iface_state_down(self); - nm_device_remove_pending_action(NM_DEVICE(self), - NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, - TRUE); - return; - } - - priv->sup_iface = g_object_ref(iface); - - g_signal_connect(priv->sup_iface, - NM_SUPPLICANT_INTERFACE_STATE, - G_CALLBACK(supplicant_iface_state_cb), - self); - g_signal_connect(priv->sup_iface, - NM_SUPPLICANT_INTERFACE_BSS_CHANGED, - G_CALLBACK(supplicant_iface_bss_changed_cb), - self); - g_signal_connect(priv->sup_iface, - NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS, - G_CALLBACK(supplicant_iface_wps_credentials_cb), - self); - g_signal_connect(priv->sup_iface, - "notify::" NM_SUPPLICANT_INTERFACE_SCANNING, - G_CALLBACK(supplicant_iface_notify_scanning_cb), - self); - g_signal_connect(priv->sup_iface, - "notify::" NM_SUPPLICANT_INTERFACE_CURRENT_BSS, - G_CALLBACK(supplicant_iface_notify_current_bss), - self); - g_signal_connect(priv->sup_iface, - "notify::" NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE, - G_CALLBACK(supplicant_iface_notify_p2p_available), - self); - - _scan_notify_is_scanning(self); - - if (nm_supplicant_interface_get_state(priv->sup_iface) - != NM_SUPPLICANT_INTERFACE_STATE_STARTING) { - /* fake an initial state change. */ - supplicant_iface_state(user_data, - NM_SUPPLICANT_INTERFACE_STATE_STARTING, - nm_supplicant_interface_get_state(priv->sup_iface), - 0, - FALSE); - } -} - -static void -supplicant_interface_acquire(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - nm_assert(!priv->sup_iface); - nm_assert(!priv->sup_create_handle); - - priv->sup_create_handle = - nm_supplicant_manager_create_interface(priv->sup_mgr, - nm_device_get_ifindex(NM_DEVICE(self)), - NM_SUPPLICANT_DRIVER_WIRELESS, - supplicant_interface_acquire_cb, - self); - nm_device_add_pending_action(NM_DEVICE(self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); -} - -static void -supplicant_interface_release(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - if (nm_clear_pointer(&priv->sup_create_handle, nm_supplicant_manager_create_interface_cancel)) - nm_device_remove_pending_action(NM_DEVICE(self), - NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, - TRUE); - - nm_clear_g_source(&priv->scan_kickoff_timeout_id); - nm_clear_g_source_inst(&priv->scan_request_delay_source); - nm_clear_g_cancellable(&priv->scan_request_cancellable); - - _scan_request_ssids_remove_all(priv, 0, 0); - - priv->scan_periodic_interval_sec = 0; - priv->scan_periodic_next_msec = 0; - - nm_clear_g_source(&priv->ap_dump_id); - - if (priv->sup_iface) { - /* Clear supplicant interface signal handlers */ - g_signal_handlers_disconnect_by_data(priv->sup_iface, self); - - /* Tell the supplicant to disconnect from the current AP */ - nm_supplicant_interface_disconnect(priv->sup_iface); - - g_clear_object(&priv->sup_iface); - } - - if (priv->p2p_device) { - /* Signal to P2P device to also release its reference */ - nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, NULL); - } - - _scan_notify_is_scanning(self); -} - -static void -update_seen_bssids_cache(NMDeviceWifi *self, NMWifiAP *ap) -{ - g_return_if_fail(NM_IS_DEVICE_WIFI(self)); - - if (ap == NULL) - return; - - /* Don't cache the BSSID for Ad-Hoc APs */ - if (nm_wifi_ap_get_mode(ap) != NM_802_11_MODE_INFRA) - return; - - if (nm_device_get_state(NM_DEVICE(self)) == NM_DEVICE_STATE_ACTIVATED - && nm_device_has_unmodified_applied_connection(NM_DEVICE(self), - NM_SETTING_COMPARE_FLAG_NONE)) { - nm_settings_connection_add_seen_bssid(nm_device_get_settings_connection(NM_DEVICE(self)), - nm_wifi_ap_get_address(ap)); - } -} - -static void -set_current_ap(NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available_connections) -{ - NMDeviceWifiPrivate *priv; - NMWifiAP * old_ap; - - g_return_if_fail(NM_IS_DEVICE_WIFI(self)); - - priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - old_ap = priv->current_ap; - - if (old_ap == new_ap) - return; - - if (new_ap) { - priv->current_ap = g_object_ref(new_ap); - - /* Update seen BSSIDs cache */ - update_seen_bssids_cache(self, priv->current_ap); - } else - priv->current_ap = NULL; - - if (old_ap) { - NM80211Mode mode = nm_wifi_ap_get_mode(old_ap); - - /* Remove any AP from the internal list if it was created by NM or isn't known to the supplicant */ - if (NM_IN_SET(mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_AP) || nm_wifi_ap_get_fake(old_ap)) - ap_add_remove(self, FALSE, old_ap, recheck_available_connections); - g_object_unref(old_ap); - } - - _notify(self, PROP_ACTIVE_ACCESS_POINT); -} - -static void -periodic_update(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv; - int ifindex; - guint32 new_rate; - - if (nm_device_get_state(NM_DEVICE(self)) != NM_DEVICE_STATE_ACTIVATED) { - /* BSSID and signal strength have meaningful values only if the device - * is activated and not scanning. - */ - return; - } - - priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - if (!nm_supplicant_interface_state_is_associated( - nm_supplicant_interface_get_state(priv->sup_iface)) - || nm_supplicant_interface_get_scanning(priv->sup_iface)) { - /* Only update current AP if we're actually talking to something, otherwise - * assume the old one (if any) is still valid until we're told otherwise or - * the connection fails. - */ - return; - } - - if (priv->mode == NM_802_11_MODE_AP) { - /* In AP mode we currently have nothing to do. */ - return; - } - - ifindex = nm_device_get_ifindex(NM_DEVICE(self)); - if (ifindex <= 0) - g_return_if_reached(); - - if (priv->current_ap) { - int percent; - - percent = nm_platform_wifi_get_quality(nm_device_get_platform(NM_DEVICE(self)), ifindex); - if (percent >= 0 && percent <= 100) { - if (nm_wifi_ap_set_strength(priv->current_ap, (gint8) percent)) { -#if NM_MORE_LOGGING - _ap_dump(self, LOGL_TRACE, priv->current_ap, "updated", 0); -#endif - } - } - } - - new_rate = nm_platform_wifi_get_rate(nm_device_get_platform(NM_DEVICE(self)), ifindex); - if (new_rate != priv->rate) { - priv->rate = new_rate; - _notify(self, PROP_BITRATE); - } -} - -static gboolean -periodic_update_cb(gpointer user_data) -{ - periodic_update(user_data); - return TRUE; -} - -static void -ap_add_remove(NMDeviceWifi *self, - gboolean is_adding, /* or else removing */ - NMWifiAP * ap, - gboolean recheck_available_connections) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - if (is_adding) { - g_object_ref(ap); - ap->wifi_device = NM_DEVICE(self); - c_list_link_tail(&priv->aps_lst_head, &ap->aps_lst); - if (!g_hash_table_insert(priv->aps_idx_by_supplicant_path, - nm_wifi_ap_get_supplicant_path(ap), - ap)) - nm_assert_not_reached(); - nm_dbus_object_export(NM_DBUS_OBJECT(ap)); - _ap_dump(self, LOGL_DEBUG, ap, "added", 0); - nm_device_wifi_emit_signal_access_point(NM_DEVICE(self), ap, TRUE); - } else { - ap->wifi_device = NULL; - c_list_unlink(&ap->aps_lst); - if (!g_hash_table_remove(priv->aps_idx_by_supplicant_path, - nm_wifi_ap_get_supplicant_path(ap))) - nm_assert_not_reached(); - _ap_dump(self, LOGL_DEBUG, ap, "removed", 0); - } - - _notify(self, PROP_ACCESS_POINTS); - - if (!is_adding) { - nm_device_wifi_emit_signal_access_point(NM_DEVICE(self), ap, FALSE); - nm_dbus_object_clear_and_unexport(&ap); - } - - nm_device_emit_recheck_auto_activate(NM_DEVICE(self)); - if (recheck_available_connections) - nm_device_recheck_available_connections(NM_DEVICE(self)); -} - -static void -remove_all_aps(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMWifiAP * ap; - - if (c_list_is_empty(&priv->aps_lst_head)) - return; - - set_current_ap(self, NULL, FALSE); - - while ((ap = c_list_first_entry(&priv->aps_lst_head, NMWifiAP, aps_lst))) - ap_add_remove(self, FALSE, ap, FALSE); - - nm_device_recheck_available_connections(NM_DEVICE(self)); -} - -static gboolean -wake_on_wlan_restore(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWirelessWakeOnWLan w; - - w = priv->wowlan_restore; - if (w == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) - return TRUE; - - priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; - return nm_platform_wifi_set_wake_on_wlan(NM_PLATFORM_GET, - nm_device_get_ifindex(NM_DEVICE(self)), - w); -} - -static void -disconnect_cb(NMSupplicantInterface *iface, GError *error, gpointer user_data) -{ - gs_unref_object NMDeviceWifi *self = NULL; - NMDeviceDeactivateCallback callback; - gpointer callback_user_data; - - nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data); - - /* error will be freed by sup_iface */ - callback(NM_DEVICE(self), error, callback_user_data); -} - -static void -disconnect_cb_on_idle(gpointer user_data, GCancellable *cancellable) -{ - gs_unref_object NMDeviceWifi *self = NULL; - NMDeviceDeactivateCallback callback; - gpointer callback_user_data; - gs_free_error GError *cancelled_error = NULL; - - nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data); - - g_cancellable_set_error_if_cancelled(cancellable, &cancelled_error); - callback(NM_DEVICE(self), cancelled_error, callback_user_data); -} - -static void -deactivate_async(NMDevice * device, - GCancellable * cancellable, - NMDeviceDeactivateCallback callback, - gpointer callback_user_data) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - gpointer user_data; - - nm_assert(G_IS_CANCELLABLE(cancellable)); - nm_assert(callback); - - user_data = nm_utils_user_data_pack(g_object_ref(self), callback, callback_user_data); - if (!priv->sup_iface) { - nm_utils_invoke_on_idle(cancellable, disconnect_cb_on_idle, user_data); - return; - } - - cleanup_association_attempt(self, FALSE); - - nm_supplicant_interface_disconnect_async(priv->sup_iface, - cancellable, - disconnect_cb, - user_data); -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - int ifindex = nm_device_get_ifindex(device); - - nm_clear_g_source(&priv->periodic_update_id); - - cleanup_association_attempt(self, TRUE); - - priv->rate = 0; - - set_current_ap(self, NULL, TRUE); - - if (!wake_on_wlan_restore(self)) - _LOGW(LOGD_DEVICE | LOGD_WIFI, "Cannot unconfigure WoWLAN."); - - /* Clear any critical protocol notification in the Wi-Fi stack */ - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), ifindex, FALSE); - - /* Ensure we're in infrastructure mode after deactivation; some devices - * (usually older ones) don't scan well in adhoc mode. - */ - if (nm_platform_wifi_get_mode(nm_device_get_platform(device), ifindex) - != NM_802_11_MODE_INFRA) { - nm_device_take_down(NM_DEVICE(self), TRUE); - nm_platform_wifi_set_mode(nm_device_get_platform(device), ifindex, NM_802_11_MODE_INFRA); - nm_device_bring_up(NM_DEVICE(self), TRUE, NULL); - } - - if (priv->mode != NM_802_11_MODE_INFRA) { - priv->mode = NM_802_11_MODE_INFRA; - _notify(self, PROP_MODE); - } - - _scan_notify_allowed(self, NM_TERNARY_TRUE); -} - -static void -deactivate_reset_hw_addr(NMDevice *device) -{ - _hw_addr_set_scanning((NMDeviceWifi *) device, TRUE); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWireless * s_wireless; - const char * mac; - const char *const * mac_blacklist; - int i; - const char * mode; - const char * perm_hw_addr; - - if (!NM_DEVICE_CLASS(nm_device_wifi_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - s_wireless = nm_connection_get_setting_wireless(connection); - - perm_hw_addr = nm_device_get_permanent_hw_address(device); - mac = nm_setting_wireless_get_mac_address(s_wireless); - if (perm_hw_addr) { - if (mac && !nm_utils_hwaddr_matches(mac, -1, perm_hw_addr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device MAC address does not match the profile"); - return FALSE; - } - - /* Check for MAC address blacklist */ - mac_blacklist = nm_setting_wireless_get_mac_address_blacklist(s_wireless); - for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid(mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached(); - return FALSE; - } - - if (nm_utils_hwaddr_matches(mac_blacklist[i], -1, perm_hw_addr, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "MAC address blacklisted"); - return FALSE; - } - } - } else if (mac) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has no valid MAC address as required by profile"); - return FALSE; - } - - /* Early exit if supplicant or device doesn't support requested mode */ - mode = nm_setting_wireless_get_mode(s_wireless); - if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_ADHOC)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the device does not support Ad-Hoc networks"); - return FALSE; - } - } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_AP) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_AP)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the device does not support Access Point mode"); - return FALSE; - } - - if (priv->sup_iface) { - if (nm_supplicant_interface_get_capability(priv->sup_iface, NM_SUPPL_CAP_TYPE_AP) - == NM_TERNARY_FALSE) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "wpa_supplicant does not support Access Point mode"); - return FALSE; - } - } - } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) { - if (!(priv->capabilities & NM_WIFI_DEVICE_CAP_MESH)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the device does not support Mesh mode"); - return FALSE; - } - - if (priv->sup_iface) { - if (nm_supplicant_interface_get_capability(priv->sup_iface, NM_SUPPL_CAP_TYPE_MESH) - == NM_TERNARY_FALSE) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "wpa_supplicant does not support Mesh mode"); - return FALSE; - } - } - } - - // FIXME: check channel/freq/band against bands the hardware supports - // FIXME: check encryption against device capabilities - // FIXME: check bitrate against device capabilities - - return TRUE; -} - -static gboolean -check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWireless * s_wifi; - const char * mode; - - s_wifi = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wifi, FALSE); - - /* a connection that is available for a certain @specific_object, MUST - * also be available in general (without @specific_object). */ - - if (specific_object) { - NMWifiAP *ap; - - ap = nm_wifi_ap_lookup_for_device(NM_DEVICE(self), specific_object); - if (!ap) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "requested access point not found"); - return FALSE; - } - if (!nm_wifi_ap_check_compatible(ap, connection)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "requested access point is not compatible with profile"); - return FALSE; - } - return TRUE; - } - - /* Ad-Hoc, AP and Mesh connections are always available because they may be - * started at any time. - */ - mode = nm_setting_wireless_get_mode(s_wifi); - if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0 - || g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_AP) == 0 - || g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) - return TRUE; - - /* Hidden SSIDs obviously don't always appear in the scan list either. - * - * For an explicit user-activation-request, a connection is considered - * available because for hidden Wi-Fi, clients didn't consistently - * set the 'hidden' property to indicate hidden SSID networks. If - * activating but the network isn't available let the device recheck - * availability. - */ - if (nm_setting_wireless_get_hidden(s_wifi) - || NM_FLAGS_HAS(flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) - return TRUE; - - if (!nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "no compatible access point found"); - return FALSE; - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWireless * s_wifi; - gs_free char * ssid_utf8 = NULL; - NMWifiAP * ap; - GBytes * ssid = NULL; - GBytes * setting_ssid = NULL; - gboolean hidden = FALSE; - const char * mode; - - s_wifi = nm_connection_get_setting_wireless(connection); - - mode = s_wifi ? nm_setting_wireless_get_mode(s_wifi) : NULL; - - if (!specific_object) { - /* If not given a specific object, we need at minimum an SSID */ - if (!s_wifi) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wireless' setting is required if no AP path was given."); - return FALSE; - } - - setting_ssid = nm_setting_wireless_get_ssid(s_wifi); - if (!setting_ssid || g_bytes_get_size(setting_ssid) == 0) { - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wireless' setting with a valid SSID is required if no AP path was given."); - return FALSE; - } - - if (!nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP)) { - /* Find a compatible AP in the scan list */ - ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection); - - /* If we still don't have an AP, then the WiFI settings needs to be - * fully specified by the client. Might not be able to find an AP - * if the network isn't broadcasting the SSID for example. - */ - if (!ap) { - if (!nm_setting_verify(NM_SETTING(s_wifi), connection, error)) - return FALSE; - - hidden = TRUE; - } - } else { - if (!nm_setting_verify(NM_SETTING(s_wifi), connection, error)) - return FALSE; - ap = NULL; - } - } else if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP)) { - if (!nm_setting_verify(NM_SETTING(s_wifi), connection, error)) - return FALSE; - ap = NULL; - } else { - ap = nm_wifi_ap_lookup_for_device(NM_DEVICE(self), specific_object); - if (!ap) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND, - "The access point %s was not in the scan list.", - specific_object); - return FALSE; - } - } - - /* Add a wifi setting if one doesn't exist yet */ - if (!s_wifi) { - s_wifi = (NMSettingWireless *) nm_setting_wireless_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wifi)); - } - - if (ap) - ssid = nm_wifi_ap_get_ssid(ap); - - if (ssid == NULL) { - /* The AP must be hidden. Connecting to a Wi-Fi AP requires the SSID - * as part of the initial handshake, so check the connection details - * for the SSID. The AP object will still be used for encryption - * settings and such. - */ - ssid = nm_setting_wireless_get_ssid(s_wifi); - } - - if (ssid == NULL) { - /* If there's no SSID on the AP itself, and no SSID in the - * connection data, then we cannot connect at all. Return an error. - */ - g_set_error_literal( - error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - ap ? "A 'wireless' setting with a valid SSID is required for hidden access points." - : "Cannot create 'wireless' setting due to missing SSID."); - return FALSE; - } - - if (ap) { - /* If the SSID is a well-known SSID, lock the connection to the AP's - * specific BSSID so NM doesn't autoconnect to some random wifi net. - */ - if (!nm_wifi_ap_complete_connection(ap, - connection, - nm_wifi_utils_is_manf_default_ssid(ssid), - error)) - return FALSE; - } - - ssid_utf8 = _nm_utils_ssid_to_utf8(ssid); - nm_utils_complete_generic( - nm_device_get_platform(device), - connection, - NM_SETTING_WIRELESS_SETTING_NAME, - existing_connections, - ssid_utf8, - ssid_utf8, - NULL, - nm_setting_wireless_get_mac_address(s_wifi) ? NULL : nm_device_get_iface(device), - TRUE); - - if (hidden) - g_object_set(s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); - - return TRUE; -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSupplicantInterfaceState supplicant_state; - - if (!priv->enabled) - return FALSE; - - if (!priv->sup_iface) - return FALSE; - - supplicant_state = nm_supplicant_interface_get_state(priv->sup_iface); - if (supplicant_state <= NM_SUPPLICANT_INTERFACE_STATE_STARTING - || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) - return FALSE; - - return TRUE; -} - -static gboolean -get_autoconnect_allowed(NMDevice *device) -{ - return !NM_DEVICE_WIFI_GET_PRIVATE(NM_DEVICE_WIFI(device))->scan_is_scanning; -} - -static gboolean -can_auto_connect(NMDevice *device, NMSettingsConnection *sett_conn, char **specific_object) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMConnection * connection; - NMSettingWireless * s_wifi; - NMWifiAP * ap; - const char * method6, *mode; - gboolean auto4, auto6; - - nm_assert(!specific_object || !*specific_object); - - if (!NM_DEVICE_CLASS(nm_device_wifi_parent_class)->can_auto_connect(device, sett_conn, NULL)) - return FALSE; - - connection = nm_settings_connection_get_connection(sett_conn); - - s_wifi = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wifi, FALSE); - - /* Always allow autoconnect for AP and non-autoconf Ad-Hoc or Mesh */ - auto4 = nm_streq0(nm_utils_get_ip_config_method(connection, AF_INET), - NM_SETTING_IP4_CONFIG_METHOD_AUTO); - method6 = nm_utils_get_ip_config_method(connection, AF_INET6); - auto6 = nm_streq0(method6, NM_SETTING_IP6_CONFIG_METHOD_AUTO) - || nm_streq0(method6, NM_SETTING_IP6_CONFIG_METHOD_DHCP); - - mode = nm_setting_wireless_get_mode(s_wifi); - - if (nm_streq0(mode, NM_SETTING_WIRELESS_MODE_AP)) - return TRUE; - else if (!auto4 && nm_streq0(mode, NM_SETTING_WIRELESS_MODE_ADHOC)) - return TRUE; - else if (!auto4 && !auto6 && nm_streq0(mode, NM_SETTING_WIRELESS_MODE_MESH)) - return TRUE; - - ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection); - if (ap) { - /* All good; connection is usable */ - NM_SET_OUT(specific_object, g_strdup(nm_dbus_object_get_path(NM_DBUS_OBJECT(ap)))); - return TRUE; - } - - return FALSE; -} - -const CList * -_nm_device_wifi_get_aps(NMDeviceWifi *self) -{ - return &NM_DEVICE_WIFI_GET_PRIVATE(self)->aps_lst_head; -} - -static void -_hw_addr_set_scanning(NMDeviceWifi *self, gboolean do_reset) -{ - NMDevice * device = (NMDevice *) self; - NMDeviceWifiPrivate *priv; - guint32 now; - gboolean randomize; - - g_return_if_fail(NM_IS_DEVICE_WIFI(self)); - - if (nm_device_is_activating(device) || nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) - return; - - priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - randomize = nm_config_data_get_device_config_boolean( - NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_RAND_MAC_ADDRESS, - device, - TRUE, - TRUE); - - if (!randomize) { - /* expire the temporary MAC address used during scanning */ - priv->hw_addr_scan_expire = 0; - - if (do_reset) { - priv->scan_last_request_started_at_msec = G_MININT64; - priv->scan_periodic_next_msec = 0; - priv->scan_periodic_interval_sec = 0; - nm_device_hw_addr_reset(device, "scanning"); - } - return; - } - - now = nm_utils_get_monotonic_timestamp_sec(); - - if (now >= priv->hw_addr_scan_expire) { - gs_free char *generate_mac_address_mask = NULL; - gs_free char *hw_addr_scan = NULL; - - /* the random MAC address for scanning expires after a while. - * - * We don't bother with to update the MAC address exactly when - * it expires, instead on the next scan request, we will generate - * a new one.*/ - priv->hw_addr_scan_expire = now + SCAN_RAND_MAC_ADDRESS_EXPIRE_SEC; - - generate_mac_address_mask = nm_config_data_get_device_config( - NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_SCAN_GENERATE_MAC_ADDRESS_MASK, - device, - NULL); - - priv->scan_last_request_started_at_msec = G_MININT64; - priv->scan_periodic_next_msec = 0; - priv->scan_periodic_interval_sec = 0; - hw_addr_scan = nm_utils_hw_addr_gen_random_eth(nm_device_get_initial_hw_address(device), - generate_mac_address_mask); - nm_device_hw_addr_set(device, hw_addr_scan, "scanning", TRUE); - } -} - -static GPtrArray * -ssids_options_to_ptrarray(GVariant *value, GError **error) -{ - gs_unref_ptrarray GPtrArray *ssids = NULL; - gsize num_ssids; - gsize i; - - nm_assert(g_variant_is_of_type(value, G_VARIANT_TYPE("aay"))); - - num_ssids = g_variant_n_children(value); - if (num_ssids > 32) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_ARGUMENT, - "too many SSIDs requested to scan"); - return NULL; - } - - if (num_ssids) { - ssids = g_ptr_array_new_full(num_ssids, (GDestroyNotify) g_bytes_unref); - for (i = 0; i < num_ssids; i++) { - gs_unref_variant GVariant *v = NULL; - gsize len; - const guint8 * bytes; - - v = g_variant_get_child_value(value, i); - bytes = g_variant_get_fixed_array(v, &len, sizeof(guint8)); - if (len > 32) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_ARGUMENT, - "SSID at index %d more than 32 bytes", - (int) i); - return NULL; - } - - g_ptr_array_add(ssids, g_bytes_new(bytes, len)); - } - } - - return g_steal_pointer(&ssids); -} - -GPtrArray * -nmtst_ssids_options_to_ptrarray(GVariant *value, GError **error) -{ - return ssids_options_to_ptrarray(value, error); -} - -static void -dbus_request_scan_cb(NMDevice * device, - GDBusMethodInvocation *context, - NMAuthSubject * subject, - GError * error, - gpointer user_data) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - gs_unref_ptrarray GPtrArray *ssids = user_data; - - if (error) { - g_dbus_method_invocation_return_gerror(context, error); - return; - } - - _scan_request_ssids_track(priv, ssids); - priv->scan_explicit_requested = TRUE; - _scan_kickoff(self); - g_dbus_method_invocation_return_value(context, NULL); -} - -void -_nm_device_wifi_request_scan(NMDeviceWifi * self, - GVariant * options, - GDBusMethodInvocation *invocation) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - gs_unref_ptrarray GPtrArray *ssids = NULL; - - if (options) { - gs_unref_variant GVariant *val = g_variant_lookup_value(options, "ssids", NULL); - - if (val) { - gs_free_error GError *ssid_error = NULL; - - if (!g_variant_is_of_type(val, G_VARIANT_TYPE("aay"))) { - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_ARGUMENT, - "Invalid 'ssid' scan option"); - return; - } - - ssids = ssids_options_to_ptrarray(val, &ssid_error); - if (ssid_error) { - g_dbus_method_invocation_return_gerror(invocation, ssid_error); - return; - } - } - } - - if (!priv->enabled || !priv->sup_iface - || nm_device_get_state(device) < NM_DEVICE_STATE_DISCONNECTED) { - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed while unavailable"); - return; - } - - nm_device_auth_request(device, - invocation, - NULL, - NM_AUTH_PERMISSION_WIFI_SCAN, - TRUE, - NULL, - dbus_request_scan_cb, - g_steal_pointer(&ssids)); -} - -static gboolean -hidden_filter_func(NMSettings *settings, NMSettingsConnection *set_con, gpointer user_data) -{ - NMConnection * connection = nm_settings_connection_get_connection(set_con); - NMSettingWireless *s_wifi; - - if (!nm_connection_is_type(connection, NM_SETTING_WIRELESS_SETTING_NAME)) - return FALSE; - s_wifi = nm_connection_get_setting_wireless(connection); - if (!s_wifi) - return FALSE; - if (nm_streq0(nm_setting_wireless_get_mode(s_wifi), NM_SETTING_WIRELESS_MODE_AP)) - return FALSE; - return nm_setting_wireless_get_hidden(s_wifi); -} - -static GPtrArray * -_scan_request_ssids_build_hidden(NMDeviceWifi *self, - gint64 now_msec, - gboolean * out_has_hidden_profiles) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - guint max_scan_ssids = nm_supplicant_interface_get_max_scan_ssids(priv->sup_iface); - gs_free NMSettingsConnection **connections = NULL; - gs_unref_ptrarray GPtrArray *ssids = NULL; - gs_unref_hashtable GHashTable *unique_ssids = NULL; - guint connections_len; - guint n_hidden; - guint i; - - NM_SET_OUT(out_has_hidden_profiles, FALSE); - - /* collect all pending explicit SSIDs. */ - ssids = _scan_request_ssids_fetch(priv, now_msec); - - if (max_scan_ssids == 0) { - /* no space. @ssids will be ignored. */ - return NULL; - } - - if (ssids) { - if (ssids->len < max_scan_ssids) { - /* Add wildcard SSID using a static wildcard SSID used for every scan */ - g_ptr_array_insert(ssids, 0, g_bytes_ref(nm_gbytes_get_empty())); - } - if (ssids->len >= max_scan_ssids) { - /* there is no more space. Use what we have. */ - g_ptr_array_set_size(ssids, max_scan_ssids); - return g_steal_pointer(&ssids); - } - } - - connections = nm_settings_get_connections_clone(nm_device_get_settings((NMDevice *) self), - &connections_len, - hidden_filter_func, - NULL, - NULL, - NULL); - if (!connections[0]) - return g_steal_pointer(&ssids); - - if (!ssids) { - ssids = g_ptr_array_new_full(max_scan_ssids, (GDestroyNotify) g_bytes_unref); - /* Add wildcard SSID using a static wildcard SSID used for every scan */ - g_ptr_array_insert(ssids, 0, g_bytes_ref(nm_gbytes_get_empty())); - } - - unique_ssids = g_hash_table_new(nm_gbytes_hash, nm_gbytes_equal); - for (i = 1; i < ssids->len; i++) { - if (!g_hash_table_add(unique_ssids, ssids->pdata[i])) - nm_assert_not_reached(); - } - - g_qsort_with_data(connections, - connections_len, - sizeof(NMSettingsConnection *), - nm_settings_connection_cmp_timestamp_p_with_data, - NULL); - - n_hidden = 0; - for (i = 0; i < connections_len; i++) { - NMSettingWireless *s_wifi; - GBytes * ssid; - - if (ssids->len >= max_scan_ssids) - break; - - if (n_hidden > 4) { - /* we allow at most 4 hidden profiles to be actively scanned. The - * reason is speed and to not disclose too many SSIDs. */ - break; - } - - s_wifi = nm_connection_get_setting_wireless( - nm_settings_connection_get_connection(connections[i])); - ssid = nm_setting_wireless_get_ssid(s_wifi); - - if (!g_hash_table_add(unique_ssids, ssid)) - continue; - - g_ptr_array_add(ssids, g_bytes_ref(ssid)); - n_hidden++; - } - - NM_SET_OUT(out_has_hidden_profiles, n_hidden > 0); - return g_steal_pointer(&ssids); -} - -static gboolean -_scan_request_delay_cb(gpointer user_data) -{ - NMDeviceWifi * self = user_data; - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - nm_clear_g_source_inst(&priv->scan_request_delay_source); - - _LOGT_scan("scan request completed (after extra delay)"); - - _scan_notify_is_scanning(self); - return G_SOURCE_REMOVE; -} - -static void -_scan_supplicant_request_scan_cb(NMSupplicantInterface *supp_iface, - GCancellable * cancellable, - gpointer user_data) -{ - NMDeviceWifi * self; - NMDeviceWifiPrivate *priv; - - if (g_cancellable_is_cancelled(cancellable)) - return; - - self = user_data; - priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - _LOGT_scan("scan request completed (D-Bus request)"); - - /* we just completed a scan request, but possibly the supplicant's state is not yet toggled - * to "scanning". That means, our internal scanning state "priv->scan_is_scanning" would already - * flip to idle, while in a moment the supplicant would toggle the state again. - * - * Artificially keep the scanning state on, for another SCAN_EXTRA_DELAY_MSEC msec. */ - nm_clear_g_source_inst(&priv->scan_request_delay_source); - priv->scan_request_delay_source = - nm_g_source_attach(nm_g_timeout_source_new(SCAN_EXTRA_DELAY_MSEC, - G_PRIORITY_DEFAULT, - _scan_request_delay_cb, - self, - NULL), - NULL); - - g_clear_object(&priv->scan_request_cancellable); - _scan_notify_is_scanning(self); -} - -static gboolean -_scan_kickoff_timeout_cb(gpointer user_data) -{ - NMDeviceWifi * self = user_data; - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - priv->scan_kickoff_timeout_id = 0; - _scan_kickoff(self); - return G_SOURCE_REMOVE; -} - -static void -_scan_kickoff(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - gs_unref_ptrarray GPtrArray *ssids = NULL; - gboolean is_explict = FALSE; - NMDeviceState device_state; - gboolean has_hidden_profiles; - gint64 now_msec; - gint64 ratelimit_duration_msec; - - if (!priv->sup_iface) { - _LOGT_scan("kickoff: don't scan (has no supplicant interface)"); - return; - } - - if (priv->scan_request_cancellable) { - _LOGT_scan("kickoff: don't scan (has scan_request_cancellable)"); - /* We are currently waiting for a scan request to complete. Wait longer. */ - return; - } - - now_msec = nm_utils_get_monotonic_timestamp_msec(); - - _scan_request_ssids_remove_all(priv, now_msec, G_MAXUINT); - - device_state = nm_device_get_state(NM_DEVICE(self)); - if (device_state > NM_DEVICE_STATE_DISCONNECTED && device_state <= NM_DEVICE_STATE_ACTIVATED) { - /* while we are activated, we rate limit more. */ - ratelimit_duration_msec = 8000; - } else - ratelimit_duration_msec = 1500; - - if (priv->scan_last_request_started_at_msec + ratelimit_duration_msec > now_msec) { - _LOGT_scan( - "kickoff: don't scan (rate limited for another %d.%03d sec%s)", - (int) ((priv->scan_last_request_started_at_msec + ratelimit_duration_msec - now_msec) - / 1000), - (int) ((priv->scan_last_request_started_at_msec + ratelimit_duration_msec - now_msec) - % 1000), - !priv->scan_kickoff_timeout_id ? ", schedule timeout" : ""); - if (!priv->scan_kickoff_timeout_id - && (priv->scan_explicit_allowed || priv->scan_periodic_allowed)) { - priv->scan_kickoff_timeout_id = g_timeout_add(priv->scan_last_request_started_at_msec - + ratelimit_duration_msec - now_msec, - _scan_kickoff_timeout_cb, - self); - } - return; - } - - if (priv->scan_explicit_requested) { - if (!priv->scan_explicit_allowed) { - _LOGT_scan("kickoff: don't scan (explicit scan requested but not allowed)"); - return; - } - priv->scan_explicit_requested = FALSE; - is_explict = TRUE; - } else { - if (!priv->scan_periodic_allowed) { - _LOGT_scan("kickoff: don't scan (periodic scan currently not allowed)"); - priv->scan_periodic_next_msec = 0; - priv->scan_periodic_interval_sec = 0; - nm_clear_g_source(&priv->scan_kickoff_timeout_id); - return; - } - - nm_assert(priv->scan_explicit_allowed); - - if (now_msec < priv->scan_periodic_next_msec) { - _LOGT_scan("kickoff: don't scan (periodic scan waiting for another %d.%03d sec%s)", - (int) ((priv->scan_periodic_next_msec - now_msec) / 1000), - (int) ((priv->scan_periodic_next_msec - now_msec) % 1000), - !priv->scan_kickoff_timeout_id ? ", schedule timeout" : ""); - if (!priv->scan_kickoff_timeout_id) { - priv->scan_kickoff_timeout_id = - g_timeout_add_seconds((priv->scan_periodic_next_msec - now_msec + 999) / 1000, - _scan_kickoff_timeout_cb, - self); - } - return; - } - - priv->scan_periodic_interval_sec = - NM_CLAMP(((int) priv->scan_periodic_interval_sec) * 3 / 2, - SCAN_INTERVAL_SEC_MIN, - SCAN_INTERVAL_SEC_MAX); - priv->scan_periodic_next_msec = now_msec + 1000 * priv->scan_periodic_interval_sec; - } - - ssids = _scan_request_ssids_build_hidden(self, now_msec, &has_hidden_profiles); - if (has_hidden_profiles) { - if (priv->hidden_probe_scan_warn) { - priv->hidden_probe_scan_warn = FALSE; - _LOGW(LOGD_WIFI, - "wifi-scan: active scanning for networks due to profiles with wifi.hidden=yes. " - "This makes you trackable"); - } - } else if (!is_explict) - priv->hidden_probe_scan_warn = TRUE; - - if (_LOGD_ENABLED(LOGD_WIFI)) { - gs_free char *ssids_str = NULL; - guint ssids_len = 0; - - if (ssids) { - gs_strfreev char **strv = NULL; - guint i; - - strv = g_new(char *, ssids->len + 1u); - for (i = 0; i < ssids->len; i++) - strv[i] = _nm_utils_ssid_to_string(ssids->pdata[i]); - strv[i] = NULL; - - nm_assert(ssids->len > 0); - nm_assert(ssids->len == NM_PTRARRAY_LEN(strv)); - - ssids_str = g_strjoinv(", ", strv); - ssids_len = ssids->len; - } - _LOGD(LOGD_WIFI, - "wifi-scan: start %s scan (%u SSIDs to probe scan%s%s%s)", - is_explict ? "explicit" : "periodic", - ssids_len, - NM_PRINT_FMT_QUOTED(ssids_str, " [", ssids_str, "]", "")); - } - - priv->scan_last_request_started_at_msec = now_msec; - - if (is_explict) - _LOGT_scan("kickoff: explicit scan starting"); - else { - _LOGT_scan("kickoff: periodic scan starting (next scan is scheduled in %d.%03d sec)", - (int) ((priv->scan_periodic_next_msec - now_msec) / 1000), - (int) ((priv->scan_periodic_next_msec - now_msec) % 1000)); - } - - _hw_addr_set_scanning(self, FALSE); - - priv->scan_request_cancellable = g_cancellable_new(); - nm_supplicant_interface_request_scan(priv->sup_iface, - ssids ? (GBytes *const *) ssids->pdata : NULL, - ssids ? ssids->len : 0u, - priv->scan_request_cancellable, - _scan_supplicant_request_scan_cb, - self); - - /* It's OK to call _scan_notify_is_scanning() again. They mutually call each other, - * but _scan_kickoff() sets "priv->scan_request_cancellable" which will stop - * them from recursing indefinitely. */ - _scan_notify_is_scanning(self); -} - -/**************************************************************************** - * WPA Supplicant control stuff - * - */ - -static gboolean -ap_list_dump(gpointer user_data) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(user_data); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - priv->ap_dump_id = 0; - - if (_LOGD_ENABLED(LOGD_WIFI_SCAN)) { - NMWifiAP *ap; - gint64 now_msec = nm_utils_get_monotonic_timestamp_msec(); - char str_buf[100]; - - _LOGD(LOGD_WIFI_SCAN, - "APs: [now:%u.%03u, last:%s]", - (guint)(now_msec / NM_UTILS_MSEC_PER_SEC), - (guint)(now_msec % NM_UTILS_MSEC_PER_SEC), - priv->scan_last_complete_msec > 0 - ? nm_sprintf_buf(str_buf, - "%u.%03u", - (guint)(priv->scan_last_complete_msec / NM_UTILS_MSEC_PER_SEC), - (guint)(priv->scan_last_complete_msec % NM_UTILS_MSEC_PER_SEC)) - : "-1"); - c_list_for_each_entry (ap, &priv->aps_lst_head, aps_lst) - _ap_dump(self, LOGL_DEBUG, ap, "dump", now_msec); - } - return G_SOURCE_REMOVE; -} - -static void -schedule_ap_list_dump(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - if (!priv->ap_dump_id && _LOGD_ENABLED(LOGD_WIFI_SCAN)) - priv->ap_dump_id = g_timeout_add_seconds(1, ap_list_dump, self); -} - -static void -try_fill_ssid_for_hidden_ap(NMDeviceWifi *self, NMWifiAP *ap) -{ - const char * bssid; - NMSettingsConnection *const *connections; - guint i; - - g_return_if_fail(nm_wifi_ap_get_ssid(ap) == NULL); - - bssid = nm_wifi_ap_get_address(ap); - g_return_if_fail(bssid); - - /* Look for this AP's BSSID in the seen-bssids list of a connection, - * and if a match is found, copy over the SSID */ - connections = nm_settings_get_connections(nm_device_get_settings((NMDevice *) self), NULL); - for (i = 0; connections[i]; i++) { - NMSettingsConnection *sett_conn = connections[i]; - NMSettingWireless * s_wifi; - - if (!nm_settings_connection_has_seen_bssid(sett_conn, bssid)) - continue; - s_wifi = - nm_connection_get_setting_wireless(nm_settings_connection_get_connection(sett_conn)); - if (!s_wifi) - continue; - - nm_wifi_ap_set_ssid(ap, nm_setting_wireless_get_ssid(s_wifi)); - break; - } -} - -static void -supplicant_iface_bss_changed_cb(NMSupplicantInterface *iface, - NMSupplicantBssInfo * bss_info, - gboolean is_present, - NMDeviceWifi * self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMWifiAP * found_ap; - GBytes * ssid; - - found_ap = g_hash_table_lookup(priv->aps_idx_by_supplicant_path, bss_info->bss_path); - - if (!is_present) { - if (!found_ap) - return; - if (found_ap == priv->current_ap) { - /* The current AP cannot be removed (to prevent NM indicating that - * it is connected, but to nothing), but it must be removed later - * when the current AP is changed or cleared. Set 'fake' to - * indicate that this AP is now unknown to the supplicant. - */ - if (nm_wifi_ap_set_fake(found_ap, TRUE)) - _ap_dump(self, LOGL_DEBUG, found_ap, "updated", 0); - } else { - ap_add_remove(self, FALSE, found_ap, TRUE); - schedule_ap_list_dump(self); - } - return; - } - - if (found_ap) { - if (!nm_wifi_ap_update_from_properties(found_ap, bss_info)) - return; - _ap_dump(self, LOGL_DEBUG, found_ap, "updated", 0); - } else { - gs_unref_object NMWifiAP *ap = NULL; - - if (!bss_info->bssid_valid) { - /* We failed to initialize the info about the AP. This can - * happen due to an error in the D-Bus communication. In this case - * we ignore the info. */ - return; - } - - ap = nm_wifi_ap_new_from_properties(bss_info); - - /* Let the manager try to fill in the SSID from seen-bssids lists */ - ssid = nm_wifi_ap_get_ssid(ap); - if (!ssid || _nm_utils_is_empty_ssid(ssid)) { - /* Try to fill the SSID from the AP database */ - try_fill_ssid_for_hidden_ap(self, ap); - - ssid = nm_wifi_ap_get_ssid(ap); - if (ssid && !_nm_utils_is_empty_ssid(ssid)) { - gs_free char *s = NULL; - - /* Yay, matched it, no longer treat as hidden */ - _LOGD(LOGD_WIFI, - "matched hidden AP %s => %s", - nm_wifi_ap_get_address(ap), - (s = _nm_utils_ssid_to_string(ssid))); - } else { - /* Didn't have an entry for this AP in the database */ - _LOGD(LOGD_WIFI, "failed to match hidden AP %s", nm_wifi_ap_get_address(ap)); - } - } - - ap_add_remove(self, TRUE, ap, TRUE); - } - - /* Update the current AP if the supplicant notified a current BSS change - * before it sent the current BSS's scan result. - */ - if (nm_supplicant_interface_get_current_bss(iface) == bss_info->bss_path) - supplicant_iface_notify_current_bss(priv->sup_iface, NULL, self); - - schedule_ap_list_dump(self); -} - -static void -cleanup_association_attempt(NMDeviceWifi *self, gboolean disconnect) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - nm_clear_g_source(&priv->sup_timeout_id); - nm_clear_g_source(&priv->link_timeout_id); - nm_clear_g_source(&priv->wps_timeout_id); - if (disconnect && priv->sup_iface) - nm_supplicant_interface_disconnect(priv->sup_iface); -} - -static void -cleanup_supplicant_failures(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - nm_clear_g_source(&priv->reacquire_iface_id); - priv->failed_iface_count = 0; -} - -static void -wifi_secrets_cb(NMActRequest * req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * connection, - GError * error, - gpointer user_data) -{ - NMDevice * device = user_data; - NMDeviceWifi * self = user_data; - NMDeviceWifiPrivate *priv; - - g_return_if_fail(NM_IS_DEVICE_WIFI(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - g_return_if_fail(priv->wifi_secrets_id == call_id); - - priv->wifi_secrets_id = NULL; - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - g_return_if_fail(req == nm_device_get_act_request(device)); - g_return_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_NEED_AUTH); - g_return_if_fail(nm_act_request_get_settings_connection(req) == connection); - - if (error) { - _LOGW(LOGD_WIFI, "no secrets: %s", error->message); - - /* Even if WPS is still pending, let's abort the activation when the secret - * request returns. - * - * This means, a user can only effectively use WPS when also running a secret - * agent, and pressing the push button while being prompted for the password. - * Note, that in the secret prompt the user can see that WPS is in progress - * (via the NM_SECRET_AGENT_GET_SECRETS_FLAG_WPS_PBC_ACTIVE flag). - * - * Previously, WPS was not cancelled when the secret request returns. - * Note that in common use-cases WPS is enabled in the connection profile - * but it won't succeed (because it's disabled in the AP or because the - * user is not prepared to press the push button). - * That means for example, during boot we would try to autoconnect with WPS. - * At that point, there is no secret-agent running, and WPS is pending for - * full 30 seconds. If in the meantime a secret agent registers (because - * of logging into the DE), the profile is still busy waiting for WPS to time - * out. Only after that delay, autoconnect starts again (note that autoconnect gets - * not blocked in this case, because a secret agent registered in the meantime). - * - * It seems wrong to continue doing WPS if the user is not aware - * that WPS is ongoing. The user is required to perform an action (push button), - * and must be told via the secret prompt. - * If no secret-agent is running, if the user cancels the secret-request, or any - * other error to obtain secrets, the user apparently does not want WPS either. - */ - nm_clear_g_source(&priv->wps_timeout_id); - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -wifi_secrets_cancel(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - if (priv->wifi_secrets_id) - nm_act_request_cancel_secrets(NULL, priv->wifi_secrets_id); - nm_assert(!priv->wifi_secrets_id); -} - -static void -supplicant_iface_wps_credentials_cb(NMSupplicantInterface *iface, - GVariant * credentials, - NMDeviceWifi * self) -{ - NMActRequest * req; - gs_unref_variant GVariant *val_key = NULL; - gs_unref_variant GVariant *secrets = NULL; - gs_free_error GError *error = NULL; - const char * array; - gsize psk_len = 0; - - if (nm_device_get_state(NM_DEVICE(self)) != NM_DEVICE_STATE_NEED_AUTH) { - _LOGI(LOGD_DEVICE | LOGD_WIFI, "WPS: The connection can't be updated with credentials"); - return; - } - - _LOGI(LOGD_DEVICE | LOGD_WIFI, "WPS: Updating the connection with credentials"); - - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - val_key = g_variant_lookup_value(credentials, "Key", G_VARIANT_TYPE_BYTESTRING); - if (val_key) { - char psk[64]; - - array = g_variant_get_fixed_array(val_key, &psk_len, 1); - if (psk_len >= 8 && psk_len <= 63) { - memcpy(psk, array, psk_len); - psk[psk_len] = '\0'; - if (g_utf8_validate(psk, psk_len, NULL)) { - secrets = g_variant_new_parsed("[{%s, [{%s, <%s>}]}]", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_PSK, - psk); - g_variant_ref_sink(secrets); - } - } - if (!secrets) - _LOGW(LOGD_DEVICE | LOGD_WIFI, "WPS: ignore invalid PSK"); - } - - if (!secrets) - return; - - if (!nm_settings_connection_new_secrets(nm_act_request_get_settings_connection(req), - nm_act_request_get_applied_connection(req), - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - secrets, - &error)) { - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "WPS: Could not update the connection with credentials: %s", - error->message); - return; - } - - wifi_secrets_cancel(self); - nm_device_activate_schedule_stage1_device_prepare(NM_DEVICE(self), FALSE); -} - -static gboolean -wps_timeout_cb(gpointer user_data) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(user_data); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - priv->wps_timeout_id = 0; - if (!priv->wifi_secrets_id) { - /* Fail only if the secrets are not being requested. */ - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } - - return G_SOURCE_REMOVE; -} - -static void -wifi_secrets_get_secrets(NMDeviceWifi * self, - const char * setting_name, - NMSecretAgentGetSecretsFlags flags) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMActRequest * req; - - wifi_secrets_cancel(self); - - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_if_fail(NM_IS_ACT_REQUEST(req)); - - priv->wifi_secrets_id = - nm_act_request_get_secrets(req, TRUE, setting_name, flags, NULL, wifi_secrets_cb, self); - g_return_if_fail(priv->wifi_secrets_id); -} - -/* - * link_timeout_cb - * - * Called when the link to the access point has been down for a specified - * period of time. - */ -static gboolean -link_timeout_cb(gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - _LOGW(LOGD_WIFI, "link timed out."); - - priv->link_timeout_id = 0; - - /* Disconnect event while activated; the supplicant hasn't been able - * to reassociate within the timeout period, so the connection must - * fail. - */ - if (nm_device_get_state(device) != NM_DEVICE_STATE_ACTIVATED) - return FALSE; - - set_current_ap(self, NULL, TRUE); - - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - priv->ssid_found ? NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT - : NM_DEVICE_STATE_REASON_SSID_NOT_FOUND); - return FALSE; -} - -static gboolean -need_new_8021x_secrets(NMDeviceWifi * self, - NMSupplicantInterfaceState old_state, - const char ** setting_name) -{ - NMSetting8021x * s_8021x; - NMSettingWirelessSecurity *s_wsec; - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - NMConnection * connection; - - g_return_val_if_fail(setting_name, FALSE); - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - - g_return_val_if_fail(connection != NULL, FALSE); - - /* 802.1x stuff only happens in the supplicant's ASSOCIATED state when it's - * attempting to authenticate with the AP. - */ - if (old_state != NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED) - return FALSE; - - /* If it's an 802.1x or LEAP connection with "always ask"/unsaved secrets - * then we need to ask again because it might be an OTP token and the PIN - * may have changed. - */ - - s_8021x = nm_connection_get_setting_802_1x(connection); - if (s_8021x) { - if (!nm_setting_get_secret_flags(NM_SETTING(s_8021x), - NM_SETTING_802_1X_PASSWORD, - &secret_flags, - NULL)) - g_assert_not_reached(); - if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) - *setting_name = NM_SETTING_802_1X_SETTING_NAME; - return *setting_name ? TRUE : FALSE; - } - - s_wsec = nm_connection_get_setting_wireless_security(connection); - if (s_wsec) { - if (!nm_setting_get_secret_flags(NM_SETTING(s_wsec), - NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, - &secret_flags, - NULL)) - g_assert_not_reached(); - if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) - *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; - return *setting_name ? TRUE : FALSE; - } - - /* Not a LEAP or 802.1x connection */ - return FALSE; -} - -static gboolean -need_new_wpa_psk(NMDeviceWifi * self, - NMSupplicantInterfaceState old_state, - int disconnect_reason, - const char ** setting_name) -{ - NMSettingWirelessSecurity *s_wsec; - NMConnection * connection; - const char * key_mgmt = NULL; - - g_return_val_if_fail(setting_name, FALSE); - - connection = nm_device_get_applied_connection(NM_DEVICE(self)); - - g_return_val_if_fail(connection, FALSE); - - /* A bad PSK will cause the supplicant to disconnect during the 4-way handshake */ - if (old_state != NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE) - return FALSE; - - s_wsec = nm_connection_get_setting_wireless_security(connection); - if (s_wsec) - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - - if (g_strcmp0(key_mgmt, "wpa-psk") == 0) { -/* -4 (locally-generated WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY) usually - * means the driver missed beacons from the AP. This usually happens - * due to driver bugs or faulty power-save management. It doesn't - * indicate that the PSK is wrong. - */ -#define LOCAL_WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY -4 - if (disconnect_reason == LOCAL_WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY) - return FALSE; - - *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; - return TRUE; - } - - /* Not a WPA-PSK connection */ - return FALSE; -} - -static gboolean -handle_8021x_or_psk_auth_fail(NMDeviceWifi * self, - NMSupplicantInterfaceState new_state, - NMSupplicantInterfaceState old_state, - int disconnect_reason) -{ - NMDevice * device = NM_DEVICE(self); - NMActRequest *req; - const char * setting_name = NULL; - gboolean handled = FALSE; - - g_return_val_if_fail(new_state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, FALSE); - - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_val_if_fail(req != NULL, FALSE); - - if (need_new_8021x_secrets(self, old_state, &setting_name) - || need_new_wpa_psk(self, old_state, disconnect_reason, &setting_name)) { - nm_act_request_clear_secrets(req); - - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) disconnected during association, asking for new key"); - - cleanup_association_attempt(self, TRUE); - nm_device_state_changed(device, - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - wifi_secrets_get_secrets(self, - setting_name, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION - | NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); - handled = TRUE; - } - - return handled; -} - -static gboolean -reacquire_interface_cb(gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - priv->reacquire_iface_id = 0; - priv->failed_iface_count++; - - _LOGW(LOGD_WIFI, "re-acquiring supplicant interface (#%d).", priv->failed_iface_count); - - if (!priv->sup_iface) - supplicant_interface_acquire(self); - - return G_SOURCE_REMOVE; -} - -static void -supplicant_iface_state_down(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - cleanup_association_attempt(self, FALSE); - - /* If the device is already in UNAVAILABLE state then the state change - * is a NOP and the interface won't be re-acquired in the device state - * change handler. So ensure we have a new one here so that we're - * ready if the supplicant comes back. - */ - supplicant_interface_release(self); - if (priv->failed_iface_count < 5) - priv->reacquire_iface_id = g_timeout_add_seconds(10, reacquire_interface_cb, self); - else - _LOGI(LOGD_DEVICE | LOGD_WIFI, "supplicant interface keeps failing, giving up"); -} - -static void -supplicant_iface_state(NMDeviceWifi * self, - NMSupplicantInterfaceState new_state, - NMSupplicantInterfaceState old_state, - int disconnect_reason, - gboolean is_real_signal) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMDeviceState devstate; - gboolean scanning; - gboolean scan_changed; - - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "supplicant interface state: %s -> %s%s", - nm_supplicant_interface_state_to_string(old_state), - nm_supplicant_interface_state_to_string(new_state), - is_real_signal ? "" : " (simulated signal)"); - - if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - supplicant_iface_state_down(self); - goto out; - } - - devstate = nm_device_get_state(device); - scanning = nm_supplicant_interface_get_scanning(priv->sup_iface); - - if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { - _LOGD(LOGD_WIFI, "supplicant ready"); - nm_device_queue_recheck_available(NM_DEVICE(device), - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - priv->scan_periodic_interval_sec = 0; - priv->scan_periodic_next_msec = 0; - } - - /* In these states we know the supplicant is actually talking to something */ - if (new_state >= NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING - && new_state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) - priv->ssid_found = TRUE; - - if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) - recheck_p2p_availability(self); - - switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: - nm_clear_g_source(&priv->sup_timeout_id); - nm_clear_g_source(&priv->link_timeout_id); - nm_clear_g_source(&priv->wps_timeout_id); - - /* If this is the initial association during device activation, - * schedule the next activation stage. - */ - if (devstate == NM_DEVICE_STATE_CONFIG) { - NMSettingWireless *s_wifi; - GBytes * ssid; - gs_free char * ssid_str = NULL; - - s_wifi = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_WIRELESS); - - g_return_if_fail(s_wifi); - - ssid = nm_setting_wireless_get_ssid(s_wifi); - g_return_if_fail(ssid); - - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) Stage 2 of 5 (Device Configure) successful. %s %s", - priv->mode == NM_802_11_MODE_AP ? "Started Wi-Fi Hotspot" - : "Connected to wireless network", - (ssid_str = _nm_utils_ssid_to_string(ssid))); - nm_device_activate_schedule_stage3_ip_config_start(device); - } else if (devstate == NM_DEVICE_STATE_ACTIVATED) - periodic_update(self); - break; - case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: - if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating(device)) { - /* Disconnect of an 802.1x/LEAP connection during authentication, - * or disconnect of a WPA-PSK connection during the 4-way handshake, - * often means secrets are wrong. Not always the case, but until we - * have more information from wpa_supplicant about why the - * disconnect happened this is the best we can do. - */ - if (handle_8021x_or_psk_auth_fail(self, new_state, old_state, disconnect_reason)) - break; - } - - /* Otherwise, it might be a stupid driver or some transient error, so - * let the supplicant try to reconnect a few more times. Give it more - * time if a scan is in progress since the link might be dropped during - * the scan but will be re-established when the scan is done. - */ - if (devstate == NM_DEVICE_STATE_ACTIVATED) { - if (priv->link_timeout_id == 0) { - priv->link_timeout_id = - g_timeout_add_seconds(scanning ? 30 : 15, link_timeout_cb, self); - priv->ssid_found = FALSE; - } - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_INACTIVE: - /* we would clear _scan_has_pending_action_set() and trigger a new scan. - * However, we don't want to cancel the current pending action, so force - * a new scan request. */ - break; - default: - break; - } - -out: - scan_changed = _scan_notify_allowed(self, NM_TERNARY_FALSE); - scan_changed |= _scan_notify_is_scanning(self); - if (scan_changed) - _scan_kickoff(self); - - if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) - nm_device_remove_pending_action(device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); -} - -static void -supplicant_iface_state_cb(NMSupplicantInterface *iface, - int new_state_i, - int old_state_i, - int disconnect_reason, - gpointer user_data) -{ - supplicant_iface_state(user_data, new_state_i, old_state_i, disconnect_reason, TRUE); -} - -static void -supplicant_iface_assoc_cb(NMSupplicantInterface *iface, GError *error, gpointer user_data) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI(user_data); - NMDevice * device = NM_DEVICE(self); - - if (error && !nm_utils_error_is_cancelled_or_disposing(error) - && nm_device_is_activating(device)) { - cleanup_association_attempt(self, TRUE); - nm_device_queue_state(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } -} - -static void -supplicant_iface_notify_current_bss(NMSupplicantInterface *iface, - GParamSpec * pspec, - NMDeviceWifi * self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMRefString * current_bss; - NMWifiAP * new_ap = NULL; - - current_bss = nm_supplicant_interface_get_current_bss(iface); - if (current_bss) - new_ap = g_hash_table_lookup(priv->aps_idx_by_supplicant_path, current_bss); - - if (new_ap != priv->current_ap) { - const char * new_bssid = NULL; - GBytes * new_ssid = NULL; - const char * old_bssid = NULL; - GBytes * old_ssid = NULL; - gs_free char *new_ssid_s = NULL; - gs_free char *old_ssid_s = NULL; - - /* Don't ever replace a "fake" current AP if we don't know about the - * supplicant's current BSS yet. It'll get replaced when we receive - * the current BSS's scan result. - */ - if (new_ap == NULL && nm_wifi_ap_get_fake(priv->current_ap)) - return; - - if (new_ap) { - new_bssid = nm_wifi_ap_get_address(new_ap); - new_ssid = nm_wifi_ap_get_ssid(new_ap); - } - - if (priv->current_ap) { - old_bssid = nm_wifi_ap_get_address(priv->current_ap); - old_ssid = nm_wifi_ap_get_ssid(priv->current_ap); - } - - _LOGD(LOGD_WIFI, - "roamed from BSSID %s (%s) to %s (%s)", - old_bssid ?: "(none)", - (old_ssid_s = _nm_utils_ssid_to_string(old_ssid)), - new_bssid ?: "(none)", - (new_ssid_s = _nm_utils_ssid_to_string(new_ssid))); - - if (new_bssid) { - /* The new AP could be in a different layer 3 network - * and so the old DHCP lease could be no longer valid. - * Also, some APs (e.g. Cisco) can be configured to drop - * all traffic until DHCP completes. To support such - * cases, renew the lease when roaming to a new AP. */ - nm_device_update_dynamic_ip_setup(NM_DEVICE(self)); - } - - set_current_ap(self, new_ap, TRUE); - } -} - -/* We bind the existence of the P2P device to a wifi device that is being - * managed by NetworkManager and is capable of P2P operation. - * Note that some care must be taken here, because we don't want to re-create - * the device every time the supplicant interface is destroyed (e.g. due to - * a suspend/resume cycle). - * Therefore, this function will be called when a change in the P2P capability - * is detected and the supplicant interface has been initialised. - */ -static void -recheck_p2p_availability(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - gboolean p2p_available; - - g_object_get(priv->sup_iface, NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE, &p2p_available, NULL); - - if (p2p_available && !priv->p2p_device) { - gs_free char *iface_name = NULL; - - /* Create a P2P device. "p2p-dev-" is the same prefix as chosen by - * wpa_supplicant internally. - */ - iface_name = g_strconcat("p2p-dev-", nm_device_get_iface(NM_DEVICE(self)), NULL); - - priv->p2p_device = nm_device_wifi_p2p_new(iface_name); - - nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, priv->sup_iface); - - g_signal_emit(self, signals[P2P_DEVICE_CREATED], 0, priv->p2p_device); - g_object_add_weak_pointer(G_OBJECT(priv->p2p_device), (gpointer *) &priv->p2p_device); - g_object_unref(priv->p2p_device); - return; - } - - if (p2p_available && priv->p2p_device) { - nm_device_wifi_p2p_set_mgmt_iface(priv->p2p_device, priv->sup_iface); - return; - } - - if (!p2p_available && priv->p2p_device) { - /* Destroy the P2P device. */ - g_object_remove_weak_pointer(G_OBJECT(priv->p2p_device), (gpointer *) &priv->p2p_device); - nm_device_wifi_p2p_remove(g_steal_pointer(&priv->p2p_device)); - return; - } -} - -static void -supplicant_iface_notify_p2p_available(NMSupplicantInterface *iface, - GParamSpec * pspec, - NMDeviceWifi * self) -{ - if (nm_supplicant_interface_get_state(iface) > NM_SUPPLICANT_INTERFACE_STATE_STARTING) - recheck_p2p_availability(self); -} - -static gboolean -handle_auth_or_fail(NMDeviceWifi *self, NMActRequest *req, gboolean new_secrets) -{ - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - const char * setting_name; - NMConnection * applied_connection; - NMSettingWirelessSecurity * s_wsec; - const char * bssid = NULL; - NM80211ApFlags ap_flags; - NMSettingWirelessSecurityWpsMethod wps_method; - const char * type; - NMSecretAgentGetSecretsFlags get_secret_flags = - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - - g_return_val_if_fail(NM_IS_DEVICE_WIFI(self), FALSE); - - if (!req) { - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_val_if_fail(req, FALSE); - } - - if (!nm_device_auth_retries_try_next(NM_DEVICE(self))) - return FALSE; - - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_NONE); - - applied_connection = nm_act_request_get_applied_connection(req); - s_wsec = nm_connection_get_setting_wireless_security(applied_connection); - wps_method = nm_setting_wireless_security_get_wps_method(s_wsec); - - /* Negotiate the WPS method */ - if (wps_method == NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT) - wps_method = NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_AUTO; - - if (wps_method & NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_AUTO && priv->current_ap) { - /* Determine the method to use from AP capabilities. */ - ap_flags = nm_wifi_ap_get_flags(priv->current_ap); - if (ap_flags & NM_802_11_AP_FLAGS_WPS_PBC) - wps_method |= NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PBC; - if (ap_flags & NM_802_11_AP_FLAGS_WPS_PIN) - wps_method |= NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PIN; - if (ap_flags & NM_802_11_AP_FLAGS_WPS - && wps_method == NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_AUTO) { - /* The AP doesn't specify which methods are supported. Allow all. */ - wps_method |= NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PBC; - wps_method |= NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PIN; - } - } - - if (wps_method & NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PBC) { - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_WPS_PBC_ACTIVE; - type = "pbc"; - } else if (wps_method & NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_PIN) { - type = "pin"; - } else - type = NULL; - - if (type) { - priv->wps_timeout_id = g_timeout_add_seconds(30, wps_timeout_cb, self); - if (priv->current_ap) - bssid = nm_wifi_ap_get_address(priv->current_ap); - nm_supplicant_interface_enroll_wps(priv->sup_iface, type, bssid, NULL); - } - - nm_act_request_clear_secrets(req); - setting_name = nm_connection_need_secrets(applied_connection, NULL); - if (!setting_name) { - _LOGW(LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return FALSE; - } - - if (new_secrets) - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - wifi_secrets_get_secrets(self, setting_name, get_secret_flags); - return TRUE; -} - -/* - * supplicant_connection_timeout_cb - * - * Called when the supplicant has been unable to connect to an access point - * within a specified period of time. - */ -static gboolean -supplicant_connection_timeout_cb(gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceWifi * self = NM_DEVICE_WIFI(user_data); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMActRequest * req; - NMConnection * connection; - - cleanup_association_attempt(self, TRUE); - - if (!nm_device_is_activating(device)) - return FALSE; - - /* Timed out waiting for a successful connection to the AP; if the AP's - * security requires network-side authentication (like WPA or 802.1x) - * and the connection attempt timed out then it's likely the authentication - * information (passwords, pin codes, etc) are wrong. - */ - - req = nm_device_get_act_request(device); - g_assert(req); - - connection = nm_act_request_get_applied_connection(req); - g_assert(connection); - - if (NM_IN_SET(priv->mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_MESH, NM_802_11_MODE_AP)) { - /* In Ad-Hoc and AP modes there's nothing to check the encryption key - * (if any), so supplicant timeouts here are almost certainly the wifi - * driver being really stupid. - */ - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) %s network creation took too long, failing activation", - priv->mode == NM_802_11_MODE_ADHOC ? "Ad-Hoc" : "Hotspot"); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); - return FALSE; - } - - g_assert(priv->mode == NM_802_11_MODE_INFRA); - - if (priv->ssid_found && nm_connection_get_setting_wireless_security(connection)) { - guint64 timestamp = 0; - gboolean new_secrets = TRUE; - - /* Connection failed; either driver problems, the encryption key is - * wrong, or the passwords or certificates were wrong. - */ - _LOGW(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) association took too long"); - - /* Ask for new secrets only if we've never activated this connection - * before. If we've connected before, don't bother the user with - * dialogs, just retry or fail, and if we never connect the user can - * fix the password somewhere else. - */ - if (nm_settings_connection_get_timestamp(nm_act_request_get_settings_connection(req), - ×tamp)) - new_secrets = !timestamp; - - if (handle_auth_or_fail(self, req, new_secrets)) - _LOGW(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) asking for new secrets"); - else { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } - } else { - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) association took too long, failing activation"); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - priv->ssid_found ? NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT - : NM_DEVICE_STATE_REASON_SSID_NOT_FOUND); - } - - return FALSE; -} - -static NMSupplicantConfig * -build_supplicant_config(NMDeviceWifi *self, - NMConnection *connection, - guint32 fixed_freq, - GError ** error) -{ - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSupplicantConfig * config = NULL; - NMSettingWireless * s_wireless; - NMSettingWirelessSecurity * s_wireless_sec; - NMSettingWirelessSecurityPmf pmf; - NMSettingWirelessSecurityFils fils; - NMTernary ap_isolation; - - g_return_val_if_fail(priv->sup_iface, NULL); - - s_wireless = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wireless != NULL, NULL); - - config = nm_supplicant_config_new(nm_supplicant_interface_get_capabilities(priv->sup_iface)); - - /* Warn if AP mode may not be supported */ - if (nm_streq0(nm_setting_wireless_get_mode(s_wireless), NM_SETTING_WIRELESS_MODE_AP) - && nm_supplicant_interface_get_capability(priv->sup_iface, NM_SUPPL_CAP_TYPE_AP) - != NM_TERNARY_TRUE) { - _LOGW(LOGD_WIFI, "Supplicant may not support AP mode; connection may time out."); - } - - if (!nm_supplicant_config_add_setting_wireless(config, s_wireless, fixed_freq, error)) { - g_prefix_error(error, "802-11-wireless: "); - goto error; - } - - if (!nm_supplicant_config_add_bgscan(config, connection, error)) { - g_prefix_error(error, "bgscan: "); - goto error; - } - - ap_isolation = nm_setting_wireless_get_ap_isolation(s_wireless); - if (ap_isolation == NM_TERNARY_DEFAULT) { - ap_isolation = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - "wifi.ap-isolation", - NM_DEVICE(self), - NM_TERNARY_FALSE, - NM_TERNARY_TRUE, - NM_TERNARY_FALSE); - } - nm_supplicant_config_set_ap_isolation(config, ap_isolation == NM_TERNARY_TRUE); - - s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - if (s_wireless_sec) { - NMSetting8021x *s_8021x; - const char * con_uuid = nm_connection_get_uuid(connection); - guint32 mtu = nm_platform_link_get_mtu(nm_device_get_platform(NM_DEVICE(self)), - nm_device_get_ifindex(NM_DEVICE(self))); - - g_assert(con_uuid); - - /* Configure PMF (802.11w) */ - pmf = nm_setting_wireless_security_get_pmf(s_wireless_sec); - if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT) { - pmf = nm_config_data_get_connection_default_int64( - NM_CONFIG_GET_DATA, - "wifi-sec.pmf", - NM_DEVICE(self), - NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE, - NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED, - NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL); - } - - /* Configure FILS (802.11ai) */ - fils = nm_setting_wireless_security_get_fils(s_wireless_sec); - if (fils == NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT) { - fils = nm_config_data_get_connection_default_int64( - NM_CONFIG_GET_DATA, - "wifi-sec.fils", - NM_DEVICE(self), - NM_SETTING_WIRELESS_SECURITY_FILS_DISABLE, - NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED, - NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL); - } - - s_8021x = nm_connection_get_setting_802_1x(connection); - if (!nm_supplicant_config_add_setting_wireless_security(config, - s_wireless_sec, - s_8021x, - con_uuid, - mtu, - pmf, - fils, - error)) { - g_prefix_error(error, "802-11-wireless-security: "); - goto error; - } - } else { - if (!nm_supplicant_config_add_no_security(config, error)) { - g_prefix_error(error, "unsecured-option: "); - goto error; - } - } - - return config; - -error: - g_object_unref(config); - return NULL; -} - -/*****************************************************************************/ - -static gboolean -wake_on_wlan_enable(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate * priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMSettingWirelessWakeOnWLan wowl; - NMSettingWireless * s_wireless; - - s_wireless = nm_device_get_applied_setting(NM_DEVICE(self), NM_TYPE_SETTING_WIRELESS); - if (s_wireless) { - wowl = nm_setting_wireless_get_wake_on_wlan(s_wireless); - if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) - goto found; - } - - wowl = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - "wifi.wake-on-wlan", - NM_DEVICE(self), - NM_SETTING_WIRELESS_WAKE_ON_WLAN_NONE, - G_MAXINT32, - NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT); - - if (NM_FLAGS_ANY(wowl, NM_SETTING_WIRELESS_WAKE_ON_WLAN_EXCLUSIVE_FLAGS)) { - if (!nm_utils_is_power_of_two(wowl)) { - _LOGD(LOGD_WIFI, - "invalid default value %u for wake-on-wlan: " - "'default' and 'ignore' are exclusive flags", - (guint) wowl); - wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; - } - } else if (NM_FLAGS_ANY(wowl, ~NM_SETTING_WIRELESS_WAKE_ON_WLAN_ALL)) { - _LOGD(LOGD_WIFI, "invalid default value %u for wake-on-wlan", (guint) wowl); - wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT; - } - if (wowl != NM_SETTING_WIRELESS_WAKE_ON_WLAN_DEFAULT) - goto found; - - wowl = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; -found: - if (wowl == NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE) { - priv->wowlan_restore = wowl; - return TRUE; - } - - priv->wowlan_restore = - nm_platform_wifi_get_wake_on_wlan(NM_PLATFORM_GET, nm_device_get_ifindex(NM_DEVICE(self))); - - return nm_platform_wifi_set_wake_on_wlan(NM_PLATFORM_GET, - nm_device_get_ifindex(NM_DEVICE(self)), - wowl); -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMWifiAP * ap = NULL; - gs_unref_object NMWifiAP *ap_fake = NULL; - NMActRequest * req; - NMConnection * connection; - NMSettingWireless * s_wireless; - const char * mode; - const char * ap_path; - - req = nm_device_get_act_request(NM_DEVICE(self)); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - connection = nm_act_request_get_applied_connection(req); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_wireless = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wireless, NM_ACT_STAGE_RETURN_FAILURE); - - nm_supplicant_interface_cancel_wps(priv->sup_iface); - - mode = nm_setting_wireless_get_mode(s_wireless); - if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_INFRA) == 0) - priv->mode = NM_802_11_MODE_INFRA; - else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_ADHOC) == 0) - priv->mode = NM_802_11_MODE_ADHOC; - else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_AP) == 0) { - priv->mode = NM_802_11_MODE_AP; - - /* Scanning not done in AP mode; clear the scan list */ - remove_all_aps(self); - } else if (g_strcmp0(mode, NM_SETTING_WIRELESS_MODE_MESH) == 0) - priv->mode = NM_802_11_MODE_MESH; - _notify(self, PROP_MODE); - - /* expire the temporary MAC address used during scanning */ - priv->hw_addr_scan_expire = 0; - - /* Set spoof MAC to the interface */ - if (!nm_device_hw_addr_set_cloned(device, connection, TRUE)) { - *out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - /* AP and Mesh modes never use a specific object or existing scanned AP */ - if (!NM_IN_SET(priv->mode, NM_802_11_MODE_AP, NM_802_11_MODE_MESH)) { - ap_path = nm_active_connection_get_specific_object(NM_ACTIVE_CONNECTION(req)); - ap = ap_path ? nm_wifi_ap_lookup_for_device(NM_DEVICE(self), ap_path) : NULL; - } - if (!ap) - ap = nm_wifi_aps_find_first_compatible(&priv->aps_lst_head, connection); - - if (!ap) { - /* If the user is trying to connect to an AP that NM doesn't yet know about - * (hidden network or something), starting a Hotspot or joining a Mesh, - * create a fake APfrom the security settings in the connection. This "fake" - * AP gets used until the real one is found in the scan list (Ad-Hoc or Hidden), - * or until the device is deactivated (Hotspot). - */ - ap_fake = nm_wifi_ap_new_fake_from_connection(connection); - if (!ap_fake) - g_return_val_if_reached(NM_ACT_STAGE_RETURN_FAILURE); - - if (nm_wifi_ap_is_hotspot(ap_fake)) - nm_wifi_ap_set_address(ap_fake, nm_device_get_hw_address(device)); - - g_object_freeze_notify(G_OBJECT(self)); - ap_add_remove(self, TRUE, ap_fake, TRUE); - g_object_thaw_notify(G_OBJECT(self)); - ap = ap_fake; - } - - _scan_notify_allowed(self, NM_TERNARY_DEFAULT); - - set_current_ap(self, ap, FALSE); - nm_active_connection_set_specific_object(NM_ACTIVE_CONNECTION(req), - nm_dbus_object_get_path(NM_DBUS_OBJECT(ap))); - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static void -ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP *ap) -{ - NMDevice * device = NM_DEVICE(self); - const char * band = nm_setting_wireless_get_band(s_wifi); - const guint32 a_freqs[] = {5180, 5200, 5220, 5745, 5765, 5785, 5805, 0}; - const guint32 bg_freqs[] = {2412, 2437, 2462, 2472, 0}; - guint32 freq = 0; - - g_assert(ap); - - if (nm_wifi_ap_get_freq(ap)) - return; - - if (g_strcmp0(band, "a") == 0) - freq = nm_platform_wifi_find_frequency(nm_device_get_platform(device), - nm_device_get_ifindex(device), - a_freqs); - else - freq = nm_platform_wifi_find_frequency(nm_device_get_platform(device), - nm_device_get_ifindex(device), - bg_freqs); - - if (!freq) - freq = (g_strcmp0(band, "a") == 0) ? 5180 : 2462; - - if (nm_wifi_ap_set_freq(ap, freq)) - _ap_dump(self, LOGL_DEBUG, ap, "updated", 0); -} - -static void -set_powersave(NMDevice *device) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMSettingWireless * s_wireless; - NMSettingWirelessPowersave val; - - s_wireless = nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRELESS); - - g_return_if_fail(s_wireless); - - val = nm_setting_wireless_get_powersave(s_wireless); - if (val == NM_SETTING_WIRELESS_POWERSAVE_DEFAULT) { - val = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA, - "wifi.powersave", - device, - NM_SETTING_WIRELESS_POWERSAVE_IGNORE, - NM_SETTING_WIRELESS_POWERSAVE_ENABLE, - NM_SETTING_WIRELESS_POWERSAVE_IGNORE); - } - - _LOGT(LOGD_WIFI, "powersave is set to %u", (unsigned) val); - - if (val == NM_SETTING_WIRELESS_POWERSAVE_IGNORE) - return; - - nm_platform_wifi_set_powersave(nm_device_get_platform(device), - nm_device_get_ifindex(device), - val == NM_SETTING_WIRELESS_POWERSAVE_ENABLE); -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - gs_unref_object NMSupplicantConfig *config = NULL; - NM80211Mode ap_mode; - NMActRequest * req; - NMWifiAP * ap; - NMConnection * connection; - const char * setting_name; - NMSettingWireless * s_wireless; - GError * error = NULL; - guint timeout; - - nm_clear_g_source(&priv->sup_timeout_id); - nm_clear_g_source(&priv->link_timeout_id); - nm_clear_g_source(&priv->wps_timeout_id); - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - ap = priv->current_ap; - if (!ap) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out_fail; - } - - ap_mode = nm_wifi_ap_get_mode(ap); - - connection = nm_act_request_get_applied_connection(req); - s_wireless = nm_connection_get_setting_wireless(connection); - nm_assert(s_wireless); - - /* If we need secrets, get them */ - setting_name = nm_connection_need_secrets(connection, NULL); - if (setting_name) { - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) access point '%s' has security, but secrets are required.", - nm_connection_get_id(connection)); - - if (!handle_auth_or_fail(self, req, FALSE)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - goto out_fail; - } - - return NM_ACT_STAGE_RETURN_POSTPONE; - } - - if (!wake_on_wlan_enable(self)) - _LOGW(LOGD_DEVICE | LOGD_WIFI, "Cannot configure WoWLAN."); - - /* have secrets, or no secrets required */ - if (nm_connection_get_setting_wireless_security(connection)) { - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) connection '%s' has security, and secrets exist. No new secrets " - "needed.", - nm_connection_get_id(connection)); - } else { - _LOGI(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) connection '%s' requires no security. No secrets needed.", - nm_connection_get_id(connection)); - } - - priv->ssid_found = FALSE; - - /* Supplicant requires an initial frequency for Ad-Hoc, Hotspot and Mesh; - * if the user didn't specify one and we didn't find an AP that matched - * the connection, just pick a frequency the device supports. - */ - if (NM_IN_SET(ap_mode, NM_802_11_MODE_ADHOC, NM_802_11_MODE_MESH) || nm_wifi_ap_is_hotspot(ap)) - ensure_hotspot_frequency(self, s_wireless, ap); - - if (ap_mode == NM_802_11_MODE_INFRA) - set_powersave(device); - - /* Build up the supplicant configuration */ - config = build_supplicant_config(self, connection, nm_wifi_ap_get_freq(ap), &error); - if (!config) { - _LOGE(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) couldn't build wireless configuration: %s", - error->message); - g_clear_error(&error); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - goto out_fail; - } - - nm_supplicant_interface_assoc(priv->sup_iface, config, supplicant_iface_assoc_cb, self); - - /* Set up a timeout on the association attempt */ - timeout = nm_device_get_supplicant_timeout(NM_DEVICE(self)); - priv->sup_timeout_id = g_timeout_add_seconds(timeout, supplicant_connection_timeout_cb, self); - - if (!priv->periodic_update_id) - priv->periodic_update_id = g_timeout_add_seconds(6, periodic_update_cb, self); - - /* We'll get stage3 started when the supplicant connects */ - return NM_ACT_STAGE_RETURN_POSTPONE; - -out_fail: - cleanup_association_attempt(self, TRUE); - wake_on_wlan_restore(self); - return NM_ACT_STAGE_RETURN_FAILURE; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - gboolean indicate_addressing_running; - NMConnection *connection; - const char * method; - - connection = nm_device_get_applied_connection(device); - - method = nm_utils_get_ip_config_method(connection, addr_family); - if (addr_family == AF_INET) - indicate_addressing_running = NM_IN_STRSET(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - else { - indicate_addressing_running = NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_AUTO, - NM_SETTING_IP6_CONFIG_METHOD_DHCP); - } - - if (indicate_addressing_running) - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - TRUE); - - return NM_DEVICE_CLASS(nm_device_wifi_parent_class) - ->act_stage3_ip_config_start(device, addr_family, out_config, out_failure_reason); -} - -static guint32 -get_configured_mtu(NMDevice *device, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - return nm_device_get_configured_mtu_from_connection(device, - NM_TYPE_SETTING_WIRELESS, - out_source); -} - -static gboolean -is_static_wep(NMConnection *connection) -{ - NMSettingWirelessSecurity *s_wsec; - const char * str; - - g_return_val_if_fail(connection != NULL, FALSE); - - s_wsec = nm_connection_get_setting_wireless_security(connection); - if (!s_wsec) - return FALSE; - - str = nm_setting_wireless_security_get_key_mgmt(s_wsec); - if (g_strcmp0(str, "none") != 0) - return FALSE; - - str = nm_setting_wireless_security_get_auth_alg(s_wsec); - if (g_strcmp0(str, "leap") == 0) - return FALSE; - - return TRUE; -} - -static NMActStageReturn -act_stage4_ip_config_timeout(NMDevice * device, - int addr_family, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMConnection * connection; - NMSettingIPConfig * s_ip; - gboolean may_fail; - - connection = nm_device_get_applied_connection(device); - s_ip = nm_connection_get_setting_ip_config(connection, addr_family); - may_fail = nm_setting_ip_config_get_may_fail(s_ip); - - if (priv->mode == NM_802_11_MODE_AP) - goto call_parent; - - if (may_fail || !is_static_wep(connection)) { - /* Not static WEP or failure allowed; let superclass handle it */ - goto call_parent; - } - - /* If IP configuration times out and it's a static WEP connection, that - * usually means the WEP key is wrong. WEP's Open System auth mode has - * no provision for figuring out if the WEP key is wrong, so you just have - * to wait for DHCP to fail to figure it out. For all other Wi-Fi security - * types (open, WPA, 802.1x, etc) if the secrets/certs were wrong the - * connection would have failed before IP configuration. - * - * Activation failed, we must have bad encryption key */ - _LOGW(LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) could not get IP configuration for connection '%s'.", - nm_connection_get_id(connection)); - - if (!handle_auth_or_fail(self, NULL, TRUE)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - _LOGI(LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) asking for new secrets"); - return NM_ACT_STAGE_RETURN_POSTPONE; - -call_parent: - return NM_DEVICE_CLASS(nm_device_wifi_parent_class) - ->act_stage4_ip_config_timeout(device, addr_family, out_failure_reason); -} - -static void -activation_success_handler(NMDevice *device) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - int ifindex = nm_device_get_ifindex(device); - NMActRequest * req; - - req = nm_device_get_act_request(device); - g_assert(req); - - /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), ifindex, FALSE); - - /* There should always be a current AP, either a fake one because we haven't - * seen a scan result for the activated AP yet, or a real one from the - * supplicant's scan list. - */ - g_warn_if_fail(priv->current_ap); - if (priv->current_ap) { - if (nm_wifi_ap_get_fake(priv->current_ap)) { - gboolean ap_changed = FALSE; - - /* If the activation AP hasn't been seen by the supplicant in a scan - * yet, it will be "fake". This usually happens for Ad-Hoc and - * AP-mode connections. Fill in the details from the device itself - * until the supplicant sends the scan result. - */ - if (!nm_wifi_ap_get_address(priv->current_ap)) { - guint8 bssid[ETH_ALEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - gs_free char *bssid_str = NULL; - - if (nm_platform_wifi_get_bssid(nm_device_get_platform(device), ifindex, bssid) - && nm_ethernet_address_is_valid(bssid, ETH_ALEN)) { - bssid_str = nm_utils_hwaddr_ntoa(bssid, ETH_ALEN); - ap_changed |= nm_wifi_ap_set_address(priv->current_ap, bssid_str); - } - } - if (!nm_wifi_ap_get_freq(priv->current_ap)) - ap_changed |= nm_wifi_ap_set_freq( - priv->current_ap, - nm_platform_wifi_get_frequency(nm_device_get_platform(device), ifindex)); - if (!nm_wifi_ap_get_max_bitrate(priv->current_ap)) - ap_changed |= nm_wifi_ap_set_max_bitrate( - priv->current_ap, - nm_platform_wifi_get_rate(nm_device_get_platform(device), ifindex)); - - if (ap_changed) - _ap_dump(self, LOGL_DEBUG, priv->current_ap, "updated", 0); - } - - nm_active_connection_set_specific_object( - NM_ACTIVE_CONNECTION(req), - nm_dbus_object_get_path(NM_DBUS_OBJECT(priv->current_ap))); - } - - periodic_update(self); - - update_seen_bssids_cache(self, priv->current_ap); - - priv->scan_periodic_interval_sec = 0; - priv->scan_periodic_next_msec = 0; -} - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - gboolean clear_aps = FALSE; - - if (new_state > NM_DEVICE_STATE_ACTIVATED) - wifi_secrets_cancel(self); - - if (new_state <= NM_DEVICE_STATE_UNAVAILABLE) { - /* Clean up the supplicant interface because in these states the - * device cannot be used. - */ - supplicant_interface_release(self); - - nm_clear_g_source(&priv->periodic_update_id); - - cleanup_association_attempt(self, TRUE); - cleanup_supplicant_failures(self); - remove_all_aps(self); - } - - switch (new_state) { - case NM_DEVICE_STATE_UNMANAGED: - clear_aps = TRUE; - break; - case NM_DEVICE_STATE_UNAVAILABLE: - /* If the device is enabled and the supplicant manager is ready, - * acquire a supplicant interface and transition to DISCONNECTED because - * the device is now ready to use. - */ - if (priv->enabled && (nm_device_get_firmware_missing(device) == FALSE)) { - if (!priv->sup_iface) - supplicant_interface_acquire(self); - } - clear_aps = TRUE; - break; - case NM_DEVICE_STATE_NEED_AUTH: - if (priv->sup_iface) - nm_supplicant_interface_disconnect(priv->sup_iface); - break; - case NM_DEVICE_STATE_IP_CHECK: - /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), - nm_device_get_ifindex(device), - FALSE); - break; - case NM_DEVICE_STATE_ACTIVATED: - activation_success_handler(device); - break; - case NM_DEVICE_STATE_FAILED: - /* Clear any critical protocol notification in the wifi stack */ - nm_platform_wifi_indicate_addressing_running(nm_device_get_platform(device), - nm_device_get_ifindex(device), - FALSE); - break; - case NM_DEVICE_STATE_DISCONNECTED: - break; - default: - break; - } - - if (clear_aps) - remove_all_aps(self); - - _scan_notify_allowed(self, NM_TERNARY_DEFAULT); -} - -static gboolean -get_enabled(NMDevice *device) -{ - return NM_DEVICE_WIFI_GET_PRIVATE(device)->enabled; -} - -static void -set_enabled(NMDevice *device, gboolean enabled) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - NMDeviceState state; - - enabled = !!enabled; - - if (priv->enabled == enabled) - return; - - priv->enabled = enabled; - - _LOGD(LOGD_WIFI, "device now %s", enabled ? "enabled" : "disabled"); - - state = nm_device_get_state(NM_DEVICE(self)); - if (state < NM_DEVICE_STATE_UNAVAILABLE) { - _LOGD(LOGD_WIFI, "(%s): device blocked by UNMANAGED state", enabled ? "enable" : "disable"); - return; - } - - if (enabled) { - gboolean no_firmware = FALSE; - - if (state != NM_DEVICE_STATE_UNAVAILABLE) - _LOGW(LOGD_CORE, "not in expected unavailable state!"); - - if (!nm_device_bring_up(NM_DEVICE(self), TRUE, &no_firmware)) { - _LOGD(LOGD_WIFI, "enable blocked by failure to bring device up"); - - if (no_firmware) - nm_device_set_firmware_missing(NM_DEVICE(device), TRUE); - else { - /* The device sucks, or the kernel was lying to us about the killswitch state */ - priv->enabled = FALSE; - } - return; - } - - /* Re-initialize the supplicant interface and wait for it to be ready */ - cleanup_supplicant_failures(self); - supplicant_interface_release(self); - supplicant_interface_acquire(self); - - _LOGD(LOGD_WIFI, "enable waiting on supplicant state"); - } else { - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_NONE); - nm_device_take_down(NM_DEVICE(self), TRUE); - } -} - -static gboolean -get_guessed_metered(NMDevice *device) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - return priv->current_ap && nm_wifi_ap_get_metered(priv->current_ap); -} - -static gboolean -can_reapply_change(NMDevice * device, - const char *setting_name, - NMSetting * s_old, - NMSetting * s_new, - GHashTable *diffs, - GError ** error) -{ - NMDeviceClass *device_class; - - /* Only handle wireless setting here, delegate other settings to parent class */ - if (nm_streq(setting_name, NM_SETTING_WIRELESS_SETTING_NAME)) { - return nm_device_hash_check_invalid_keys( - diffs, - NM_SETTING_WIRELESS_SETTING_NAME, - error, - NM_SETTING_WIRELESS_SEEN_BSSIDS, /* ignored */ - NM_SETTING_WIRELESS_MTU, /* reapplied with IP config */ - NM_SETTING_WIRELESS_WAKE_ON_WLAN); - } - - device_class = NM_DEVICE_CLASS(nm_device_wifi_parent_class); - return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); -} - -static void -reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_new) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI(device); - NMDeviceState state = nm_device_get_state(device); - - NM_DEVICE_CLASS(nm_device_wifi_parent_class)->reapply_connection(device, con_old, con_new); - - _LOGD(LOGD_DEVICE, "reapplying wireless settings"); - - if (state >= NM_DEVICE_STATE_CONFIG && !wake_on_wlan_enable(self)) - _LOGW(LOGD_DEVICE | LOGD_WIFI, "Cannot configure WoWLAN."); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(object); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - const char ** list; - - switch (prop_id) { - case PROP_MODE: - g_value_set_uint(value, priv->mode); - break; - case PROP_BITRATE: - g_value_set_uint(value, priv->rate); - break; - case PROP_CAPABILITIES: - g_value_set_uint(value, priv->capabilities); - break; - case PROP_ACCESS_POINTS: - list = nm_wifi_aps_get_paths(&priv->aps_lst_head, TRUE); - g_value_take_boxed(value, nm_utils_strv_make_deep_copied(list)); - break; - case PROP_ACTIVE_ACCESS_POINT: - nm_dbus_utils_g_value_set_object_path(value, priv->current_ap); - break; - case PROP_SCANNING: - g_value_set_boolean(value, nm_device_wifi_get_scanning(self)); - break; - case PROP_LAST_SCAN: - g_value_set_int64( - value, - priv->scan_last_complete_msec > 0 - ? nm_utils_monotonic_timestamp_as_boottime(priv->scan_last_complete_msec, - NM_UTILS_NSEC_PER_MSEC) - : (gint64) -1); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMDeviceWifi * device = NM_DEVICE_WIFI(object); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(device); - - switch (prop_id) { - case PROP_CAPABILITIES: - /* construct-only */ - priv->capabilities = g_value_get_uint(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_wifi_init(NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - c_list_init(&priv->aps_lst_head); - c_list_init(&priv->scanning_prohibited_lst_head); - c_list_init(&priv->scan_request_ssids_lst_head); - priv->aps_idx_by_supplicant_path = g_hash_table_new(nm_direct_hash, NULL); - - priv->scan_last_request_started_at_msec = G_MININT64; - priv->hidden_probe_scan_warn = TRUE; - priv->mode = NM_802_11_MODE_INFRA; - priv->wowlan_restore = NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE; -} - -static void -constructed(GObject *object) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(object); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - G_OBJECT_CLASS(nm_device_wifi_parent_class)->constructed(object); - - if (priv->capabilities & NM_WIFI_DEVICE_CAP_AP) - _LOGI(LOGD_PLATFORM | LOGD_WIFI, "driver supports Access Point (AP) mode"); - - /* Connect to the supplicant manager */ - priv->sup_mgr = g_object_ref(nm_supplicant_manager_get()); -} - -NMDevice * -nm_device_wifi_new(const char *iface, NMDeviceWifiCapabilities capabilities) -{ - return g_object_new(NM_TYPE_DEVICE_WIFI, - NM_DEVICE_IFACE, - iface, - NM_DEVICE_TYPE_DESC, - "802.11 Wi-Fi", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_WIFI, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_WIFI, - NM_DEVICE_RFKILL_TYPE, - RFKILL_TYPE_WLAN, - NM_DEVICE_WIFI_CAPABILITIES, - (guint) capabilities, - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(object); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - nm_assert(c_list_is_empty(&priv->scanning_prohibited_lst_head)); - - nm_clear_g_source(&priv->periodic_update_id); - - wifi_secrets_cancel(self); - - cleanup_association_attempt(self, TRUE); - supplicant_interface_release(self); - cleanup_supplicant_failures(self); - - g_clear_object(&priv->sup_mgr); - - remove_all_aps(self); - - if (priv->p2p_device) { - /* Destroy the P2P device. */ - g_object_remove_weak_pointer(G_OBJECT(priv->p2p_device), (gpointer *) &priv->p2p_device); - nm_device_wifi_p2p_remove(g_steal_pointer(&priv->p2p_device)); - } - - G_OBJECT_CLASS(nm_device_wifi_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMDeviceWifi * self = NM_DEVICE_WIFI(object); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE(self); - - nm_assert(c_list_is_empty(&priv->aps_lst_head)); - nm_assert(g_hash_table_size(priv->aps_idx_by_supplicant_path) == 0); - - g_hash_table_unref(priv->aps_idx_by_supplicant_path); - - G_OBJECT_CLASS(nm_device_wifi_parent_class)->finalize(object); -} - -static void -nm_device_wifi_class_init(NMDeviceWifiClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->constructed = constructed; - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - dbus_object_class->interface_infos = - NM_DBUS_INTERFACE_INFOS(&nm_interface_info_device_wireless); - - device_class->connection_type_supported = NM_SETTING_WIRELESS_SETTING_NAME; - device_class->connection_type_check_compatible = NM_SETTING_WIRELESS_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_WIFI); - - device_class->can_auto_connect = can_auto_connect; - device_class->get_autoconnect_allowed = get_autoconnect_allowed; - device_class->is_available = is_available; - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - device_class->get_enabled = get_enabled; - device_class->get_guessed_metered = get_guessed_metered; - device_class->set_enabled = set_enabled; - - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->get_configured_mtu = get_configured_mtu; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->act_stage4_ip_config_timeout = act_stage4_ip_config_timeout; - device_class->deactivate_async = deactivate_async; - device_class->deactivate = deactivate; - device_class->deactivate_reset_hw_addr = deactivate_reset_hw_addr; - device_class->unmanaged_on_quit = unmanaged_on_quit; - device_class->can_reapply_change = can_reapply_change; - device_class->reapply_connection = reapply_connection; - - device_class->state_changed = device_state_changed; - - obj_properties[PROP_MODE] = g_param_spec_uint(NM_DEVICE_WIFI_MODE, - "", - "", - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_AP, - NM_802_11_MODE_INFRA, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BITRATE] = g_param_spec_uint(NM_DEVICE_WIFI_BITRATE, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ACCESS_POINTS] = - g_param_spec_boxed(NM_DEVICE_WIFI_ACCESS_POINTS, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ACTIVE_ACCESS_POINT] = - g_param_spec_string(NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_CAPABILITIES] = - g_param_spec_uint(NM_DEVICE_WIFI_CAPABILITIES, - "", - "", - 0, - G_MAXUINT32, - NM_WIFI_DEVICE_CAP_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SCANNING] = g_param_spec_boolean(NM_DEVICE_WIFI_SCANNING, - "", - "", - FALSE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LAST_SCAN] = g_param_spec_int64(NM_DEVICE_WIFI_LAST_SCAN, - "", - "", - -1, - G_MAXINT64, - -1, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[P2P_DEVICE_CREATED] = g_signal_new(NM_DEVICE_WIFI_P2P_DEVICE_CREATED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, - 1, - NM_TYPE_DEVICE); -} diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h deleted file mode 100644 index 713c1480..00000000 --- a/src/devices/wifi/nm-device-wifi.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2005 - 2016 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_WIFI_H__ -#define __NETWORKMANAGER_DEVICE_WIFI_H__ - -#include "devices/nm-device.h" - -#define NM_TYPE_DEVICE_WIFI (nm_device_wifi_get_type()) -#define NM_DEVICE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifi)) -#define NM_DEVICE_WIFI_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_WIFI, NMDeviceWifiClass)) -#define NM_IS_DEVICE_WIFI(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_WIFI)) -#define NM_IS_DEVICE_WIFI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_WIFI)) -#define NM_DEVICE_WIFI_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_WIFI, NMDeviceWifiClass)) - -#define NM_DEVICE_WIFI_MODE "mode" -#define NM_DEVICE_WIFI_BITRATE "bitrate" -#define NM_DEVICE_WIFI_ACCESS_POINTS "access-points" -#define NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT "active-access-point" -#define NM_DEVICE_WIFI_CAPABILITIES "wireless-capabilities" -#define NM_DEVICE_WIFI_SCANNING "scanning" -#define NM_DEVICE_WIFI_LAST_SCAN "last-scan" - -#define NM_DEVICE_WIFI_P2P_DEVICE_CREATED "p2p-device-created" - -typedef struct _NMDeviceWifi NMDeviceWifi; -typedef struct _NMDeviceWifiClass NMDeviceWifiClass; - -GType nm_device_wifi_get_type(void); - -NMDevice *nm_device_wifi_new(const char *iface, NMDeviceWifiCapabilities capabilities); - -const CList *_nm_device_wifi_get_aps(NMDeviceWifi *self); - -void _nm_device_wifi_request_scan(NMDeviceWifi * self, - GVariant * options, - GDBusMethodInvocation *invocation); - -GPtrArray *nmtst_ssids_options_to_ptrarray(GVariant *value, GError **error); - -gboolean nm_device_wifi_get_scanning(NMDeviceWifi *self); - -void nm_device_wifi_scanning_prohibited_track(NMDeviceWifi *self, - gpointer tag, - gboolean temporarily_prohibited); - -#endif /* __NETWORKMANAGER_DEVICE_WIFI_H__ */ diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c deleted file mode 100644 index c7e99e0b..00000000 --- a/src/devices/wifi/nm-iwd-manager.c +++ /dev/null @@ -1,990 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Intel Corporation - */ - -#include "nm-default.h" - -#include "nm-iwd-manager.h" - -#include <net/if.h> - -#include "nm-logging.h" -#include "nm-core-internal.h" -#include "nm-manager.h" -#include "nm-device-iwd.h" -#include "nm-wifi-utils.h" -#include "nm-glib-aux/nm-random-utils.h" -#include "settings/nm-settings.h" - -/*****************************************************************************/ - -typedef struct { - const char * name; - NMIwdNetworkSecurity security; - char buf[0]; -} KnownNetworkId; - -typedef struct { - GDBusProxy * known_network; - NMSettingsConnection *mirror_connection; -} KnownNetworkData; - -typedef struct { - NMManager * manager; - NMSettings * settings; - GCancellable * cancellable; - gboolean running; - GDBusObjectManager *object_manager; - guint agent_id; - char * agent_path; - GHashTable * known_networks; -} NMIwdManagerPrivate; - -struct _NMIwdManager { - GObject parent; - NMIwdManagerPrivate _priv; -}; - -struct _NMIwdManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT) - -#define NM_IWD_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIwdManager, NM_IS_IWD_MANAGER) - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "iwd-manager" -#define _NMLOG_DOMAIN LOGD_WIFI - -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - if (nm_logging_enabled(level, _NMLOG_DOMAIN)) { \ - char __prefix[32]; \ - \ - if (self) \ - g_snprintf(__prefix, \ - sizeof(__prefix), \ - "%s[%p]", \ - ""_NMLOG_PREFIX_NAME \ - "", \ - (self)); \ - else \ - g_strlcpy(__prefix, _NMLOG_PREFIX_NAME, sizeof(__prefix)); \ - _nm_log((level), \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -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, - const char * interface_name, - const char * method_name, - GVariant * parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) -{ - NMIwdManager * self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - const char * network_path, *device_path, *ifname; - gs_unref_object GDBusInterface *network = NULL, *device_obj = NULL; - int ifindex; - NMDevice * device; - gs_free char * name_owner = NULL; - int errsv; - - /* Be paranoid and check the sender address */ - name_owner = g_dbus_object_manager_client_get_name_owner( - G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager)); - if (!nm_streq0(name_owner, sender)) - goto return_error; - - if (!strcmp(method_name, "RequestUserPassword")) - g_variant_get(parameters, "(&os)", &network_path, NULL); - else - g_variant_get(parameters, "(&o)", &network_path); - - network = g_dbus_object_manager_get_interface(priv->object_manager, - network_path, - NM_IWD_NETWORK_INTERFACE); - if (!network) { - _LOGE("unable to find the network object"); - return; - } - - 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); - goto return_error; - } - - device_obj = g_dbus_object_manager_get_interface(priv->object_manager, - device_path, - NM_IWD_DEVICE_INTERFACE); - - 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); - goto return_error; - } - - ifindex = if_nametoindex(ifname); - if (!ifindex) { - errsv = errno; - _LOGD("agent-request: if_nametoindex failed for Name %s for Device at %s: %i", - ifname, - device_path, - errsv); - goto return_error; - } - - device = nm_manager_get_device_by_ifindex(priv->manager, ifindex); - if (!NM_IS_DEVICE_IWD(device)) { - _LOGD("agent-request: IWD device named %s is not a Wifi device in IWD Agent request", - ifname); - goto return_error; - } - - if (nm_device_iwd_agent_query(NM_DEVICE_IWD(device), invocation)) - return; - - _LOGD("agent-request: device %s did not handle the IWD Agent request", ifname); - -return_error: - /* IWD doesn't look at the specific error */ - g_dbus_method_invocation_return_error_literal(invocation, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "Secrets not available for this connection"); -} - -static const GDBusInterfaceInfo iwd_agent_iface_info = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - "net.connman.iwd.Agent", - .methods = NM_DEFINE_GDBUS_METHOD_INFOS( - NM_DEFINE_GDBUS_METHOD_INFO( - "RequestPassphrase", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("network", "o"), ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("passphrase", "s"), ), ), - NM_DEFINE_GDBUS_METHOD_INFO( - "RequestPrivateKeyPassphrase", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("network", "o"), ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("passphrase", "s"), ), ), - NM_DEFINE_GDBUS_METHOD_INFO( - "RequestUserNameAndPassword", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("network", "o"), ), - .out_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("user", "s"), - NM_DEFINE_GDBUS_ARG_INFO("password", "s"), ), ), - NM_DEFINE_GDBUS_METHOD_INFO( - "RequestUserPassword", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("network", "o"), - NM_DEFINE_GDBUS_ARG_INFO("user", "s"), ), - .out_args = - NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("password", "s"), ), ), ), ); - -static guint -iwd_agent_export(GDBusConnection *connection, gpointer user_data, char **agent_path, GError **error) -{ - static const GDBusInterfaceVTable vtable = { - .method_call = agent_dbus_method_cb, - }; - char path[50]; - unsigned int rnd; - guint id; - - nm_utils_random_bytes(&rnd, sizeof(rnd)); - - nm_sprintf_buf(path, "/agent/%u", rnd); - - id = - g_dbus_connection_register_object(connection, - path, - NM_UNCONST_PTR(GDBusInterfaceInfo, &iwd_agent_iface_info), - &vtable, - user_data, - NULL, - error); - - if (id) - *agent_path = g_strdup(path); - return id; -} - -static void -register_agent(NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - GDBusInterface * agent_manager; - - agent_manager = g_dbus_object_manager_get_interface(priv->object_manager, - "/net/connman/iwd", - NM_IWD_AGENT_MANAGER_INTERFACE); - - if (!agent_manager) { - /* IWD prior to 1.0 dated 30 October, 2019 has the agent manager on a - * different path. */ - agent_manager = g_dbus_object_manager_get_interface(priv->object_manager, - "/", - NM_IWD_AGENT_MANAGER_INTERFACE); - } - - if (!agent_manager) { - _LOGE("unable to register the IWD Agent: PSK/8021x Wi-Fi networks may not work"); - return; - } - - /* Register our agent */ - g_dbus_proxy_call(G_DBUS_PROXY(agent_manager), - "RegisterAgent", - g_variant_new("(o)", priv->agent_path), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - NULL, - NULL); - - g_object_unref(agent_manager); -} - -/*****************************************************************************/ - -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 -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); - const char * ifname; - int ifindex; - NMDevice * device; - int errsv; - - 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; - } - - ifindex = if_nametoindex(ifname); - - if (!ifindex) { - errsv = errno; - _LOGE("if_nametoindex failed for Name %s for Device at %s: %i", - ifname, - g_dbus_proxy_get_object_path(proxy), - errsv); - return; - } - - device = nm_manager_get_device_by_ifindex(priv->manager, ifindex); - if (!NM_IS_DEVICE_IWD(device)) { - _LOGE("IWD device named %s is not a Wifi device", ifname); - return; - } - - nm_device_iwd_set_dbus_object(NM_DEVICE_IWD(device), object); -} - -/* Look up an existing NMSettingsConnection for a WPA2-Enterprise network - * that has been preprovisioned with an IWD config file, or create a new - * in-memory connection object so that NM autoconnect mechanism and the - * clients know this networks needs no additional EAP configuration from - * the user. - */ -static NMSettingsConnection * -mirror_8021x_connection(NMIwdManager *self, const char *name, gboolean create_new) -{ - NMIwdManagerPrivate * priv = NM_IWD_MANAGER_GET_PRIVATE(self); - NMSettingsConnection *const *iter; - gs_unref_object NMConnection *connection = NULL; - NMSettingsConnection * settings_connection = NULL; - char uuid[37]; - NMSetting * setting; - GError * error = NULL; - gs_unref_bytes GBytes *new_ssid = NULL; - - for (iter = nm_settings_get_connections(priv->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; - NMSetting8021x * s_8021x; - gboolean external = FALSE; - guint i; - - 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)); - - if (!nm_streq(ssid_name, name)) - continue; - - s_8021x = nm_connection_get_setting_802_1x(conn); - for (i = 0; i < nm_setting_802_1x_get_num_eap_methods(s_8021x); i++) { - if (nm_streq(nm_setting_802_1x_get_eap_method(s_8021x, i), "external")) { - external = TRUE; - break; - } - } - - /* Prefer returning connections for EAP method "external" */ - if (!settings_connection || external) - settings_connection = sett_conn; - } - - /* If we already have an NMSettingsConnection matching this - * KnownNetwork, whether it's saved or an in-memory connection - * potentially created by ourselves then we have nothing left to - * do here. - */ - if (settings_connection || !create_new) - return settings_connection; - - 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), - 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); - - /* "password" and "private-key-password" may be requested by the IWD agent - * from NM and IWD will implement a specific secret cache policy so by - * default respect that policy and don't save copies of those secrets in - * NM settings. The saved values can not be used anyway because of our - * use of NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW. - */ - setting = NM_SETTING(g_object_new(NM_TYPE_SETTING_802_1X, - NM_SETTING_802_1X_PASSWORD_FLAGS, - NM_SETTING_SECRET_FLAG_NOT_SAVED, - NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS, - NM_SETTING_SECRET_FLAG_NOT_SAVED, - 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; - - if (!nm_settings_add_connection(priv->settings, - connection, - NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, - NM_SETTINGS_CONNECTION_ADD_REASON_NONE, - NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, - &settings_connection, - &error)) { - _LOGW("failed to add a mirror NMConnection for IWD's Known Network '%s': %s", - name, - error->message); - g_error_free(error); - return NULL; - } - - 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, FALSE); - - 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; - - 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) { - _LOGW("DBus error: KnownNetwork already exists ('%s', %s)", name, type_str); - g_free(id); - nm_g_object_ref_set(&data->known_network, proxy); - } 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, TRUE); - - 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 -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; - - 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, 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 void -object_added(GDBusObjectManager *object_manager, GDBusObject *object, gpointer user_data) -{ - GList *interfaces, *iter; - - interfaces = g_dbus_object_get_interfaces(object); - - for (iter = interfaces; iter; iter = iter->next) { - GDBusInterface *interface = G_DBUS_INTERFACE(iter->data); - - interface_added(NULL, object, interface, user_data); - } - - g_list_free_full(interfaces, g_object_unref); -} - -static void -object_removed(GDBusObjectManager *object_manager, GDBusObject *object, gpointer user_data) -{ - GList *interfaces, *iter; - - interfaces = g_dbus_object_get_interfaces(object); - - for (iter = interfaces; iter; iter = iter->next) { - GDBusInterface *interface = G_DBUS_INTERFACE(iter->data); - - interface_removed(NULL, object, interface, user_data); - } - - g_list_free_full(interfaces, g_object_unref); -} - -static void -connection_removed(NMSettings *settings, NMSettingsConnection *sett_conn, gpointer user_data) -{ - NMIwdManager * self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - NMConnection * conn = nm_settings_connection_get_connection(sett_conn); - NMSettingWireless * s_wireless; - gboolean mapped; - KnownNetworkData * data; - KnownNetworkId id; - gs_free char * ssid_str = NULL; - - id.security = nm_wifi_connection_get_iwd_security(conn, &mapped); - if (!mapped) - return; - - s_wireless = nm_connection_get_setting_wireless(conn); - ssid_str = _nm_utils_ssid_to_utf8(nm_setting_wireless_get_ssid(s_wireless)); - id.name = ssid_str; - data = g_hash_table_lookup(priv->known_networks, &id); - if (!data) - return; - - if (id.security == NM_IWD_NETWORK_SECURITY_8021X) { - NMSettingsConnection *new_mirror_conn; - - if (data->mirror_connection != sett_conn) - return; - - g_clear_object(&data->mirror_connection); - - /* Don't call Forget for an 8021x network until there's no - * longer *any* matching NMSettingsConnection (debatable) - */ - new_mirror_conn = mirror_8021x_connection(self, id.name, FALSE); - if (new_mirror_conn) { - data->mirror_connection = g_object_ref(new_mirror_conn); - return; - } - } - - if (!priv->running) - return; - - g_dbus_proxy_call(data->known_network, - "Forget", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - NULL, - NULL); -} - -static gboolean -_om_has_name_owner(GDBusObjectManager *object_manager) -{ - gs_free char *name_owner = NULL; - - nm_assert(G_IS_DBUS_OBJECT_MANAGER_CLIENT(object_manager)); - - name_owner = - g_dbus_object_manager_client_get_name_owner(G_DBUS_OBJECT_MANAGER_CLIENT(object_manager)); - return !!name_owner; -} - -static void -release_object_manager(NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - - if (!priv->object_manager) - return; - - g_signal_handlers_disconnect_by_data(priv->object_manager, self); - - if (priv->agent_id) { - GDBusConnection * agent_connection; - GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT(priv->object_manager); - - agent_connection = g_dbus_object_manager_client_get_connection(omc); - - /* We're is called when we're shutting down (i.e. our DBus connection - * is being closed, and IWD will detect this) or IWD was stopped so - * in either case calling UnregisterAgent will not do anything. - */ - g_dbus_connection_unregister_object(agent_connection, priv->agent_id); - priv->agent_id = 0; - nm_clear_g_free(&priv->agent_path); - } - - g_clear_object(&priv->object_manager); -} - -static void prepare_object_manager(NMIwdManager *self); - -static void -name_owner_changed(GObject *object, GParamSpec *pspec, gpointer user_data) -{ - NMIwdManager * self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - GDBusObjectManager * object_manager = G_DBUS_OBJECT_MANAGER(object); - - nm_assert(object_manager == priv->object_manager); - - if (_om_has_name_owner(object_manager)) { - release_object_manager(self); - prepare_object_manager(self); - } else { - const CList *tmp_lst; - NMDevice * device; - - if (!priv->running) - return; - - priv->running = false; - - nm_manager_for_each_device (priv->manager, device, tmp_lst) { - if (NM_IS_DEVICE_IWD(device)) { - nm_device_iwd_set_dbus_object(NM_DEVICE_IWD(device), NULL); - } - } - } -} - -static void -device_added(NMManager *manager, NMDevice *device, gpointer user_data) -{ - NMIwdManager * self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - GList * objects, *iter; - - if (!NM_IS_DEVICE_IWD(device)) - return; - - if (!priv->running) - return; - - objects = g_dbus_object_manager_get_objects(priv->object_manager); - for (iter = objects; iter; iter = iter->next) { - GDBusObject * object = G_DBUS_OBJECT(iter->data); - gs_unref_object GDBusInterface *interface = NULL; - const char * obj_ifname; - - interface = g_dbus_object_get_interface(object, NM_IWD_DEVICE_INTERFACE); - obj_ifname = get_property_string_or_null((GDBusProxy *) interface, "Name"); - - if (!obj_ifname || strcmp(nm_device_get_iface(device), obj_ifname)) - continue; - - nm_device_iwd_set_dbus_object(NM_DEVICE_IWD(device), object); - break; - } - - g_list_free_full(objects, g_object_unref); -} - -static void -got_object_manager(GObject *object, GAsyncResult *result, gpointer user_data) -{ - NMIwdManager * self = user_data; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - GError * error = NULL; - GDBusObjectManager * object_manager; - GDBusConnection * connection; - - 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)", - error->message); - g_clear_error(&error); - return; - } - - priv->object_manager = object_manager; - - g_signal_connect(priv->object_manager, - "notify::name-owner", - G_CALLBACK(name_owner_changed), - self); - - nm_assert(G_IS_DBUS_OBJECT_MANAGER_CLIENT(object_manager)); - - 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); - if (!priv->agent_id) { - _LOGE("failed to export the IWD Agent: PSK/8021x Wi-Fi networks may not work: %s", - error->message); - g_clear_error(&error); - } - - if (_om_has_name_owner(object_manager)) { - GList *objects, *iter; - - priv->running = true; - - g_signal_connect(priv->object_manager, - "interface-added", - G_CALLBACK(interface_added), - self); - g_signal_connect(priv->object_manager, - "interface-removed", - G_CALLBACK(interface_removed), - self); - g_signal_connect(priv->object_manager, "object-added", G_CALLBACK(object_added), self); - g_signal_connect(priv->object_manager, "object-removed", G_CALLBACK(object_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(NULL, G_DBUS_OBJECT(iter->data), self); - - g_list_free_full(objects, g_object_unref); - - if (priv->agent_id) - register_agent(self); - } -} - -static void -prepare_object_manager(NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - - g_dbus_object_manager_client_new_for_bus(NM_IWD_BUS_TYPE, - G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, - NM_IWD_SERVICE, - "/", - NULL, - NULL, - NULL, - priv->cancellable, - got_object_manager, - self); -} - -gboolean -nm_iwd_manager_is_known_network(NMIwdManager *self, const char *name, NMIwdNetworkSecurity security) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - KnownNetworkId kn_id = {name, security}; - - return g_hash_table_contains(priv->known_networks, &kn_id); -} - -GDBusProxy * -nm_iwd_manager_get_dbus_interface(NMIwdManager *self, const char *path, const char *name) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - GDBusInterface * interface; - - if (!priv->object_manager) - return NULL; - - interface = g_dbus_object_manager_get_interface(priv->object_manager, path, name); - - return interface ? G_DBUS_PROXY(interface) : NULL; -} - -/*****************************************************************************/ - -NM_DEFINE_SINGLETON_GETTER(NMIwdManager, nm_iwd_manager_get, NM_TYPE_IWD_MANAGER); - -static void -nm_iwd_manager_init(NMIwdManager *self) -{ - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - - priv->manager = g_object_ref(NM_MANAGER_GET); - g_signal_connect(priv->manager, NM_MANAGER_DEVICE_ADDED, G_CALLBACK(device_added), self); - - priv->settings = g_object_ref(NM_SETTINGS_GET); - g_signal_connect(priv->settings, - NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK(connection_removed), - 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); -} - -static void -dispose(GObject *object) -{ - NMIwdManager * self = (NMIwdManager *) object; - NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE(self); - - release_object_manager(self); - - nm_clear_g_cancellable(&priv->cancellable); - - if (priv->settings) { - g_signal_handlers_disconnect_by_data(priv->settings, self); - g_clear_object(&priv->settings); - } - - /* This may trigger mirror connection removals so it happens - * after the g_signal_handlers_disconnect_by_data above. - */ - nm_clear_pointer(&priv->known_networks, g_hash_table_destroy); - - if (priv->manager) { - g_signal_handlers_disconnect_by_data(priv->manager, self); - g_clear_object(&priv->manager); - } - - G_OBJECT_CLASS(nm_iwd_manager_parent_class)->dispose(object); -} - -static void -nm_iwd_manager_class_init(NMIwdManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->dispose = dispose; -} diff --git a/src/devices/wifi/nm-iwd-manager.h b/src/devices/wifi/nm-iwd-manager.h deleted file mode 100644 index 00f0c304..00000000 --- a/src/devices/wifi/nm-iwd-manager.h +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2017 Intel Corporation - */ - -#ifndef __NETWORKMANAGER_IWD_MANAGER_H__ -#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" - -#define NM_IWD_AGENT_MANAGER_INTERFACE "net.connman.iwd.AgentManager" -#define NM_IWD_WIPHY_INTERFACE "net.connman.iwd.Adapter" -#define NM_IWD_DEVICE_INTERFACE "net.connman.iwd.Device" -#define NM_IWD_NETWORK_INTERFACE "net.connman.iwd.Network" -#define NM_IWD_AGENT_INTERFACE "net.connman.iwd.Agent" -#define NM_IWD_WSC_INTERFACE "net.connman.iwd.WiFiSimpleConfiguration" -#define NM_IWD_KNOWN_NETWORK_INTERFACE "net.connman.iwd.KnownNetwork" -#define NM_IWD_SIGNAL_AGENT_INTERFACE "net.connman.iwd.SignalLevelAgent" -#define NM_IWD_AP_INTERFACE "net.connman.iwd.AccessPoint" -#define NM_IWD_ADHOC_INTERFACE "net.connman.iwd.AdHoc" -#define NM_IWD_STATION_INTERFACE "net.connman.iwd.Station" - -#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)) -#define NM_IS_IWD_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_IWD_MANAGER)) -#define NM_IS_IWD_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_IWD_MANAGER)) -#define NM_IWD_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_IWD_MANAGER, NMIwdManagerClass)) - -typedef struct _NMIwdManager NMIwdManager; -typedef struct _NMIwdManagerClass NMIwdManagerClass; - -GType nm_iwd_manager_get_type(void); - -NMIwdManager *nm_iwd_manager_get(void); - -gboolean nm_iwd_manager_is_known_network(NMIwdManager * self, - const char * name, - NMIwdNetworkSecurity security); - -GDBusProxy * -nm_iwd_manager_get_dbus_interface(NMIwdManager *self, const char *path, const char *name); - -#endif /* __NETWORKMANAGER_IWD_MANAGER_H__ */ diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c deleted file mode 100644 index 55438a53..00000000 --- a/src/devices/wifi/nm-wifi-ap.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2004 - 2017 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "nm-default.h" - -#include "nm-wifi-ap.h" - -#include <stdlib.h> - -#include "NetworkManagerUtils.h" -#include "devices/nm-device.h" -#include "nm-core-internal.h" -#include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" -#include "nm-setting-wireless.h" -#include "nm-utils.h" -#include "nm-wifi-utils.h" -#include "platform/nm-platform.h" -#include "supplicant/nm-supplicant-interface.h" - -#define PROTO_WPA "wpa" -#define PROTO_RSN "rsn" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMWifiAP, - PROP_FLAGS, - PROP_WPA_FLAGS, - PROP_RSN_FLAGS, - PROP_SSID, - PROP_FREQUENCY, - PROP_HW_ADDRESS, - PROP_MODE, - PROP_MAX_BITRATE, - PROP_STRENGTH, - PROP_LAST_SEEN, ); - -struct _NMWifiAPPrivate { - /* Scanned or cached values */ - GBytes * ssid; - char * address; - NM80211Mode mode; - guint8 strength; - guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */ - guint32 max_bitrate; /* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */ - - gint64 - last_seen_msec; /* Timestamp when the AP was seen lastly (in nm_utils_get_monotonic_timestamp_*() scale). - * Note that this value might be negative! */ - - NM80211ApFlags flags; /* General flags */ - NM80211ApSecurityFlags wpa_flags; /* WPA-related flags */ - NM80211ApSecurityFlags rsn_flags; /* RSN (WPA2) -related flags */ - - bool metered : 1; - - /* Non-scanned attributes */ - bool fake : 1; /* Whether or not the AP is from a scan */ - bool hotspot : 1; /* Whether the AP is a local device's hotspot network */ -}; - -typedef struct _NMWifiAPPrivate NMWifiAPPrivate; - -struct _NMWifiAPClass { - NMDBusObjectClass parent; -}; - -G_DEFINE_TYPE(NMWifiAP, nm_wifi_ap, NM_TYPE_DBUS_OBJECT) - -#define NM_WIFI_AP_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMWifiAP, NM_IS_WIFI_AP) - -/*****************************************************************************/ - -GBytes * -nm_wifi_ap_get_ssid(const NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), NULL); - - return NM_WIFI_AP_GET_PRIVATE(ap)->ssid; -} - -gboolean -nm_wifi_ap_set_ssid_arr(NMWifiAP *ap, const guint8 *ssid, gsize ssid_len) -{ - NMWifiAPPrivate *priv; - - g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); - - if (ssid_len > 32) - g_return_val_if_reached(FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (nm_utils_gbytes_equal_mem(priv->ssid, ssid, ssid_len)) - return FALSE; - - nm_clear_pointer(&priv->ssid, g_bytes_unref); - if (ssid_len > 0) - priv->ssid = g_bytes_new(ssid, ssid_len); - - _notify(ap, PROP_SSID); - return TRUE; -} - -gboolean -nm_wifi_ap_set_ssid(NMWifiAP *ap, GBytes *ssid) -{ - NMWifiAPPrivate *priv; - gsize l; - - g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); - - if (!ssid) { - /* we don't clear the SSID, once we have it. We can only update - * it by a better value. */ - return FALSE; - } - - l = g_bytes_get_size(ssid); - if (l == 0 || l > 32) - g_return_val_if_reached(FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (ssid == priv->ssid) - return FALSE; - if (priv->ssid && g_bytes_equal(ssid, priv->ssid)) - return FALSE; - - g_bytes_ref(ssid); - nm_clear_pointer(&priv->ssid, g_bytes_unref); - priv->ssid = ssid; - - _notify(ap, PROP_SSID); - return TRUE; -} - -static gboolean -nm_wifi_ap_set_flags(NMWifiAP *ap, NM80211ApFlags flags) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (priv->flags != flags) { - priv->flags = flags; - _notify(ap, PROP_FLAGS); - return TRUE; - } - return FALSE; -} - -static gboolean -nm_wifi_ap_set_wpa_flags(NMWifiAP *ap, NM80211ApSecurityFlags flags) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (priv->wpa_flags != flags) { - priv->wpa_flags = flags; - _notify(ap, PROP_WPA_FLAGS); - return TRUE; - } - return FALSE; -} - -static gboolean -nm_wifi_ap_set_rsn_flags(NMWifiAP *ap, NM80211ApSecurityFlags flags) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (priv->rsn_flags != flags) { - priv->rsn_flags = flags; - _notify(ap, PROP_RSN_FLAGS); - return TRUE; - } - return FALSE; -} - -const char * -nm_wifi_ap_get_address(const NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), NULL); - - return NM_WIFI_AP_GET_PRIVATE(ap)->address; -} - -static gboolean -nm_wifi_ap_set_address_bin(NMWifiAP *ap, const guint8 addr[static 6 /* ETH_ALEN */]) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (!priv->address || !nm_utils_hwaddr_matches(addr, ETH_ALEN, priv->address, -1)) { - g_free(priv->address); - priv->address = nm_utils_hwaddr_ntoa(addr, ETH_ALEN); - _notify(ap, PROP_HW_ADDRESS); - return TRUE; - } - return FALSE; -} - -gboolean -nm_wifi_ap_set_address(NMWifiAP *ap, const char *addr) -{ - guint8 addr_buf[ETH_ALEN]; - - g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); - if (!addr || !nm_utils_hwaddr_aton(addr, addr_buf, sizeof(addr_buf))) - g_return_val_if_reached(FALSE); - - return nm_wifi_ap_set_address_bin(ap, addr_buf); -} - -NM80211Mode -nm_wifi_ap_get_mode(NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), NM_802_11_MODE_UNKNOWN); - - return NM_WIFI_AP_GET_PRIVATE(ap)->mode; -} - -static gboolean -nm_wifi_ap_set_mode(NMWifiAP *ap, NM80211Mode mode) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); - - nm_assert(NM_IN_SET(mode, - NM_802_11_MODE_UNKNOWN, - NM_802_11_MODE_ADHOC, - NM_802_11_MODE_INFRA, - NM_802_11_MODE_MESH)); - - if (priv->mode != mode) { - priv->mode = mode; - _notify(ap, PROP_MODE); - return TRUE; - } - return FALSE; -} - -gboolean -nm_wifi_ap_is_hotspot(NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); - - return NM_WIFI_AP_GET_PRIVATE(ap)->hotspot; -} - -gint8 -nm_wifi_ap_get_strength(NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), 0); - - return NM_WIFI_AP_GET_PRIVATE(ap)->strength; -} - -gboolean -nm_wifi_ap_set_strength(NMWifiAP *ap, gint8 strength) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (priv->strength != strength) { - priv->strength = strength; - _notify(ap, PROP_STRENGTH); - return TRUE; - } - return FALSE; -} - -guint32 -nm_wifi_ap_get_freq(NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), 0); - - return NM_WIFI_AP_GET_PRIVATE(ap)->freq; -} - -gboolean -nm_wifi_ap_set_freq(NMWifiAP *ap, guint32 freq) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (priv->freq != freq) { - priv->freq = freq; - _notify(ap, PROP_FREQUENCY); - return TRUE; - } - return FALSE; -} - -guint32 -nm_wifi_ap_get_max_bitrate(NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), 0); - g_return_val_if_fail(nm_dbus_object_is_exported(NM_DBUS_OBJECT(ap)), 0); - - return NM_WIFI_AP_GET_PRIVATE(ap)->max_bitrate; -} - -gboolean -nm_wifi_ap_set_max_bitrate(NMWifiAP *ap, guint32 bitrate) -{ - NMWifiAPPrivate *priv; - - g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (priv->max_bitrate != bitrate) { - priv->max_bitrate = bitrate; - _notify(ap, PROP_MAX_BITRATE); - return TRUE; - } - return FALSE; -} - -gboolean -nm_wifi_ap_get_fake(const NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); - - return NM_WIFI_AP_GET_PRIVATE(ap)->fake; -} - -gboolean -nm_wifi_ap_set_fake(NMWifiAP *ap, gboolean fake) -{ - NMWifiAPPrivate *priv; - - g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (priv->fake != !!fake) { - priv->fake = fake; - return TRUE; - } - return FALSE; -} - -NM80211ApFlags -nm_wifi_ap_get_flags(const NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), NM_802_11_AP_FLAGS_NONE); - - return NM_WIFI_AP_GET_PRIVATE(ap)->flags; -} - -static gboolean -nm_wifi_ap_set_last_seen(NMWifiAP *ap, gint32 last_seen_msec) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(ap); - - if (priv->last_seen_msec != last_seen_msec) { - priv->last_seen_msec = last_seen_msec; - _notify(ap, PROP_LAST_SEEN); - return TRUE; - } - return FALSE; -} - -gboolean -nm_wifi_ap_get_metered(const NMWifiAP *self) -{ - return NM_WIFI_AP_GET_PRIVATE(self)->metered; -} - -/*****************************************************************************/ - -gboolean -nm_wifi_ap_update_from_properties(NMWifiAP *ap, const NMSupplicantBssInfo *bss_info) -{ - NMWifiAPPrivate *priv; - gboolean changed = FALSE; - - g_return_val_if_fail(NM_IS_WIFI_AP(ap), FALSE); - g_return_val_if_fail(bss_info, FALSE); - nm_assert(NM_IS_REF_STRING(bss_info->bss_path)); - - priv = NM_WIFI_AP_GET_PRIVATE(ap); - - nm_assert(!ap->_supplicant_path || ap->_supplicant_path == bss_info->bss_path); - - g_object_freeze_notify(G_OBJECT(ap)); - - if (!ap->_supplicant_path) { - ap->_supplicant_path = nm_ref_string_ref(bss_info->bss_path); - changed = TRUE; - } - - changed |= nm_wifi_ap_set_flags(ap, bss_info->ap_flags); - changed |= nm_wifi_ap_set_mode(ap, bss_info->mode); - changed |= nm_wifi_ap_set_strength(ap, bss_info->signal_percent); - changed |= nm_wifi_ap_set_freq(ap, bss_info->frequency); - changed |= nm_wifi_ap_set_ssid(ap, bss_info->ssid); - - if (bss_info->bssid_valid) - changed |= nm_wifi_ap_set_address_bin(ap, bss_info->bssid); - else { - /* we don't actually clear the value. */ - } - - changed |= nm_wifi_ap_set_max_bitrate(ap, bss_info->max_rate); - - if (priv->metered != bss_info->metered) { - priv->metered = bss_info->metered; - changed = TRUE; - } - - changed |= nm_wifi_ap_set_wpa_flags(ap, bss_info->wpa_flags); - changed |= nm_wifi_ap_set_rsn_flags(ap, bss_info->rsn_flags); - - changed |= nm_wifi_ap_set_last_seen(ap, bss_info->last_seen_msec); - - changed |= nm_wifi_ap_set_fake(ap, FALSE); - - g_object_thaw_notify(G_OBJECT(ap)); - - return changed; -} - -static gboolean -has_proto(NMSettingWirelessSecurity *sec, const char *proto) -{ - guint32 num_protos = nm_setting_wireless_security_get_num_protos(sec); - guint32 i; - - if (num_protos == 0) - return TRUE; /* interpret no protos as "all" */ - - for (i = 0; i < num_protos; i++) { - if (!strcmp(nm_setting_wireless_security_get_proto(sec, i), proto)) - return TRUE; - } - return FALSE; -} - -static void -add_pair_ciphers(NMWifiAP *ap, NMSettingWirelessSecurity *sec) -{ - NMWifiAPPrivate * priv = NM_WIFI_AP_GET_PRIVATE(ap); - guint32 num = nm_setting_wireless_security_get_num_pairwise(sec); - NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; - guint32 i; - - /* If no ciphers are specified, that means "all" WPA ciphers */ - if (num == 0) { - flags |= NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP; - } else { - for (i = 0; i < num; i++) { - const char *cipher = nm_setting_wireless_security_get_pairwise(sec, i); - - if (!strcmp(cipher, "tkip")) - flags |= NM_802_11_AP_SEC_PAIR_TKIP; - else if (!strcmp(cipher, "ccmp")) - flags |= NM_802_11_AP_SEC_PAIR_CCMP; - } - } - - if (has_proto(sec, PROTO_WPA)) - nm_wifi_ap_set_wpa_flags(ap, priv->wpa_flags | flags); - if (has_proto(sec, PROTO_RSN)) - nm_wifi_ap_set_rsn_flags(ap, priv->rsn_flags | flags); -} - -static void -add_group_ciphers(NMWifiAP *ap, NMSettingWirelessSecurity *sec) -{ - NMWifiAPPrivate * priv = NM_WIFI_AP_GET_PRIVATE(ap); - guint32 num = nm_setting_wireless_security_get_num_groups(sec); - NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; - guint32 i; - - /* If no ciphers are specified, that means "all" WPA ciphers */ - if (num == 0) { - flags |= NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP; - } else { - for (i = 0; i < num; i++) { - const char *cipher = nm_setting_wireless_security_get_group(sec, i); - - if (!strcmp(cipher, "wep40")) - flags |= NM_802_11_AP_SEC_GROUP_WEP40; - else if (!strcmp(cipher, "wep104")) - flags |= NM_802_11_AP_SEC_GROUP_WEP104; - else if (!strcmp(cipher, "tkip")) - flags |= NM_802_11_AP_SEC_GROUP_TKIP; - else if (!strcmp(cipher, "ccmp")) - flags |= NM_802_11_AP_SEC_GROUP_CCMP; - } - } - - if (has_proto(sec, PROTO_WPA)) - nm_wifi_ap_set_wpa_flags(ap, priv->wpa_flags | flags); - if (has_proto(sec, PROTO_RSN)) - nm_wifi_ap_set_rsn_flags(ap, priv->rsn_flags | flags); -} - -const char * -nm_wifi_ap_to_string(const NMWifiAP *self, char *str_buf, gulong buf_len, gint64 now_msec) -{ - const NMWifiAPPrivate *priv; - const char * supplicant_id = "-"; - const char * export_path; - guint32 chan; - gs_free char * ssid_to_free = NULL; - char str_buf_ts[100]; - - g_return_val_if_fail(NM_IS_WIFI_AP(self), NULL); - - priv = NM_WIFI_AP_GET_PRIVATE(self); - - chan = nm_utils_wifi_freq_to_channel(priv->freq); - if (self->_supplicant_path) - supplicant_id = strrchr(self->_supplicant_path->str, '/') ?: supplicant_id; - - export_path = nm_dbus_object_get_path(NM_DBUS_OBJECT(self)); - if (export_path) - export_path = strrchr(export_path, '/') ?: export_path; - else - export_path = "/"; - - nm_utils_get_monotonic_timestamp_msec_cached(&now_msec); - - g_snprintf(str_buf, - buf_len, - "%17s %-35s [ %c %3u %3u%% %c%c W:%04X R:%04X ] %s sup:%s [nm:%s]", - priv->address ?: "(none)", - (ssid_to_free = _nm_utils_ssid_to_string(priv->ssid)), - (priv->mode == NM_802_11_MODE_ADHOC - ? '*' - : (priv->hotspot - ? '#' - : (priv->fake ? 'f' : (priv->mode == NM_802_11_MODE_MESH ? 'm' : 'a')))), - chan, - priv->strength, - priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : '_', - priv->metered ? 'M' : '_', - priv->wpa_flags & 0xFFFF, - priv->rsn_flags & 0xFFFF, - priv->last_seen_msec != G_MININT64 - ? nm_sprintf_buf(str_buf_ts, - "%3u.%03us", - (guint)((now_msec - priv->last_seen_msec) / 1000), - (guint)((now_msec - priv->last_seen_msec) % 1000)) - : " ", - supplicant_id, - export_path); - return str_buf; -} - -static guint -freq_to_band(guint32 freq) -{ - if (freq >= 4915 && freq <= 5825) - return 5; - else if (freq >= 2412 && freq <= 2484) - return 2; - return 0; -} - -gboolean -nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection) -{ - NMWifiAPPrivate * priv; - NMSettingWireless * s_wireless; - NMSettingWirelessSecurity *s_wireless_sec; - GBytes * ssid; - const char * mode; - const char * band; - const char * bssid; - guint32 channel; - - g_return_val_if_fail(NM_IS_WIFI_AP(self), FALSE); - g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE(self); - - s_wireless = nm_connection_get_setting_wireless(connection); - if (s_wireless == NULL) - return FALSE; - - ssid = nm_setting_wireless_get_ssid(s_wireless); - if (ssid != priv->ssid) { - if (!ssid || !priv->ssid) - return FALSE; - if (!g_bytes_equal(ssid, priv->ssid)) - return FALSE; - } - - bssid = nm_setting_wireless_get_bssid(s_wireless); - if (bssid && (!priv->address || !nm_utils_hwaddr_matches(bssid, -1, priv->address, -1))) - return FALSE; - - mode = nm_setting_wireless_get_mode(s_wireless); - if (mode) { - if (!strcmp(mode, "infrastructure") && (priv->mode != NM_802_11_MODE_INFRA)) - return FALSE; - if (!strcmp(mode, "adhoc") && (priv->mode != NM_802_11_MODE_ADHOC)) - return FALSE; - if (!strcmp(mode, "ap") && (priv->mode != NM_802_11_MODE_INFRA || priv->hotspot != TRUE)) - return FALSE; - if (!strcmp(mode, "mesh") && (priv->mode != NM_802_11_MODE_MESH)) - return FALSE; - } - - band = nm_setting_wireless_get_band(s_wireless); - if (band) { - guint ap_band = freq_to_band(priv->freq); - - if (!strcmp(band, "a") && ap_band != 5) - return FALSE; - else if (!strcmp(band, "bg") && ap_band != 2) - return FALSE; - } - - channel = nm_setting_wireless_get_channel(s_wireless); - if (channel) { - guint32 ap_chan = nm_utils_wifi_freq_to_channel(priv->freq); - - if (channel != ap_chan) - return FALSE; - } - - s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - - return nm_setting_wireless_ap_security_compatible(s_wireless, - s_wireless_sec, - priv->flags, - priv->wpa_flags, - priv->rsn_flags, - priv->mode); -} - -gboolean -nm_wifi_ap_complete_connection(NMWifiAP * self, - NMConnection *connection, - gboolean lock_bssid, - GError ** error) -{ - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self); - - g_return_val_if_fail(connection != NULL, FALSE); - - return nm_wifi_utils_complete_connection(priv->ssid, - priv->address, - priv->mode, - priv->freq, - priv->flags, - priv->wpa_flags, - priv->rsn_flags, - connection, - lock_bssid, - error); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMWifiAP * self = NM_WIFI_AP(object); - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_FLAGS: - g_value_set_uint(value, priv->flags); - break; - case PROP_WPA_FLAGS: - g_value_set_uint(value, priv->wpa_flags); - break; - case PROP_RSN_FLAGS: - g_value_set_uint(value, priv->rsn_flags); - break; - case PROP_SSID: - g_value_take_variant(value, nm_utils_gbytes_to_variant_ay(priv->ssid)); - break; - case PROP_FREQUENCY: - g_value_set_uint(value, priv->freq); - break; - case PROP_HW_ADDRESS: - g_value_set_string(value, priv->address); - break; - case PROP_MODE: - g_value_set_uint(value, priv->mode); - break; - case PROP_MAX_BITRATE: - g_value_set_uint(value, priv->max_bitrate); - break; - case PROP_STRENGTH: - g_value_set_uchar(value, priv->strength); - break; - case PROP_LAST_SEEN: - g_value_set_int(value, - priv->last_seen_msec != G_MININT64 ? (int) NM_MAX( - nm_utils_monotonic_timestamp_as_boottime(priv->last_seen_msec, - NM_UTILS_NSEC_PER_MSEC) - / 1000, - 1) - : -1); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_wifi_ap_init(NMWifiAP *self) -{ - NMWifiAPPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_WIFI_AP, NMWifiAPPrivate); - - self->_priv = priv; - - c_list_init(&self->aps_lst); - - priv->mode = NM_802_11_MODE_INFRA; - priv->flags = NM_802_11_AP_FLAGS_NONE; - priv->wpa_flags = NM_802_11_AP_SEC_NONE; - priv->rsn_flags = NM_802_11_AP_SEC_NONE; - priv->last_seen_msec = G_MININT64; -} - -NMWifiAP * -nm_wifi_ap_new_from_properties(const NMSupplicantBssInfo *bss_info) -{ - NMWifiAP *ap; - - ap = g_object_new(NM_TYPE_WIFI_AP, NULL); - nm_wifi_ap_update_from_properties(ap, bss_info); - return ap; -} - -NMWifiAP * -nm_wifi_ap_new_fake_from_connection(NMConnection *connection) -{ - NMWifiAP * ap; - NMWifiAPPrivate * priv; - NMSettingWireless * s_wireless; - NMSettingWirelessSecurity *s_wireless_sec; - const char * mode, *band, *key_mgmt; - guint32 channel; - NM80211ApSecurityFlags flags; - gboolean psk = FALSE, eap = FALSE, adhoc = FALSE; - - g_return_val_if_fail(connection != NULL, NULL); - - s_wireless = nm_connection_get_setting_wireless(connection); - g_return_val_if_fail(s_wireless != NULL, NULL); - - ap = (NMWifiAP *) g_object_new(NM_TYPE_WIFI_AP, NULL); - priv = NM_WIFI_AP_GET_PRIVATE(ap); - priv->fake = TRUE; - - nm_wifi_ap_set_ssid(ap, nm_setting_wireless_get_ssid(s_wireless)); - - // FIXME: bssid too? - - mode = nm_setting_wireless_get_mode(s_wireless); - if (mode) { - if (!strcmp(mode, "infrastructure")) - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); - else if (!strcmp(mode, "adhoc")) { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_ADHOC); - adhoc = TRUE; - } else if (!strcmp(mode, "mesh")) - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_MESH); - else if (!strcmp(mode, "ap")) { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); - NM_WIFI_AP_GET_PRIVATE(ap)->hotspot = TRUE; - } else - goto error; - } else { - nm_wifi_ap_set_mode(ap, NM_802_11_MODE_INFRA); - } - - band = nm_setting_wireless_get_band(s_wireless); - channel = nm_setting_wireless_get_channel(s_wireless); - - if (band && channel) { - guint32 freq = nm_utils_wifi_channel_to_freq(channel, band); - - if (freq == 0) - goto error; - - nm_wifi_ap_set_freq(ap, freq); - } - - s_wireless_sec = nm_connection_get_setting_wireless_security(connection); - /* Assume presence of a security setting means the AP is encrypted */ - if (!s_wireless_sec) - goto done; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wireless_sec); - - /* Everything below here uses encryption */ - nm_wifi_ap_set_flags(ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY); - - /* Static & Dynamic WEP */ - if (!strcmp(key_mgmt, "none") || !strcmp(key_mgmt, "ieee8021x")) - goto done; - - psk = !strcmp(key_mgmt, "wpa-psk"); - eap = !strcmp(key_mgmt, "wpa-eap"); - if (!adhoc && (psk || eap)) { - if (has_proto(s_wireless_sec, PROTO_WPA)) { - flags = priv->wpa_flags - | (eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK); - nm_wifi_ap_set_wpa_flags(ap, flags); - } - if (has_proto(s_wireless_sec, PROTO_RSN)) { - flags = priv->rsn_flags - | (eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK); - nm_wifi_ap_set_rsn_flags(ap, flags); - } - - add_pair_ciphers(ap, s_wireless_sec); - add_group_ciphers(ap, s_wireless_sec); - } else if (adhoc && psk) { - /* Ad-Hoc has special requirements: proto=RSN, pairwise=CCMP and - * group=CCMP. - */ - flags = priv->wpa_flags | NM_802_11_AP_SEC_KEY_MGMT_PSK; - - /* Clear ciphers; only CCMP is supported */ - flags &= ~(NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104 - | NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_GROUP_WEP40 - | NM_802_11_AP_SEC_GROUP_WEP104 | NM_802_11_AP_SEC_GROUP_TKIP); - - flags |= NM_802_11_AP_SEC_PAIR_CCMP; - flags |= NM_802_11_AP_SEC_GROUP_CCMP; - nm_wifi_ap_set_rsn_flags(ap, flags); - - /* Don't use Ad-Hoc WPA (WPA-none) anymore */ - nm_wifi_ap_set_wpa_flags(ap, NM_802_11_AP_SEC_NONE); - } -done: - return ap; - -error: - g_object_unref(ap); - return NULL; -} - -static void -finalize(GObject *object) -{ - NMWifiAP * self = NM_WIFI_AP(object); - NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE(self); - - nm_assert(!self->wifi_device); - nm_assert(c_list_is_empty(&self->aps_lst)); - - nm_ref_string_unref(self->_supplicant_path); - if (priv->ssid) - g_bytes_unref(priv->ssid); - g_free(priv->address); - - G_OBJECT_CLASS(nm_wifi_ap_parent_class)->finalize(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_access_point = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_ACCESS_POINT, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Flags", "u", NM_WIFI_AP_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WpaFlags", "u", NM_WIFI_AP_WPA_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("RsnFlags", "u", NM_WIFI_AP_RSN_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Ssid", "ay", NM_WIFI_AP_SSID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Frequency", - "u", - NM_WIFI_AP_FREQUENCY), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_WIFI_AP_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "u", NM_WIFI_AP_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("MaxBitrate", - "u", - NM_WIFI_AP_MAX_BITRATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Strength", "y", NM_WIFI_AP_STRENGTH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("LastSeen", - "i", - NM_WIFI_AP_LAST_SEEN), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_wifi_ap_class_init(NMWifiAPClass *ap_class) -{ -#define ALL_SEC_FLAGS \ - (NM_802_11_AP_SEC_NONE | NM_802_11_AP_SEC_PAIR_WEP40 | NM_802_11_AP_SEC_PAIR_WEP104 \ - | NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_WEP40 \ - | NM_802_11_AP_SEC_GROUP_WEP104 | NM_802_11_AP_SEC_GROUP_TKIP | NM_802_11_AP_SEC_GROUP_CCMP \ - | NM_802_11_AP_SEC_KEY_MGMT_PSK | NM_802_11_AP_SEC_KEY_MGMT_802_1X \ - | NM_802_11_AP_SEC_KEY_MGMT_SAE | NM_802_11_AP_SEC_KEY_MGMT_OWE \ - | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM) - - GObjectClass * object_class = G_OBJECT_CLASS(ap_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(ap_class); - - g_type_class_add_private(object_class, sizeof(NMWifiAPPrivate)); - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH_ACCESS_POINT); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_access_point); - - object_class->get_property = get_property; - object_class->finalize = finalize; - - obj_properties[PROP_FLAGS] = g_param_spec_uint(NM_WIFI_AP_FLAGS, - "", - "", - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_FLAGS_NONE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_WPA_FLAGS] = g_param_spec_uint(NM_WIFI_AP_WPA_FLAGS, - "", - "", - NM_802_11_AP_SEC_NONE, - ALL_SEC_FLAGS, - NM_802_11_AP_SEC_NONE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_RSN_FLAGS] = g_param_spec_uint(NM_WIFI_AP_RSN_FLAGS, - "", - "", - NM_802_11_AP_SEC_NONE, - ALL_SEC_FLAGS, - NM_802_11_AP_SEC_NONE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SSID] = g_param_spec_variant(NM_WIFI_AP_SSID, - "", - "", - G_VARIANT_TYPE("ay"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_FREQUENCY] = g_param_spec_uint(NM_WIFI_AP_FREQUENCY, - "", - "", - 0, - 10000, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HW_ADDRESS] = - g_param_spec_string(NM_WIFI_AP_HW_ADDRESS, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MODE] = g_param_spec_uint(NM_WIFI_AP_MODE, - "", - "", - NM_802_11_MODE_ADHOC, - NM_802_11_MODE_INFRA, - NM_802_11_MODE_INFRA, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MAX_BITRATE] = g_param_spec_uint(NM_WIFI_AP_MAX_BITRATE, - "", - "", - 0, - G_MAXUINT16, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_STRENGTH] = g_param_spec_uchar(NM_WIFI_AP_STRENGTH, - "", - "", - 0, - G_MAXINT8, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LAST_SEEN] = g_param_spec_int(NM_WIFI_AP_LAST_SEEN, - "", - "", - -1, - G_MAXINT, - -1, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} - -/*****************************************************************************/ - -const char ** -nm_wifi_aps_get_paths(const CList *aps_lst_head, gboolean include_without_ssid) -{ - NMWifiAP * ap; - gsize i, n; - const char **list; - const char * path; - - n = c_list_length(aps_lst_head); - list = g_new(const char *, n + 1); - - i = 0; - if (n > 0) { - c_list_for_each_entry (ap, aps_lst_head, aps_lst) { - nm_assert(i < n); - if (!include_without_ssid && !nm_wifi_ap_get_ssid(ap)) - continue; - - path = nm_dbus_object_get_path(NM_DBUS_OBJECT(ap)); - nm_assert(path); - - list[i++] = path; - } - nm_assert(i <= n); - nm_assert(!include_without_ssid || i == n); - } - list[i] = NULL; - return list; -} - -NMWifiAP * -nm_wifi_aps_find_first_compatible(const CList *aps_lst_head, NMConnection *connection) -{ - NMWifiAP *ap; - - g_return_val_if_fail(connection, NULL); - - c_list_for_each_entry (ap, aps_lst_head, aps_lst) { - if (nm_wifi_ap_check_compatible(ap, connection)) - return ap; - } - return NULL; -} - -/*****************************************************************************/ - -NMWifiAP * -nm_wifi_ap_lookup_for_device(NMDevice *device, const char *exported_path) -{ - NMWifiAP *ap; - - g_return_val_if_fail(NM_IS_DEVICE(device), NULL); - - ap = nm_dbus_manager_lookup_object(nm_dbus_object_get_manager(NM_DBUS_OBJECT(device)), - exported_path); - if (!ap || !NM_IS_WIFI_AP(ap) || ap->wifi_device != device) - return NULL; - - return ap; -} diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h deleted file mode 100644 index 4608c6ff..00000000 --- a/src/devices/wifi/nm-wifi-ap.h +++ /dev/null @@ -1,94 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2004 - 2017 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __NM_WIFI_AP_H__ -#define __NM_WIFI_AP_H__ - -#include "nm-dbus-object.h" -#include "nm-dbus-interface.h" -#include "nm-connection.h" - -#define NM_TYPE_WIFI_AP (nm_wifi_ap_get_type()) -#define NM_WIFI_AP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_AP, NMWifiAP)) -#define NM_WIFI_AP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_AP, NMWifiAPClass)) -#define NM_IS_WIFI_AP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_AP)) -#define NM_IS_WIFI_AP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WIFI_AP)) -#define NM_WIFI_AP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WIFI_AP, NMWifiAPClass)) - -#define NM_WIFI_AP_FLAGS "flags" -#define NM_WIFI_AP_WPA_FLAGS "wpa-flags" -#define NM_WIFI_AP_RSN_FLAGS "rsn-flags" -#define NM_WIFI_AP_SSID "ssid" -#define NM_WIFI_AP_FREQUENCY "frequency" -#define NM_WIFI_AP_HW_ADDRESS "hw-address" -#define NM_WIFI_AP_MODE "mode" -#define NM_WIFI_AP_MAX_BITRATE "max-bitrate" -#define NM_WIFI_AP_STRENGTH "strength" -#define NM_WIFI_AP_LAST_SEEN "last-seen" - -typedef struct { - NMDBusObject parent; - NMDevice * wifi_device; - CList aps_lst; - NMRefString * _supplicant_path; - struct _NMWifiAPPrivate *_priv; -} NMWifiAP; - -struct _NMSupplicantBssInfo; - -typedef struct _NMWifiAPClass NMWifiAPClass; - -GType nm_wifi_ap_get_type(void); - -NMWifiAP *nm_wifi_ap_new_from_properties(const struct _NMSupplicantBssInfo *bss_info); -NMWifiAP *nm_wifi_ap_new_fake_from_connection(NMConnection *connection); - -gboolean nm_wifi_ap_update_from_properties(NMWifiAP * ap, - const struct _NMSupplicantBssInfo *bss_info); - -gboolean nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection); - -gboolean nm_wifi_ap_complete_connection(NMWifiAP * self, - NMConnection *connection, - gboolean lock_bssid, - GError ** error); - -static inline NMRefString * -nm_wifi_ap_get_supplicant_path(NMWifiAP *ap) -{ - g_return_val_if_fail(NM_IS_WIFI_AP(ap), NULL); - - return ap->_supplicant_path; -} - -GBytes * nm_wifi_ap_get_ssid(const NMWifiAP *ap); -gboolean nm_wifi_ap_set_ssid_arr(NMWifiAP *ap, const guint8 *ssid, gsize ssid_len); -gboolean nm_wifi_ap_set_ssid(NMWifiAP *ap, GBytes *ssid); -const char * nm_wifi_ap_get_address(const NMWifiAP *ap); -gboolean nm_wifi_ap_set_address(NMWifiAP *ap, const char *addr); -NM80211Mode nm_wifi_ap_get_mode(NMWifiAP *ap); -gboolean nm_wifi_ap_is_hotspot(NMWifiAP *ap); -gint8 nm_wifi_ap_get_strength(NMWifiAP *ap); -gboolean nm_wifi_ap_set_strength(NMWifiAP *ap, gint8 strength); -guint32 nm_wifi_ap_get_freq(NMWifiAP *ap); -gboolean nm_wifi_ap_set_freq(NMWifiAP *ap, guint32 freq); -guint32 nm_wifi_ap_get_max_bitrate(NMWifiAP *ap); -gboolean nm_wifi_ap_set_max_bitrate(NMWifiAP *ap, guint32 bitrate); -gboolean nm_wifi_ap_get_fake(const NMWifiAP *ap); -gboolean nm_wifi_ap_set_fake(NMWifiAP *ap, gboolean fake); -NM80211ApFlags nm_wifi_ap_get_flags(const NMWifiAP *self); -gboolean nm_wifi_ap_get_metered(const NMWifiAP *self); - -const char * -nm_wifi_ap_to_string(const NMWifiAP *self, char *str_buf, gulong buf_len, gint64 now_msec); - -const char **nm_wifi_aps_get_paths(const CList *aps_lst_head, gboolean include_without_ssid); - -NMWifiAP *nm_wifi_aps_find_first_compatible(const CList *aps_lst_head, NMConnection *connection); - -NMWifiAP *nm_wifi_ap_lookup_for_device(NMDevice *device, const char *exported_path); - -#endif /* __NM_WIFI_AP_H__ */ diff --git a/src/devices/wifi/nm-wifi-common.c b/src/devices/wifi/nm-wifi-common.c deleted file mode 100644 index e2ef4186..00000000 --- a/src/devices/wifi/nm-wifi-common.c +++ /dev/null @@ -1,176 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-wifi-common.h" - -#include "devices/nm-device.h" -#include "nm-wifi-ap.h" -#include "nm-device-wifi.h" -#include "nm-dbus-manager.h" - -#if WITH_IWD - #include "nm-device-iwd.h" -#endif - -/*****************************************************************************/ - -void -nm_device_wifi_emit_signal_access_point(NMDevice *device, - NMWifiAP *ap, - gboolean is_added /* or else is_removed */) -{ - nm_dbus_object_emit_signal(NM_DBUS_OBJECT(device), - &nm_interface_info_device_wireless, - is_added ? &nm_signal_info_wireless_access_point_added - : &nm_signal_info_wireless_access_point_removed, - "(o)", - nm_dbus_object_get_path(NM_DBUS_OBJECT(ap))); -} - -/*****************************************************************************/ - -static const CList * -_dispatch_get_aps(NMDevice *device) -{ -#if WITH_IWD - if (NM_IS_DEVICE_IWD(device)) - return _nm_device_iwd_get_aps(NM_DEVICE_IWD(device)); -#endif - return _nm_device_wifi_get_aps(NM_DEVICE_WIFI(device)); -} - -static void -_dispatch_request_scan(NMDevice *device, GVariant *options, GDBusMethodInvocation *invocation) -{ -#if WITH_IWD - if (NM_IS_DEVICE_IWD(device)) { - _nm_device_iwd_request_scan(NM_DEVICE_IWD(device), options, invocation); - return; - } -#endif - _nm_device_wifi_request_scan(NM_DEVICE_WIFI(device), options, invocation); -} - -static void -impl_device_wifi_get_access_points(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - gs_free const char **list = NULL; - GVariant * v; - const CList * all_aps; - - /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */ - - all_aps = _dispatch_get_aps(NM_DEVICE(obj)); - list = nm_wifi_aps_get_paths(all_aps, FALSE); - v = g_variant_new_objv(list, -1); - g_dbus_method_invocation_return_value(invocation, g_variant_new_tuple(&v, 1)); -} - -static void -impl_device_wifi_get_all_access_points(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - gs_free const char **list = NULL; - GVariant * v; - const CList * all_aps; - - /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */ - - all_aps = _dispatch_get_aps(NM_DEVICE(obj)); - list = nm_wifi_aps_get_paths(all_aps, TRUE); - v = g_variant_new_objv(list, -1); - g_dbus_method_invocation_return_value(invocation, g_variant_new_tuple(&v, 1)); -} - -static void -impl_device_wifi_request_scan(NMDBusObject * obj, - const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) -{ - gs_unref_variant GVariant *options = NULL; - - /* NOTE: this handler is called both for NMDevicwWifi and NMDeviceIwd. */ - - g_variant_get(parameters, "(@a{sv})", &options); - - _dispatch_request_scan(NM_DEVICE(obj), options, invocation); -} - -const GDBusSignalInfo nm_signal_info_wireless_access_point_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( - "AccessPointAdded", - .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("access_point", "o"), ), ); - -const GDBusSignalInfo nm_signal_info_wireless_access_point_removed = - NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( - "AccessPointRemoved", - .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("access_point", "o"), ), ); - -const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_WIRELESS, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS( - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( - NM_DEFINE_GDBUS_METHOD_INFO_INIT( - "GetAccessPoints", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("access_points", "ao"), ), ), - .handle = impl_device_wifi_get_access_points, ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( - NM_DEFINE_GDBUS_METHOD_INFO_INIT( - "GetAllAccessPoints", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("access_points", "ao"), ), ), - .handle = impl_device_wifi_get_all_access_points, ), - NM_DEFINE_DBUS_METHOD_INFO_EXTENDED( - NM_DEFINE_GDBUS_METHOD_INFO_INIT( - "RequestScan", - .in_args = NM_DEFINE_GDBUS_ARG_INFOS( - NM_DEFINE_GDBUS_ARG_INFO("options", "a{sv}"), ), ), - .handle = impl_device_wifi_request_scan, ), ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, - &nm_signal_info_wireless_access_point_added, - &nm_signal_info_wireless_access_point_removed, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("PermHwAddress", - "s", - NM_DEVICE_PERM_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Mode", "u", NM_DEVICE_WIFI_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Bitrate", - "u", - NM_DEVICE_WIFI_BITRATE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("AccessPoints", - "ao", - NM_DEVICE_WIFI_ACCESS_POINTS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ActiveAccessPoint", - "o", - NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("WirelessCapabilities", - "u", - NM_DEVICE_WIFI_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastScan", - "x", - NM_DEVICE_WIFI_LAST_SCAN), ), ), - .legacy_property_changed = TRUE, -}; diff --git a/src/devices/wifi/nm-wifi-common.h b/src/devices/wifi/nm-wifi-common.h deleted file mode 100644 index 203f2a53..00000000 --- a/src/devices/wifi/nm-wifi-common.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NM_WIFI_COMMON_H__ -#define __NM_WIFI_COMMON_H__ - -#include "nm-dbus-utils.h" -#include "nm-wifi-ap.h" - -/*****************************************************************************/ - -void nm_device_wifi_emit_signal_access_point(NMDevice *device, - NMWifiAP *ap, - gboolean is_added /* or else is_removed */); - -extern const NMDBusInterfaceInfoExtended nm_interface_info_device_wireless; -extern const GDBusSignalInfo nm_signal_info_wireless_access_point_added; -extern const GDBusSignalInfo nm_signal_info_wireless_access_point_removed; - -#endif /* __NM_WIFI_COMMON_H__ */ diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c deleted file mode 100644 index 1d140759..00000000 --- a/src/devices/wifi/nm-wifi-factory.c +++ /dev/null @@ -1,157 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 - 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <gmodule.h> - -#include "devices/nm-device-factory.h" -#include "nm-setting-wireless.h" -#include "nm-setting-olpc-mesh.h" -#include "nm-device-wifi.h" -#include "nm-device-wifi-p2p.h" -#include "nm-device-olpc-mesh.h" -#include "nm-device-iwd.h" -#include "settings/nm-settings-connection.h" -#include "platform/nm-platform.h" -#include "nm-config.h" - -/*****************************************************************************/ - -#define NM_TYPE_WIFI_FACTORY (nm_wifi_factory_get_type()) -#define NM_WIFI_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_FACTORY, NMWifiFactory)) -#define NM_WIFI_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_FACTORY, NMWifiFactoryClass)) -#define NM_IS_WIFI_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_FACTORY)) -#define NM_IS_WIFI_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WIFI_FACTORY)) -#define NM_WIFI_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WIFI_FACTORY, NMWifiFactoryClass)) - -typedef struct { - NMDeviceFactory parent; -} NMWifiFactory; - -typedef struct { - NMDeviceFactoryClass parent; -} NMWifiFactoryClass; - -static GType nm_wifi_factory_get_type(void); - -G_DEFINE_TYPE(NMWifiFactory, nm_wifi_factory, NM_TYPE_DEVICE_FACTORY) - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES( - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(NM_LINK_TYPE_WIFI, NM_LINK_TYPE_OLPC_MESH) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_WIRELESS_SETTING_NAME, - NM_SETTING_OLPC_MESH_SETTING_NAME)) - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - return (NMDeviceFactory *) g_object_new(NM_TYPE_WIFI_FACTORY, NULL); -} - -/*****************************************************************************/ - -static void -p2p_device_created(NMDeviceWifi *device, NMDeviceWifiP2P *p2p_device, NMDeviceFactory *self) -{ - nm_log_info(LOGD_PLATFORM | LOGD_WIFI, - "Wi-Fi P2P device controlled by interface %s created", - nm_device_get_iface(NM_DEVICE(device))); - - g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, p2p_device); -} - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - gs_free char *backend = NULL; - - g_return_val_if_fail(iface != NULL, NULL); - g_return_val_if_fail(plink != NULL, NULL); - g_return_val_if_fail(g_strcmp0(iface, plink->name) == 0, NULL); - g_return_val_if_fail(NM_IN_SET(plink->type, NM_LINK_TYPE_WIFI, NM_LINK_TYPE_OLPC_MESH), NULL); - - if (plink->type != NM_LINK_TYPE_WIFI) - return nm_device_olpc_mesh_new(iface); - - backend = nm_config_data_get_device_config_by_pllink(NM_CONFIG_GET_DATA, - NM_CONFIG_KEYFILE_KEY_DEVICE_WIFI_BACKEND, - plink, - "wifi", - NULL); - nm_strstrip(backend); - - nm_log_dbg(LOGD_PLATFORM | LOGD_WIFI, - "(%s) config: backend is %s%s%s%s", - iface, - NM_PRINT_FMT_QUOTE_STRING(backend), - WITH_IWD ? " (iwd support enabled)" : ""); - if (!backend || !g_ascii_strcasecmp(backend, "wpa_supplicant")) { - NMDevice * device; - NMDeviceWifiCapabilities capabilities; - NM80211Mode mode; - - if (!nm_platform_wifi_get_capabilities(NM_PLATFORM_GET, plink->ifindex, &capabilities)) { - nm_log_warn(LOGD_PLATFORM | LOGD_WIFI, - "(%s) failed to initialize Wi-Fi driver for ifindex %d", - iface, - plink->ifindex); - return NULL; - } - - /* Ignore monitor-mode and other unhandled interface types. - * FIXME: keep TYPE_MONITOR devices in UNAVAILABLE state and manage - * them if/when they change to a handled type. - */ - mode = nm_platform_wifi_get_mode(NM_PLATFORM_GET, plink->ifindex); - if (mode == NM_802_11_MODE_UNKNOWN) { - *out_ignore = TRUE; - return NULL; - } - - device = nm_device_wifi_new(iface, capabilities); - - g_signal_connect_object(device, - NM_DEVICE_WIFI_P2P_DEVICE_CREATED, - G_CALLBACK(p2p_device_created), - factory, - 0); - - return device; - } -#if WITH_IWD - else if (!g_ascii_strcasecmp(backend, "iwd")) - return nm_device_iwd_new(iface); -#endif - - nm_log_warn(LOGD_PLATFORM | LOGD_WIFI, - "(%s) config: unknown or unsupported wifi-backend %s", - iface, - backend); - return NULL; -} - -/*****************************************************************************/ - -static void -nm_wifi_factory_init(NMWifiFactory *self) -{} - -static void -nm_wifi_factory_class_init(NMWifiFactoryClass *klass) -{ - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - factory_class->create_device = create_device; - factory_class->get_supported_types = get_supported_types; -} diff --git a/src/devices/wifi/nm-wifi-p2p-peer.c b/src/devices/wifi/nm-wifi-p2p-peer.c deleted file mode 100644 index a194f168..00000000 --- a/src/devices/wifi/nm-wifi-p2p-peer.c +++ /dev/null @@ -1,698 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-wifi-p2p-peer.h" - -#include <stdlib.h> - -#include "NetworkManagerUtils.h" -#include "devices/nm-device.h" -#include "nm-core-internal.h" -#include "nm-dbus-manager.h" -#include "nm-glib-aux/nm-ref-string.h" -#include "nm-setting-wireless.h" -#include "nm-utils.h" -#include "nm-wifi-utils.h" -#include "platform/nm-platform.h" -#include "supplicant/nm-supplicant-types.h" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMWifiP2PPeer, - PROP_NAME, - PROP_MANUFACTURER, - PROP_MODEL, - PROP_MODEL_NUMBER, - PROP_SERIAL, - PROP_WFD_IES, - PROP_HW_ADDRESS, - PROP_STRENGTH, - PROP_LAST_SEEN, - PROP_FLAGS, ); - -struct _NMWifiP2PPeerPrivate { - NMRefString *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */ - - /* Scanned or cached values */ - char *name; - char *manufacturer; - char *model; - char *model_number; - char *serial; - - char *address; - - GBytes *wfd_ies; - - const char **groups; - - guint8 strength; - - NM80211ApFlags flags; /* General flags */ - - /* Non-scanned attributes */ - gint32 - last_seen; /* Timestamp when the Peer was seen lastly (obtained via nm_utils_get_monotonic_timestamp_sec()) */ -}; - -typedef struct _NMWifiP2PPeerPrivate NMWifiP2PPeerPrivate; - -struct _NMWifiP2PPeerClass { - NMDBusObjectClass parent; -}; - -G_DEFINE_TYPE(NMWifiP2PPeer, nm_wifi_p2p_peer, NM_TYPE_DBUS_OBJECT) - -#define NM_WIFI_P2P_PEER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE_PTR(self, NMWifiP2PPeer, NM_IS_WIFI_P2P_PEER) - -/*****************************************************************************/ - -const char ** -nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head) -{ - NMWifiP2PPeer *peer; - const char ** list; - const char * path; - gsize i, n; - - n = c_list_length(peers_lst_head); - list = g_new(const char *, n + 1); - - i = 0; - if (n > 0) { - c_list_for_each_entry (peer, peers_lst_head, peers_lst) { - nm_assert(i < n); - path = nm_dbus_object_get_path(NM_DBUS_OBJECT(peer)); - nm_assert(path); - - list[i++] = path; - } - nm_assert(i <= n); - } - list[i] = NULL; - return list; -} - -NMWifiP2PPeer * -nm_wifi_p2p_peers_find_first_compatible(const CList *peers_lst_head, NMConnection *connection) -{ - NMWifiP2PPeer *peer; - - g_return_val_if_fail(connection, NULL); - - c_list_for_each_entry (peer, peers_lst_head, peers_lst) { - if (nm_wifi_p2p_peer_check_compatible(peer, connection)) - return peer; - } - return NULL; -} - -NMWifiP2PPeer * -nm_wifi_p2p_peers_find_by_supplicant_path(const CList *peers_lst_head, const char *path) -{ - NMWifiP2PPeer *peer; - - g_return_val_if_fail(path != NULL, NULL); - - c_list_for_each_entry (peer, peers_lst_head, peers_lst) { - if (nm_streq0(path, nm_wifi_p2p_peer_get_supplicant_path(peer))) - return peer; - } - return NULL; -} - -/*****************************************************************************/ - -NMWifiP2PPeer * -nm_wifi_p2p_peer_lookup_for_device(NMDevice *device, const char *exported_path) -{ - NMWifiP2PPeer *peer; - - g_return_val_if_fail(NM_IS_DEVICE(device), NULL); - - peer = (NMWifiP2PPeer *) nm_dbus_manager_lookup_object( - nm_dbus_object_get_manager(NM_DBUS_OBJECT(device)), - exported_path); - if (!peer || !NM_IS_WIFI_P2P_PEER(peer) || peer->wifi_device != device) - return NULL; - - return peer; -} - -/*****************************************************************************/ - -const char * -nm_wifi_p2p_peer_get_supplicant_path(NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return nm_ref_string_get_str(NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->supplicant_path); -} - -const char * -nm_wifi_p2p_peer_get_name(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->name; -} - -gboolean -nm_wifi_p2p_peer_set_name(NMWifiP2PPeer *peer, const char *str) -{ - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (!nm_utils_strdup_reset(&priv->name, str)) - return FALSE; - _notify(peer, PROP_NAME); - return TRUE; -} - -const char * -nm_wifi_p2p_peer_get_manufacturer(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->manufacturer; -} - -gboolean -nm_wifi_p2p_peer_set_manufacturer(NMWifiP2PPeer *peer, const char *str) -{ - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (!nm_utils_strdup_reset(&priv->manufacturer, str)) - return FALSE; - _notify(peer, PROP_MANUFACTURER); - return TRUE; -} - -const char * -nm_wifi_p2p_peer_get_model(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->model; -} - -gboolean -nm_wifi_p2p_peer_set_model(NMWifiP2PPeer *peer, const char *str) -{ - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (!nm_utils_strdup_reset(&priv->model, str)) - return FALSE; - _notify(peer, PROP_MODEL); - return TRUE; -} - -const char * -nm_wifi_p2p_peer_get_model_number(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->model_number; -} - -gboolean -nm_wifi_p2p_peer_set_model_number(NMWifiP2PPeer *peer, const char *str) -{ - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (!nm_utils_strdup_reset(&priv->model_number, str)) - return FALSE; - _notify(peer, PROP_MODEL_NUMBER); - return TRUE; -} - -const char * -nm_wifi_p2p_peer_get_serial(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->serial; -} - -gboolean -nm_wifi_p2p_peer_set_serial(NMWifiP2PPeer *peer, const char *str) -{ - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (!nm_utils_strdup_reset(&priv->serial, str)) - return FALSE; - _notify(peer, PROP_SERIAL); - return TRUE; -} - -GBytes * -nm_wifi_p2p_peer_get_wfd_ies(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->wfd_ies; -} - -gboolean -nm_wifi_p2p_peer_set_wfd_ies(NMWifiP2PPeer *peer, GBytes *wfd_ies) -{ - NMWifiP2PPeerPrivate *priv; - gs_unref_bytes GBytes *wfd_ies_old = NULL; - - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (nm_gbytes_equal0(priv->wfd_ies, wfd_ies)) - return FALSE; - - wfd_ies_old = g_steal_pointer(&priv->wfd_ies); - priv->wfd_ies = wfd_ies ? g_bytes_ref(wfd_ies) : NULL; - - _notify(peer, PROP_WFD_IES); - return TRUE; -} - -const char *const * -nm_wifi_p2p_peer_get_groups(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->groups; -} - -const char * -nm_wifi_p2p_peer_get_address(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NULL); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->address; -} - -static gboolean -nm_wifi_p2p_peer_set_address_bin(NMWifiP2PPeer *peer, const guint8 addr[static ETH_ALEN]) -{ - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (priv->address && nm_utils_hwaddr_matches(addr, ETH_ALEN, priv->address, -1)) - return FALSE; - - g_free(priv->address); - priv->address = nm_utils_hwaddr_ntoa(addr, ETH_ALEN); - _notify(peer, PROP_HW_ADDRESS); - return TRUE; -} - -gboolean -nm_wifi_p2p_peer_set_address(NMWifiP2PPeer *peer, const char *addr) -{ - guint8 addr_buf[ETH_ALEN]; - - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE); - - if (!addr || !nm_utils_hwaddr_aton(addr, addr_buf, sizeof(addr_buf))) - g_return_val_if_reached(FALSE); - - return nm_wifi_p2p_peer_set_address_bin(peer, addr_buf); -} - -gint8 -nm_wifi_p2p_peer_get_strength(NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), 0); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->strength; -} - -gboolean -nm_wifi_p2p_peer_set_strength(NMWifiP2PPeer *peer, const gint8 strength) -{ - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (priv->strength != strength) { - priv->strength = strength; - _notify(peer, PROP_STRENGTH); - return TRUE; - } - return FALSE; -} - -NM80211ApFlags -nm_wifi_p2p_peer_get_flags(const NMWifiP2PPeer *peer) -{ - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), NM_802_11_AP_FLAGS_NONE); - - return NM_WIFI_P2P_PEER_GET_PRIVATE(peer)->flags; -} - -static gboolean -nm_wifi_p2p_peer_set_last_seen(NMWifiP2PPeer *peer, gint32 last_seen) -{ - NMWifiP2PPeerPrivate *priv; - - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - if (priv->last_seen != last_seen) { - priv->last_seen = last_seen; - _notify(peer, PROP_LAST_SEEN); - return TRUE; - } - return FALSE; -} - -/*****************************************************************************/ - -gboolean -nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer *peer, const NMSupplicantPeerInfo *peer_info) -{ - NMWifiP2PPeerPrivate *priv; - gboolean changed = FALSE; - - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(peer), FALSE); - g_return_val_if_fail(peer_info, FALSE); - nm_assert(NM_IS_REF_STRING(peer_info->peer_path)); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE(peer); - - nm_assert(!priv->supplicant_path || priv->supplicant_path == peer_info->peer_path); - - g_object_freeze_notify(G_OBJECT(peer)); - - if (!priv->supplicant_path) { - priv->supplicant_path = nm_ref_string_ref(peer_info->peer_path); - changed = TRUE; - } - - changed |= nm_wifi_p2p_peer_set_strength(peer, peer_info->signal_percent); - changed |= nm_wifi_p2p_peer_set_name(peer, peer_info->device_name); - changed |= nm_wifi_p2p_peer_set_manufacturer(peer, peer_info->manufacturer); - changed |= nm_wifi_p2p_peer_set_model(peer, peer_info->model); - changed |= nm_wifi_p2p_peer_set_model_number(peer, peer_info->model_number); - changed |= nm_wifi_p2p_peer_set_serial(peer, peer_info->serial); - - if (peer_info->address_valid) - changed |= nm_wifi_p2p_peer_set_address_bin(peer, peer_info->address); - else { - /* we don't reset the address. */ - } - - changed |= nm_wifi_p2p_peer_set_wfd_ies(peer, peer_info->ies); - changed |= nm_wifi_p2p_peer_set_last_seen(peer, peer_info->last_seen_msec / 1000u); - - /* We currently only use the groups information internally to check if - * the peer is still joined. */ - if (!_nm_utils_strv_equal((char **) priv->groups, (char **) peer_info->groups)) { - g_free(priv->groups); - priv->groups = nm_utils_strv_dup_packed(peer_info->groups, -1); - changed |= TRUE; - } - - g_object_thaw_notify(G_OBJECT(peer)); - - return changed; -} - -const char * -nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_len, gint32 now_s) -{ - const NMWifiP2PPeerPrivate *priv; - const char * supplicant_id = "-"; - const char * export_path; - - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(self), NULL); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self); - - if (priv->supplicant_path) - supplicant_id = strrchr(priv->supplicant_path->str, '/') ?: supplicant_id; - - export_path = nm_dbus_object_get_path(NM_DBUS_OBJECT(self)); - if (export_path) - export_path = strrchr(export_path, '/') ?: export_path; - else - export_path = "/"; - - g_snprintf(str_buf, - buf_len, - "%17s [n:%s, m:%s, mod:%s, mod_num:%s, ser:%s] %3us sup:%s [nm:%s]", - priv->address ?: "(none)", - priv->name, - priv->manufacturer, - priv->model, - priv->model_number, - priv->serial, - priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_sec()) - - priv->last_seen) - : -1, - supplicant_id, - export_path); - - return str_buf; -} - -gboolean -nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection) -{ - NMWifiP2PPeerPrivate *priv; - NMSettingWifiP2P * s_wifi_p2p; - const char * hwaddr; - - g_return_val_if_fail(NM_IS_WIFI_P2P_PEER(self), FALSE); - g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self); - - s_wifi_p2p = - NM_SETTING_WIFI_P2P(nm_connection_get_setting(connection, NM_TYPE_SETTING_WIFI_P2P)); - if (s_wifi_p2p == NULL) - return FALSE; - - hwaddr = nm_setting_wifi_p2p_get_peer(s_wifi_p2p); - if (hwaddr && (!priv->address || !nm_utils_hwaddr_matches(hwaddr, -1, priv->address, -1))) - return FALSE; - - return TRUE; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMWifiP2PPeer * self = NM_WIFI_P2P_PEER(object); - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_FLAGS: - g_value_set_uint(value, priv->flags); - break; - case PROP_NAME: - g_value_set_string(value, priv->name); - break; - case PROP_MANUFACTURER: - g_value_set_string(value, priv->manufacturer); - break; - case PROP_MODEL: - g_value_set_string(value, priv->model); - break; - case PROP_MODEL_NUMBER: - g_value_set_string(value, priv->model_number); - break; - case PROP_SERIAL: - g_value_set_string(value, priv->serial); - break; - case PROP_WFD_IES: - g_value_take_variant(value, nm_utils_gbytes_to_variant_ay(priv->wfd_ies)); - break; - case PROP_HW_ADDRESS: - g_value_set_string(value, priv->address); - break; - case PROP_STRENGTH: - g_value_set_uchar(value, priv->strength); - break; - case PROP_LAST_SEEN: - g_value_set_int(value, - priv->last_seen > 0 - ? (int) nm_utils_monotonic_timestamp_as_boottime(priv->last_seen, - NM_UTILS_NSEC_PER_SEC) - : -1); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_wifi_p2p_peer_init(NMWifiP2PPeer *self) -{ - NMWifiP2PPeerPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerPrivate); - - self->_priv = priv; - - c_list_init(&self->peers_lst); - - priv->flags = NM_802_11_AP_FLAGS_NONE; - priv->last_seen = -1; -} - -NMWifiP2PPeer * -nm_wifi_p2p_peer_new_from_properties(const NMSupplicantPeerInfo *peer_info) -{ - NMWifiP2PPeer *peer; - - g_return_val_if_fail(peer_info, NULL); - - peer = g_object_new(NM_TYPE_WIFI_P2P_PEER, NULL); - nm_wifi_p2p_peer_update_from_properties(peer, peer_info); - return peer; -} - -static void -finalize(GObject *object) -{ - NMWifiP2PPeer * self = NM_WIFI_P2P_PEER(object); - NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE(self); - - nm_assert(!self->wifi_device); - nm_assert(c_list_is_empty(&self->peers_lst)); - - nm_ref_string_unref(priv->supplicant_path); - g_free(priv->name); - g_free(priv->manufacturer); - g_free(priv->model); - g_free(priv->model_number); - g_free(priv->serial); - g_free(priv->address); - g_bytes_unref(priv->wfd_ies); - g_free(priv->groups); - - G_OBJECT_CLASS(nm_wifi_p2p_peer_parent_class)->finalize(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_WIFI_P2P_PEER, - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - /* Before 1.24, we wrongly exposed a property "Groups" of type "as". Don't reuse that property name. */ - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags", "u", NM_WIFI_P2P_PEER_FLAGS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Name", "s", NM_WIFI_P2P_PEER_NAME), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Manufacturer", - "s", - NM_WIFI_P2P_PEER_MANUFACTURER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Model", "s", NM_WIFI_P2P_PEER_MODEL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ModelNumber", - "s", - NM_WIFI_P2P_PEER_MODEL_NUMBER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Serial", "s", NM_WIFI_P2P_PEER_SERIAL), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("WfdIEs", - "ay", - NM_WIFI_P2P_PEER_WFD_IES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("HwAddress", - "s", - NM_WIFI_P2P_PEER_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Strength", - "y", - NM_WIFI_P2P_PEER_STRENGTH), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("LastSeen", - "i", - NM_WIFI_P2P_PEER_LAST_SEEN), ), ), - .legacy_property_changed = FALSE, -}; - -static void -nm_wifi_p2p_peer_class_init(NMWifiP2PPeerClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - - g_type_class_add_private(object_class, sizeof(NMWifiP2PPeerPrivate)); - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH_WIFI_P2P_PEER); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_p2p_peer); - - object_class->get_property = get_property; - object_class->finalize = finalize; - - obj_properties[PROP_FLAGS] = g_param_spec_uint(NM_WIFI_P2P_PEER_FLAGS, - "", - "", - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_FLAGS_NONE, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_NAME] = g_param_spec_string(NM_WIFI_P2P_PEER_NAME, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MANUFACTURER] = - g_param_spec_string(NM_WIFI_P2P_PEER_MANUFACTURER, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MODEL] = g_param_spec_string(NM_WIFI_P2P_PEER_MODEL, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MODEL_NUMBER] = - g_param_spec_string(NM_WIFI_P2P_PEER_MODEL_NUMBER, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SERIAL] = g_param_spec_string(NM_WIFI_P2P_PEER_SERIAL, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_WFD_IES] = g_param_spec_variant(NM_WIFI_P2P_PEER_WFD_IES, - "", - "", - G_VARIANT_TYPE("ay"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HW_ADDRESS] = - g_param_spec_string(NM_WIFI_P2P_PEER_HW_ADDRESS, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_STRENGTH] = g_param_spec_uchar(NM_WIFI_P2P_PEER_STRENGTH, - "", - "", - 0, - G_MAXINT8, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_LAST_SEEN] = g_param_spec_int(NM_WIFI_P2P_PEER_LAST_SEEN, - "", - "", - -1, - G_MAXINT, - -1, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/wifi/nm-wifi-p2p-peer.h b/src/devices/wifi/nm-wifi-p2p-peer.h deleted file mode 100644 index e19cf3d8..00000000 --- a/src/devices/wifi/nm-wifi-p2p-peer.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NM_WIFI_P2P_PEER_H__ -#define __NM_WIFI_P2P_PEER_H__ - -#include "nm-dbus-object.h" -#include "nm-dbus-interface.h" -#include "nm-connection.h" - -#define NM_TYPE_WIFI_P2P_PEER (nm_wifi_p2p_peer_get_type()) -#define NM_WIFI_P2P_PEER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeer)) -#define NM_WIFI_P2P_PEER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerClass)) -#define NM_IS_WIFI_P2P_PEER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WIFI_P2P_PEER)) -#define NM_IS_WIFI_P2P_PEER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WIFI_P2P_PEER)) -#define NM_WIFI_P2P_PEER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WIFI_P2P_PEER, NMWifiP2PPeerClass)) - -#define NM_WIFI_P2P_PEER_FLAGS "flags" -#define NM_WIFI_P2P_PEER_NAME "name" -#define NM_WIFI_P2P_PEER_MANUFACTURER "manufacturer" -#define NM_WIFI_P2P_PEER_MODEL "model" -#define NM_WIFI_P2P_PEER_MODEL_NUMBER "model-number" -#define NM_WIFI_P2P_PEER_SERIAL "serial" -#define NM_WIFI_P2P_PEER_WFD_IES "wfd-ies" -#define NM_WIFI_P2P_PEER_HW_ADDRESS "hw-address" -#define NM_WIFI_P2P_PEER_STRENGTH "strength" -#define NM_WIFI_P2P_PEER_LAST_SEEN "last-seen" - -typedef struct { - NMDBusObject parent; - NMDevice * wifi_device; - CList peers_lst; - struct _NMWifiP2PPeerPrivate *_priv; -} NMWifiP2PPeer; - -typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass; - -struct _NMSupplicantPeerInfo; - -GType nm_wifi_p2p_peer_get_type(void); - -NMWifiP2PPeer *nm_wifi_p2p_peer_new_from_properties(const struct _NMSupplicantPeerInfo *peer_info); - -gboolean nm_wifi_p2p_peer_update_from_properties(NMWifiP2PPeer * peer, - const struct _NMSupplicantPeerInfo *peer_info); - -gboolean nm_wifi_p2p_peer_check_compatible(NMWifiP2PPeer *self, NMConnection *connection); - -const char *nm_wifi_p2p_peer_get_supplicant_path(NMWifiP2PPeer *peer); - -const char *nm_wifi_p2p_peer_get_name(const NMWifiP2PPeer *peer); -gboolean nm_wifi_p2p_peer_set_name(NMWifiP2PPeer *peer, const char *name); -const char *nm_wifi_p2p_peer_get_manufacturer(const NMWifiP2PPeer *peer); -gboolean nm_wifi_p2p_peer_set_manufacturer(NMWifiP2PPeer *peer, const char *manufacturer); -const char *nm_wifi_p2p_peer_get_model(const NMWifiP2PPeer *peer); -gboolean nm_wifi_p2p_peer_set_model(NMWifiP2PPeer *peer, const char *model); -const char *nm_wifi_p2p_peer_get_model_number(const NMWifiP2PPeer *peer); -gboolean nm_wifi_p2p_peer_set_model_number(NMWifiP2PPeer *peer, const char *number); -const char *nm_wifi_p2p_peer_get_serial(const NMWifiP2PPeer *peer); -gboolean nm_wifi_p2p_peer_set_serial(NMWifiP2PPeer *peer, const char *serial); - -GBytes * nm_wifi_p2p_peer_get_wfd_ies(const NMWifiP2PPeer *peer); -gboolean nm_wifi_p2p_peer_set_wfd_ies(NMWifiP2PPeer *peer, GBytes *bytes); - -const char *const *nm_wifi_p2p_peer_get_groups(const NMWifiP2PPeer *peer); - -const char * nm_wifi_p2p_peer_get_address(const NMWifiP2PPeer *peer); -gboolean nm_wifi_p2p_peer_set_address(NMWifiP2PPeer *peer, const char *addr); -gint8 nm_wifi_p2p_peer_get_strength(NMWifiP2PPeer *peer); -gboolean nm_wifi_p2p_peer_set_strength(NMWifiP2PPeer *peer, gint8 strength); -NM80211ApFlags nm_wifi_p2p_peer_get_flags(const NMWifiP2PPeer *self); - -const char * -nm_wifi_p2p_peer_to_string(const NMWifiP2PPeer *self, char *str_buf, gsize buf_len, gint32 now_s); - -const char **nm_wifi_p2p_peers_get_paths(const CList *peers_lst_head); - -NMWifiP2PPeer *nm_wifi_p2p_peers_find_first_compatible(const CList * peers_lst_head, - NMConnection *connection); - -NMWifiP2PPeer *nm_wifi_p2p_peers_find_by_supplicant_path(const CList *peers_lst_head, - const char * path); - -NMWifiP2PPeer *nm_wifi_p2p_peer_lookup_for_device(NMDevice *device, const char *exported_path); - -#endif /* __NM_WIFI_P2P_PEER_H__ */ diff --git a/src/devices/wifi/nm-wifi-utils.c b/src/devices/wifi/nm-wifi-utils.c deleted file mode 100644 index e371d197..00000000 --- a/src/devices/wifi/nm-wifi-utils.c +++ /dev/null @@ -1,919 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-wifi-utils.h" - -#include <stdlib.h> - -#include "nm-utils.h" -#include "nm-core-internal.h" - -static gboolean -verify_no_wep(NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error) -{ - if (nm_setting_wireless_security_get_wep_key(s_wsec, 0) - || nm_setting_wireless_security_get_wep_key(s_wsec, 1) - || nm_setting_wireless_security_get_wep_key(s_wsec, 2) - || nm_setting_wireless_security_get_wep_key(s_wsec, 3) - || nm_setting_wireless_security_get_wep_tx_keyidx(s_wsec) - || nm_setting_wireless_security_get_wep_key_type(s_wsec)) { - /* Dynamic WEP cannot have any WEP keys set */ - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("%s is incompatible with static WEP keys"), - tag); - g_prefix_error(error, "%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); - return FALSE; - } - - return TRUE; -} - -static gboolean -verify_leap(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, - gboolean adhoc, - GError ** error) -{ - const char *key_mgmt, *auth_alg, *leap_username; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - auth_alg = nm_setting_wireless_security_get_auth_alg(s_wsec); - leap_username = nm_setting_wireless_security_get_leap_username(s_wsec); - - /* One (or both) of two things indicates we want LEAP: - * 1) auth_alg == 'leap' - * 2) valid leap_username - * - * LEAP always requires a LEAP username. - */ - - if (auth_alg) { - if (!strcmp(auth_alg, "leap")) { - /* LEAP authentication requires at least a LEAP username */ - if (!leap_username) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_MISSING_PROPERTY, - _("LEAP authentication requires a LEAP username")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME); - return FALSE; - } - } else if (leap_username) { - /* Leap username requires 'leap' auth */ - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("LEAP username requires 'leap' authentication")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME); - return FALSE; - } - } - - if (leap_username) { - if (key_mgmt && strcmp(key_mgmt, "ieee8021x")) { - /* LEAP requires ieee8021x key management */ - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("LEAP authentication requires IEEE 802.1x key management")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); - return FALSE; - } - } - - /* At this point if auth_alg is set it must be 'leap', and if key_mgmt - * is set it must be 'ieee8021x'. - */ - if (leap_username) { - if (auth_alg) - g_assert(strcmp(auth_alg, "leap") == 0); - if (key_mgmt) - g_assert(strcmp(key_mgmt, "ieee8021x") == 0); - - if (adhoc) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("LEAP authentication is incompatible with Ad-Hoc mode")); - g_prefix_error(error, "%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); - return FALSE; - } - - if (!verify_no_wep(s_wsec, "LEAP", error)) - return FALSE; - - if (s_8021x) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("LEAP authentication is incompatible with 802.1x setting")); - g_prefix_error(error, "%s: ", NM_SETTING_802_1X_SETTING_NAME); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -verify_no_wpa(NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error) -{ - const char *key_mgmt; - int n, i; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - if (key_mgmt && !strncmp(key_mgmt, "wpa", 3)) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("a connection using '%s' authentication cannot use WPA key management"), - tag); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); - return FALSE; - } - - if (nm_setting_wireless_security_get_num_protos(s_wsec)) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("a connection using '%s' authentication cannot specify WPA protocols"), - tag); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_PROTO); - return FALSE; - } - - n = nm_setting_wireless_security_get_num_pairwise(s_wsec); - for (i = 0; i < n; i++) { - const char *pw; - - pw = nm_setting_wireless_security_get_pairwise(s_wsec, i); - if (!strcmp(pw, "tkip") || !strcmp(pw, "ccmp")) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("a connection using '%s' authentication cannot specify WPA ciphers"), - tag); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_PAIRWISE); - return FALSE; - } - } - - n = nm_setting_wireless_security_get_num_groups(s_wsec); - for (i = 0; i < n; i++) { - const char *gr; - - gr = nm_setting_wireless_security_get_group(s_wsec, i); - if (strcmp(gr, "wep40") && strcmp(gr, "wep104")) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("a connection using '%s' authentication cannot specify WPA ciphers"), - tag); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_GROUP); - return FALSE; - } - } - - if (nm_setting_wireless_security_get_psk(s_wsec)) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("a connection using '%s' authentication cannot specify a WPA password"), - tag); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_PSK); - return FALSE; - } - - return TRUE; -} - -static gboolean -verify_dynamic_wep(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, - gboolean adhoc, - GError ** error) -{ - const char *key_mgmt, *auth_alg, *leap_username; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - auth_alg = nm_setting_wireless_security_get_auth_alg(s_wsec); - leap_username = nm_setting_wireless_security_get_leap_username(s_wsec); - - g_return_val_if_fail(leap_username == NULL, TRUE); - - if (key_mgmt) { - if (!strcmp(key_mgmt, "ieee8021x")) { - if (!s_8021x) { - /* 802.1x key management requires an 802.1x setting */ - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_MISSING_SETTING, - _("Dynamic WEP requires an 802.1x setting")); - g_prefix_error(error, "%s: ", NM_SETTING_802_1X_SETTING_NAME); - return FALSE; - } - - if (auth_alg && strcmp(auth_alg, "open")) { - /* 802.1x key management must use "open" authentication */ - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Dynamic WEP requires 'open' authentication")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG); - return FALSE; - } - - /* Dynamic WEP incompatible with anything static WEP related */ - if (!verify_no_wep(s_wsec, "Dynamic WEP", error)) - return FALSE; - } else if (!strcmp(key_mgmt, "none")) { - if (s_8021x) { - /* 802.1x setting requires 802.1x key management */ - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Dynamic WEP requires 'ieee8021x' key management")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); - return FALSE; - } - } - } else if (s_8021x) { - /* 802.1x setting incompatible with anything but 'open' auth */ - if (auth_alg && strcmp(auth_alg, "open")) { - /* 802.1x key management must use "open" authentication */ - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Dynamic WEP requires 'open' authentication")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG); - return FALSE; - } - - /* Dynamic WEP incompatible with anything static WEP related */ - if (!verify_no_wep(s_wsec, "Dynamic WEP", error)) - return FALSE; - } - - return TRUE; -} - -static gboolean -verify_wpa_psk(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, - gboolean adhoc, - guint32 wpa_flags, - guint32 rsn_flags, - GError ** error) -{ - const char *key_mgmt, *auth_alg; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - auth_alg = nm_setting_wireless_security_get_auth_alg(s_wsec); - - if (!nm_streq0(key_mgmt, "wpa-psk")) - return TRUE; - - if (s_8021x) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("WPA-PSK authentication is incompatible with 802.1x")); - g_prefix_error(error, "%s: ", NM_SETTING_802_1X_SETTING_NAME); - return FALSE; - } - - if (auth_alg && !nm_streq(auth_alg, "open")) { - /* WPA must use "open" authentication */ - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("WPA-PSK requires 'open' authentication")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG); - return FALSE; - } - - /* Make sure the AP's capabilities support WPA-PSK */ - if (!(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Access point does not support PSK but setting requires it")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); - return FALSE; - } - - if (adhoc) { - /* Ad-Hoc RSN requires 'rsn' proto, 'ccmp' pairwise, and 'ccmp' group */ - if (nm_setting_wireless_security_get_num_protos(s_wsec) != 1 - || !nm_streq0(nm_setting_wireless_security_get_proto(s_wsec, 0), "rsn")) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("WPA Ad-Hoc authentication requires 'rsn' protocol")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_PROTO); - return FALSE; - } - - if (nm_setting_wireless_security_get_num_pairwise(s_wsec) != 1 - || !nm_streq0(nm_setting_wireless_security_get_pairwise(s_wsec, 0), "ccmp")) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("WPA Ad-Hoc authentication requires 'ccmp' pairwise cipher")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_PAIRWISE); - return FALSE; - } - - if (nm_setting_wireless_security_get_num_groups(s_wsec) != 1 - || !nm_streq0(nm_setting_wireless_security_get_group(s_wsec, 0), "ccmp")) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("WPA Ad-Hoc requires 'ccmp' group cipher")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_GROUP); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -verify_wpa_eap(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, - guint32 wpa_flags, - guint32 rsn_flags, - GError ** error) -{ - const char *key_mgmt, *auth_alg; - gboolean is_wpa_eap = FALSE; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - auth_alg = nm_setting_wireless_security_get_auth_alg(s_wsec); - - if (key_mgmt) { - if (!strcmp(key_mgmt, "wpa-eap")) { - if (!s_8021x) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_MISSING_SETTING, - _("WPA-EAP authentication requires an 802.1x setting")); - g_prefix_error(error, "%s: ", NM_SETTING_802_1X_SETTING_NAME); - return FALSE; - } - - if (auth_alg && strcmp(auth_alg, "open")) { - /* WPA must use "open" authentication */ - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("WPA-EAP requires 'open' authentication")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG); - return FALSE; - } - - is_wpa_eap = TRUE; - } else if (s_8021x) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("802.1x setting requires 'wpa-eap' key management")); - g_prefix_error(error, "%s: ", NM_SETTING_802_1X_SETTING_NAME); - return FALSE; - } - } - - if (is_wpa_eap || s_8021x) { - /* Make sure the AP's capabilities support WPA-EAP */ - if (!(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X) - && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("Access point does not support 802.1x but setting requires it")); - g_prefix_error(error, "%s: ", NM_SETTING_802_1X_SETTING_NAME); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -verify_adhoc(NMSettingWirelessSecurity *s_wsec, - NMSetting8021x * s_8021x, - gboolean adhoc, - GError ** error) -{ - const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL; - - if (!adhoc) - return TRUE; - - if (s_wsec) { - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - auth_alg = nm_setting_wireless_security_get_auth_alg(s_wsec); - leap_username = nm_setting_wireless_security_get_leap_username(s_wsec); - } - - if (key_mgmt && !NM_IN_STRSET(key_mgmt, "none", "wpa-psk")) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Ad-Hoc mode requires 'none' or 'wpa-psk' key management")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); - return FALSE; - } - - if (s_8021x) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("Ad-Hoc mode is incompatible with 802.1x security")); - g_prefix_error(error, "%s: ", NM_SETTING_802_1X_SETTING_NAME); - return FALSE; - } - - if (leap_username) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Ad-Hoc mode is incompatible with LEAP security")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG); - return FALSE; - } - - if (auth_alg && !nm_streq(auth_alg, "open")) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Ad-Hoc mode requires 'open' authentication")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG); - return FALSE; - } - - return TRUE; -} - -gboolean -nm_wifi_utils_complete_connection(GBytes * ap_ssid, - const char * bssid, - NM80211Mode ap_mode, - guint32 ap_freq, - guint32 ap_flags, - guint32 ap_wpa_flags, - guint32 ap_rsn_flags, - NMConnection *connection, - gboolean lock_bssid, - GError ** error) -{ - NMSettingWireless * s_wifi; - NMSettingWirelessSecurity *s_wsec; - NMSetting8021x * s_8021x; - GBytes * ssid; - const char * mode, *key_mgmt, *auth_alg, *leap_username; - gboolean adhoc = FALSE; - gboolean mesh = FALSE; - - s_wifi = nm_connection_get_setting_wireless(connection); - g_assert(s_wifi); - s_wsec = nm_connection_get_setting_wireless_security(connection); - s_8021x = nm_connection_get_setting_802_1x(connection); - - /* Fill in missing SSID */ - ssid = nm_setting_wireless_get_ssid(s_wifi); - if (!ssid) - g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid, NULL); - else if (!ap_ssid || !g_bytes_equal(ssid, ap_ssid)) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match access point")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SETTING_NAME, - NM_SETTING_WIRELESS_SSID); - return FALSE; - } - - if (lock_bssid && !nm_setting_wireless_get_bssid(s_wifi)) - g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL); - - /* And mode */ - mode = nm_setting_wireless_get_mode(s_wifi); - if (mode) { - gboolean valid = FALSE; - - /* Make sure the supplied mode matches the AP's */ - if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_INFRA) - || !strcmp(mode, NM_SETTING_WIRELESS_MODE_AP)) { - if (ap_mode == NM_802_11_MODE_INFRA) - valid = TRUE; - } else if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_ADHOC)) { - if (ap_mode == NM_802_11_MODE_ADHOC) - valid = TRUE; - adhoc = TRUE; - } else if (!strcmp(mode, NM_SETTING_WIRELESS_MODE_MESH)) { - if (ap_mode == NM_802_11_MODE_MESH) - valid = TRUE; - mesh = TRUE; - } - - if (valid == FALSE) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match access point")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SETTING_NAME, - NM_SETTING_WIRELESS_MODE); - return FALSE; - } - } else { - mode = NM_SETTING_WIRELESS_MODE_INFRA; - if (ap_mode == NM_802_11_MODE_ADHOC) { - mode = NM_SETTING_WIRELESS_MODE_ADHOC; - adhoc = TRUE; - } else if (ap_mode == NM_802_11_MODE_MESH) { - mode = NM_SETTING_WIRELESS_MODE_MESH; - mesh = TRUE; - } - g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_MODE, mode, NULL); - } - - /* For now mesh requires channel and band, fill them only if both not present. - * Do not check existing values against an existing ap/mesh point, - * mesh join will start a new network if required */ - if (mesh) { - const char *band; - guint32 channel; - gboolean band_valid = TRUE; - gboolean chan_valid = TRUE; - gboolean valid; - - band = nm_setting_wireless_get_band(s_wifi); - channel = nm_setting_wireless_get_channel(s_wifi); - - valid = ((band == NULL) && (channel == 0)) || ((band != NULL) && (channel != 0)); - - if ((band == NULL) && (channel == 0)) { - channel = nm_utils_wifi_freq_to_channel(ap_freq); - if (channel) { - g_object_set(s_wifi, NM_SETTING_WIRELESS_CHANNEL, channel, NULL); - } else { - chan_valid = FALSE; - } - - band = nm_utils_wifi_freq_to_band(ap_freq); - if (band) { - g_object_set(s_wifi, NM_SETTING_WIRELESS_BAND, band, NULL); - } else { - band_valid = FALSE; - } - } - - if (!valid || !chan_valid || !band_valid) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match mesh point")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SETTING_NAME, - NM_SETTING_WIRELESS_MODE); - return FALSE; - } - } - - /* Security */ - - /* Open */ - if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY) && (ap_wpa_flags == NM_802_11_AP_SEC_NONE) - && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) { - /* Make sure the connection doesn't specify security */ - if (s_wsec || s_8021x) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("Access point is unencrypted but setting specifies security")); - if (s_wsec) - g_prefix_error(error, "%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME); - else - g_prefix_error(error, "%s: ", NM_SETTING_802_1X_SETTING_NAME); - return FALSE; - } - return TRUE; - } - - /* Everything else requires security */ - if (!s_wsec) { - s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wsec)); - } - - key_mgmt = nm_setting_wireless_security_get_key_mgmt(s_wsec); - auth_alg = nm_setting_wireless_security_get_auth_alg(s_wsec); - leap_username = nm_setting_wireless_security_get_leap_username(s_wsec); - - /* Ad-Hoc checks */ - if (!verify_adhoc(s_wsec, s_8021x, adhoc, error)) - return FALSE; - - /* Static WEP, Dynamic WEP, or LEAP */ - if ((ap_flags & NM_802_11_AP_FLAGS_PRIVACY) && (ap_wpa_flags == NM_802_11_AP_SEC_NONE) - && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) { - const char *tag = "WEP"; - gboolean is_dynamic_wep = FALSE; - - if (!verify_leap(s_wsec, s_8021x, adhoc, error)) - return FALSE; - - if (leap_username) { - tag = "LEAP"; - } else { - /* Static or Dynamic WEP */ - if (!verify_dynamic_wep(s_wsec, s_8021x, adhoc, error)) - return FALSE; - - if (s_8021x || (key_mgmt && !strcmp(key_mgmt, "ieee8021x"))) { - is_dynamic_wep = TRUE; - tag = "Dynamic WEP"; - } - } - - /* Nothing WPA-related can be set */ - if (!verify_no_wpa(s_wsec, tag, error)) - return FALSE; - - if (leap_username) { - /* LEAP */ - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "ieee8021x", - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, - "leap", - NULL); - } else if (is_dynamic_wep) { - /* Dynamic WEP */ - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "ieee8021x", - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, - "open", - NULL); - - if (s_8021x) { - /* Dynamic WEP requires a valid 802.1x setting since we can't - * autocomplete 802.1x. - */ - if (!nm_setting_verify(NM_SETTING(s_8021x), NULL, error)) - return FALSE; - } - } else { - /* Static WEP */ - g_object_set(s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL); - } - - return TRUE; - } - - /* WPA/RSN */ - g_assert(ap_wpa_flags || ap_rsn_flags); - - /* Ensure key management is valid for WPA */ - if ((key_mgmt && !strcmp(key_mgmt, "ieee8021x")) || leap_username) { - g_set_error_literal( - error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("WPA authentication is incompatible with non-EAP (original) LEAP or Dynamic WEP")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT); - return FALSE; - } - - /* 'shared' auth incompatible with any type of WPA */ - if (auth_alg && strcmp(auth_alg, "open")) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("WPA authentication is incompatible with Shared Key authentication")); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG); - return FALSE; - } - - if (!verify_no_wep(s_wsec, "WPA", error)) - return FALSE; - - if (!verify_wpa_psk(s_wsec, s_8021x, adhoc, ap_wpa_flags, ap_rsn_flags, error)) - return FALSE; - - if (!adhoc && !verify_wpa_eap(s_wsec, s_8021x, ap_wpa_flags, ap_rsn_flags, error)) - return FALSE; - - if (adhoc) { - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "wpa-psk", - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, - "open", - NULL); - nm_setting_wireless_security_add_proto(s_wsec, "rsn"); - nm_setting_wireless_security_add_pairwise(s_wsec, "ccmp"); - nm_setting_wireless_security_add_group(s_wsec, "ccmp"); - } else if (s_8021x) { - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "wpa-eap", - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, - "open", - NULL); - /* Leave proto/pairwise/group as client set them; if they are unset the - * supplicant will figure out the best combination at connect time. - */ - - /* 802.1x also requires the client to completely fill in the 8021x - * setting. Since there's so much configuration required for it, there's - * no way it can be automatically completed. - */ - } else if ((key_mgmt && !strcmp(key_mgmt, "sae")) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_SAE)) { - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "sae", - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, - "open", - NULL); - } else if ((key_mgmt && !strcmp(key_mgmt, "owe")) - || NM_FLAGS_ANY(ap_rsn_flags, - NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) { - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "owe", - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, - "open", - NULL); - } else if ((key_mgmt && !strcmp(key_mgmt, "wpa-psk")) - || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK) - || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) { - g_object_set(s_wsec, - NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, - "wpa-psk", - NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, - "open", - NULL); - /* Leave proto/pairwise/group as client set them; if they are unset the - * supplicant will figure out the best combination at connect time. - */ - } else { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_FAILED, - _("Failed to determine AP security information")); - return FALSE; - } - - return TRUE; -} - -gboolean -nm_wifi_utils_is_manf_default_ssid(GBytes *ssid) -{ - const guint8 *ssid_p; - gsize ssid_l; - int i; - /* - * List of manufacturer default SSIDs that are often unchanged by users. - * - * NOTE: this list should *not* contain networks that you would like to - * automatically roam to like "Starbucks" or "AT&T" or "T-Mobile HotSpot". - */ - static const char *manf_defaults[] = { - "linksys", - "linksys-a", - "linksys-g", - "default", - "belkin54g", - "NETGEAR", - "o2DSL", - "WLAN", - "ALICE-WLAN", - "Speedport W 501V", - "TURBONETT", - }; - - ssid_p = g_bytes_get_data(ssid, &ssid_l); - - for (i = 0; i < G_N_ELEMENTS(manf_defaults); i++) { - if (ssid_l == strlen(manf_defaults[i])) { - if (memcmp(manf_defaults[i], ssid_p, ssid_l) == 0) - return TRUE; - } - } - 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; -} diff --git a/src/devices/wifi/nm-wifi-utils.h b/src/devices/wifi/nm-wifi-utils.h deleted file mode 100644 index 678b353b..00000000 --- a/src/devices/wifi/nm-wifi-utils.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#ifndef __NM_WIFI_UTILS_H__ -#define __NM_WIFI_UTILS_H__ - -#include "nm-dbus-interface.h" -#include "nm-connection.h" -#include "nm-setting-wireless.h" -#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, - guint32 ap_freq, - guint32 flags, - guint32 wpa_flags, - guint32 rsn_flags, - NMConnection *connection, - gboolean lock_bssid, - GError ** error); - -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__ */ diff --git a/src/devices/wifi/tests/test-devices-wifi.c b/src/devices/wifi/tests/test-devices-wifi.c deleted file mode 100644 index 7be55860..00000000 --- a/src/devices/wifi/tests/test-devices-wifi.c +++ /dev/null @@ -1,1609 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "devices/wifi/nm-wifi-utils.h" -#include "devices/wifi/nm-device-wifi.h" -#include "nm-core-internal.h" - -#include "nm-test-utils-core.h" - -#define DEBUG 1 - -/*****************************************************************************/ - -#define COMPARE(src, expected, success, error, edomain, ecode) \ - { \ - if (expected) { \ - if (!success) { \ - g_assert(error != NULL); \ - g_warning("Failed to complete connection: %s", error->message); \ - } \ - g_assert(success == TRUE); \ - g_assert(error == NULL); \ - \ - success = nm_connection_compare(src, expected, NM_SETTING_COMPARE_FLAG_EXACT); \ - if (success == FALSE && DEBUG) { \ - g_print("\n- COMPLETED ---------------------------------\n"); \ - nm_connection_dump(src); \ - g_print("+ EXPECTED ++++++++++++++++++++++++++++++++++++\n"); \ - nm_connection_dump(expected); \ - g_print("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"); \ - } \ - g_assert(success == TRUE); \ - } else { \ - if (success) { \ - g_print("\n- COMPLETED ---------------------------------\n"); \ - nm_connection_dump(src); \ - } \ - g_assert(success == FALSE); \ - g_assert_error(error, edomain, ecode); \ - } \ - \ - g_clear_error(&error); \ - } - -static gboolean -complete_connection(const char * ssid, - const char * bssid, - NM80211Mode mode, - guint32 flags, - guint32 wpa_flags, - guint32 rsn_flags, - gboolean lock_bssid, - NMConnection *src, - GError ** error) -{ - gs_unref_bytes GBytes *ssid_b = NULL; - NMSettingWireless * s_wifi; - - /* Add a wifi setting if one doesn't exist */ - s_wifi = nm_connection_get_setting_wireless(src); - if (!s_wifi) { - s_wifi = (NMSettingWireless *) nm_setting_wireless_new(); - nm_connection_add_setting(src, NM_SETTING(s_wifi)); - } - - ssid_b = g_bytes_new(ssid, strlen(ssid)); - - return nm_wifi_utils_complete_connection(ssid_b, - bssid, - mode, - 0, - flags, - wpa_flags, - rsn_flags, - src, - lock_bssid, - error); -} - -typedef struct { - const char *key; - const char *str; - guint32 uint; -} KeyData; - -static void -set_items(NMSetting *setting, const KeyData *items) -{ - const KeyData *item; - GParamSpec * pspec; - GBytes * tmp; - - for (item = items; item && item->key; item++) { - g_assert(item->key); - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(setting), item->key); - g_assert(pspec); - - if (pspec->value_type == G_TYPE_STRING) { - g_assert(item->uint == 0); - if (item->str) - g_object_set(G_OBJECT(setting), item->key, item->str, NULL); - } else if (pspec->value_type == G_TYPE_UINT) { - g_assert(item->str == NULL); - g_object_set(G_OBJECT(setting), item->key, item->uint, NULL); - } else if (pspec->value_type == G_TYPE_INT) { - int foo = (int) item->uint; - - g_assert(item->str == NULL); - g_object_set(G_OBJECT(setting), item->key, foo, NULL); - } else if (pspec->value_type == G_TYPE_BOOLEAN) { - gboolean foo = !!(item->uint); - - g_assert(item->str == NULL); - g_object_set(G_OBJECT(setting), item->key, foo, NULL); - } else if (pspec->value_type == G_TYPE_BYTES) { - g_assert(item->str); - tmp = g_bytes_new(item->str, strlen(item->str)); - g_object_set(G_OBJECT(setting), item->key, tmp, NULL); - g_bytes_unref(tmp); - } else { - /* Special types, check based on property name */ - if (!strcmp(item->key, NM_SETTING_WIRELESS_SECURITY_PROTO)) - nm_setting_wireless_security_add_proto(NM_SETTING_WIRELESS_SECURITY(setting), - item->str); - else if (!strcmp(item->key, NM_SETTING_WIRELESS_SECURITY_PAIRWISE)) - nm_setting_wireless_security_add_pairwise(NM_SETTING_WIRELESS_SECURITY(setting), - item->str); - else if (!strcmp(item->key, NM_SETTING_WIRELESS_SECURITY_GROUP)) - nm_setting_wireless_security_add_group(NM_SETTING_WIRELESS_SECURITY(setting), - item->str); - else if (!strcmp(item->key, NM_SETTING_802_1X_EAP)) - nm_setting_802_1x_add_eap_method(NM_SETTING_802_1X(setting), item->str); - } - } -} - -static NMSettingWireless * -fill_wifi_empty(NMConnection *connection) -{ - NMSettingWireless *s_wifi; - - s_wifi = nm_connection_get_setting_wireless(connection); - if (!s_wifi) { - s_wifi = (NMSettingWireless *) nm_setting_wireless_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wifi)); - } - return s_wifi; -} - -static NMSettingWireless * -fill_wifi(NMConnection *connection, const KeyData items[]) -{ - NMSettingWireless *s_wifi; - - s_wifi = nm_connection_get_setting_wireless(connection); - if (!s_wifi) { - s_wifi = (NMSettingWireless *) nm_setting_wireless_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wifi)); - } - - set_items(NM_SETTING(s_wifi), items); - return s_wifi; -} - -static NMSettingWirelessSecurity * -fill_wsec(NMConnection *connection, const KeyData items[]) -{ - NMSettingWirelessSecurity *s_wsec; - - s_wsec = nm_connection_get_setting_wireless_security(connection); - if (!s_wsec) { - s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wsec)); - } - - set_items(NM_SETTING(s_wsec), items); - return s_wsec; -} - -static NMSetting8021x * -fill_8021x(NMConnection *connection, const KeyData items[]) -{ - NMSetting8021x *s_8021x; - - s_8021x = nm_connection_get_setting_802_1x(connection); - if (!s_8021x) { - s_8021x = (NMSetting8021x *) nm_setting_802_1x_new(); - nm_connection_add_setting(connection, NM_SETTING(s_8021x)); - } - - set_items(NM_SETTING(s_8021x), items); - return s_8021x; -} - -static NMConnection * -create_basic(const char *ssid, const char *bssid, NM80211Mode mode) -{ - NMConnection * connection; - NMSettingWireless *s_wifi = NULL; - GBytes * tmp; - - connection = nm_simple_connection_new(); - - s_wifi = (NMSettingWireless *) nm_setting_wireless_new(); - nm_connection_add_setting(connection, NM_SETTING(s_wifi)); - - /* SSID */ - tmp = g_bytes_new(ssid, strlen(ssid)); - g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_SSID, tmp, NULL); - g_bytes_unref(tmp); - - /* BSSID */ - if (bssid) - g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL); - - if (mode == NM_802_11_MODE_INFRA) - g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_MODE, "infrastructure", NULL); - else if (mode == NM_802_11_MODE_ADHOC) - g_object_set(G_OBJECT(s_wifi), NM_SETTING_WIRELESS_MODE, "adhoc", NULL); - else - g_assert_not_reached(); - - return connection; -} - -/*****************************************************************************/ - -static void -test_lock_bssid(void) -{ - NMConnection *src, *expected; - const char * bssid = "01:02:03:04:05:06"; - const char * ssid = "blahblah"; - gboolean success; - GError * error = NULL; - - src = nm_simple_connection_new(); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - TRUE, - src, - &error); - expected = create_basic(ssid, bssid, NM_802_11_MODE_INFRA); - COMPARE(src, expected, success, error, 0, 0); - - g_object_unref(src); - g_object_unref(expected); -} - -/*****************************************************************************/ - -static void -test_open_ap_empty_connection(void) -{ - NMConnection *src, *expected; - const char * bssid = "01:02:03:04:05:06"; - const char * ssid = "blahblah"; - gboolean success; - GError * error = NULL; - - /* Test that an empty source connection is correctly filled with the - * SSID and Infra modes of the given AP details. - */ - - src = nm_simple_connection_new(); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); - COMPARE(src, expected, success, error, 0, 0); - - g_object_unref(src); - g_object_unref(expected); -} - -/*****************************************************************************/ - -static void -test_open_ap_leap_connection_1(gconstpointer add_wifi) -{ - NMConnection *src; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, "Bill Smith", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that a basic connection filled with a LEAP username is - * rejected when completion is attempted with an open AP. LEAP requires - * the AP to have the Privacy bit set. - */ - - src = nm_simple_connection_new(); - if (add_wifi) - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - - success = complete_connection("blahblah", - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - /* We expect failure */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING); - - g_object_unref(src); -} - -/*****************************************************************************/ - -static void -test_open_ap_leap_connection_2(void) -{ - NMConnection *src; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that a basic connection specifying IEEE8021x security (ie, Dynamic - * WEP or LEAP) is rejected when completion is attempted with an open AP. - */ - - src = nm_simple_connection_new(); - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - - success = complete_connection("blahblah", - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - /* We expect failure */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING); - - g_object_unref(src); -} - -/*****************************************************************************/ - -static void -test_open_ap_wep_connection(gconstpointer add_wifi) -{ - NMConnection *src; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = { - {NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, "11111111111111111111111111", 0}, - {NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, NULL, 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that a static WEP connection is rejected when completion is - * attempted with an open AP. - */ - - src = nm_simple_connection_new(); - if (add_wifi) - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - success = complete_connection("blahblah", - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - /* We expect failure */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING); - - g_object_unref(src); -} - -/*****************************************************************************/ - -static void -test_ap_wpa_psk_connection_base(const char * key_mgmt, - const char * auth_alg, - guint32 flags, - guint32 wpa_flags, - guint32 rsn_flags, - gboolean add_wifi, - guint error_code, - NMConnection *expected) -{ - NMConnection *src; - const char * ssid = "blahblah"; - const char * bssid = "01:02:03:04:05:06"; - const KeyData exp_wifi[] = {{NM_SETTING_WIRELESS_SSID, ssid, 0}, - {NM_SETTING_WIRELESS_MODE, "infrastructure", 0}, - {NULL}}; - const KeyData both_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, 0}, - {NM_SETTING_WIRELESS_SECURITY_PSK, "asdfasdfasdfasdfasdfafs", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - src = nm_simple_connection_new(); - if (add_wifi) - fill_wifi_empty(src); - fill_wsec(src, both_wsec); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - flags, - wpa_flags, - rsn_flags, - FALSE, - src, - &error); - if (expected) { - fill_wifi(expected, exp_wifi); - fill_wsec(expected, both_wsec); - } - COMPARE(src, expected, success, error, NM_CONNECTION_ERROR, error_code); - - g_object_unref(src); -} - -static void -test_open_ap_wpa_psk_connection_1(void) -{ - /* Test that a WPA-PSK connection filling only the PSK itself and *not* - * filling the wifi setting is rejected when completion is attempted with - * an open AP. - */ - test_ap_wpa_psk_connection_base(NULL, - NULL, - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - NM_CONNECTION_ERROR_INVALID_SETTING, - NULL); -} - -static void -test_open_ap_wpa_psk_connection_2(void) -{ - /* Test that a WPA-PSK connection filling only the PSK itself and also - * filling the wifi setting is rejected when completion is attempted with - * an open AP. - */ - test_ap_wpa_psk_connection_base(NULL, - NULL, - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - TRUE, - NM_CONNECTION_ERROR_INVALID_SETTING, - NULL); -} - -static void -test_open_ap_wpa_psk_connection_3(void) -{ - /* Test that a WPA-PSK connection filling the PSK and setting the auth alg - * to 'open' is rejected when completion is attempted with an open AP. - */ - test_ap_wpa_psk_connection_base(NULL, - "open", - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - NM_CONNECTION_ERROR_INVALID_SETTING, - NULL); -} - -static void -test_open_ap_wpa_psk_connection_4(void) -{ - /* Test that a WPA-PSK connection filling the PSK and setting the auth alg - * to 'shared' is rejected when completion is attempted with an open AP. - * Shared auth cannot be used with WPA. - */ - test_ap_wpa_psk_connection_base(NULL, - "shared", - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - NM_CONNECTION_ERROR_INVALID_SETTING, - NULL); -} - -static void -test_open_ap_wpa_psk_connection_5(void) -{ - /* Test that a WPA-PSK connection filling the PSK, the auth algorithm, and - * key management is rejected when completion is attempted with an open AP. - */ - test_ap_wpa_psk_connection_base("wpa-psk", - "open", - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - NM_CONNECTION_ERROR_INVALID_SETTING, - NULL); -} - -/*****************************************************************************/ - -static void -test_ap_wpa_eap_connection_base(const char *key_mgmt, - const char *auth_alg, - guint32 flags, - guint32 wpa_flags, - guint32 rsn_flags, - gboolean add_wifi, - guint error_code) -{ - NMConnection *src; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_empty[] = {{NULL}}; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, key_mgmt, 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, auth_alg, 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - src = nm_simple_connection_new(); - if (add_wifi) - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - fill_8021x(src, src_empty); - success = complete_connection("blahblah", - bssid, - NM_802_11_MODE_INFRA, - flags, - wpa_flags, - rsn_flags, - FALSE, - src, - &error); - /* Failure expected */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, error_code); - - g_object_unref(src); -} - -enum { - IDX_NONE = 0, - IDX_OPEN, - IDX_PRIV, - IDX_WPA_PSK_PTKIP_GTKIP, - IDX_WPA_PSK_PTKIP_PCCMP_GTKIP, - IDX_WPA_RSN_PSK_PTKIP_PCCMP_GTKIP, - IDX_WPA_RSN_PSK_PCCMP_GCCMP, - IDX_RSN_PSK_PCCMP_GCCMP, - IDX_RSN_PSK_PTKIP_PCCMP_GTKIP, - IDX_WPA_8021X, - IDX_RSN_8021X, -}; - -static guint32 -flags_for_idx(guint32 idx) -{ - if (idx == IDX_OPEN) - return NM_802_11_AP_FLAGS_NONE; - else if (idx == IDX_PRIV || idx == IDX_WPA_PSK_PTKIP_GTKIP - || idx == IDX_WPA_PSK_PTKIP_PCCMP_GTKIP || idx == IDX_RSN_PSK_PCCMP_GCCMP - || idx == IDX_RSN_PSK_PTKIP_PCCMP_GTKIP || idx == IDX_WPA_RSN_PSK_PTKIP_PCCMP_GTKIP - || idx == IDX_WPA_RSN_PSK_PCCMP_GCCMP || idx == IDX_WPA_8021X || idx == IDX_RSN_8021X) - return NM_802_11_AP_FLAGS_PRIVACY; - else - g_assert_not_reached(); -} - -static guint32 -wpa_flags_for_idx(guint32 idx) -{ - if (idx == IDX_OPEN || idx == IDX_PRIV || idx == IDX_RSN_8021X || idx == IDX_RSN_PSK_PCCMP_GCCMP - || idx == IDX_RSN_PSK_PTKIP_PCCMP_GTKIP) - return NM_802_11_AP_SEC_NONE; - else if (idx == IDX_WPA_PSK_PTKIP_GTKIP) - return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_GROUP_TKIP - | NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (idx == IDX_WPA_RSN_PSK_PTKIP_PCCMP_GTKIP) - return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_TKIP - | NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (NM_IN_SET(idx, IDX_WPA_PSK_PTKIP_PCCMP_GTKIP, IDX_WPA_RSN_PSK_PCCMP_GCCMP)) - return NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_CCMP - | NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (idx == IDX_WPA_8021X) - return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_GROUP_TKIP - | NM_802_11_AP_SEC_KEY_MGMT_802_1X; - else - g_assert_not_reached(); -} - -static guint32 -rsn_flags_for_idx(guint32 idx) -{ - if (idx == IDX_OPEN || idx == IDX_PRIV || idx == IDX_WPA_8021X || idx == IDX_WPA_PSK_PTKIP_GTKIP - || idx == IDX_WPA_PSK_PTKIP_PCCMP_GTKIP) - return NM_802_11_AP_SEC_NONE; - else if (idx == IDX_RSN_PSK_PCCMP_GCCMP) - return NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_CCMP - | NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (idx == IDX_RSN_PSK_PTKIP_PCCMP_GTKIP) - return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_TKIP - | NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (idx == IDX_WPA_RSN_PSK_PTKIP_PCCMP_GTKIP) - return NM_802_11_AP_SEC_PAIR_TKIP | NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_TKIP - | NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (idx == IDX_WPA_RSN_PSK_PCCMP_GCCMP) - return NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_CCMP - | NM_802_11_AP_SEC_KEY_MGMT_PSK; - else if (idx == IDX_RSN_8021X) - return NM_802_11_AP_SEC_PAIR_CCMP | NM_802_11_AP_SEC_GROUP_CCMP - | NM_802_11_AP_SEC_KEY_MGMT_802_1X; - else - g_assert_not_reached(); -} - -static guint32 -error_code_for_idx(guint32 idx, guint num) -{ - if (idx == IDX_OPEN) - return NM_CONNECTION_ERROR_INVALID_SETTING; - else if (idx == IDX_PRIV) { - if (num <= 3) - return NM_CONNECTION_ERROR_MISSING_PROPERTY; - else - return NM_CONNECTION_ERROR_INVALID_PROPERTY; - } else if (idx == IDX_WPA_PSK_PTKIP_GTKIP || idx == IDX_WPA_PSK_PTKIP_PCCMP_GTKIP - || idx == IDX_WPA_RSN_PSK_PCCMP_GCCMP || idx == IDX_WPA_RSN_PSK_PTKIP_PCCMP_GTKIP - || idx == IDX_RSN_PSK_PTKIP_PCCMP_GTKIP || idx == IDX_RSN_PSK_PCCMP_GCCMP) - if (num == 4) - return NM_CONNECTION_ERROR_INVALID_PROPERTY; - else - return NM_CONNECTION_ERROR_INVALID_SETTING; - else - g_assert_not_reached(); -} - -static void -test_ap_wpa_eap_connection_1(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - - test_ap_wpa_eap_connection_base(NULL, - NULL, - flags_for_idx(idx), - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - error_code_for_idx(idx, 1)); -} - -static void -test_ap_wpa_eap_connection_2(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - - test_ap_wpa_eap_connection_base(NULL, - NULL, - flags_for_idx(idx), - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - TRUE, - error_code_for_idx(idx, 2)); -} - -static void -test_ap_wpa_eap_connection_3(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - - test_ap_wpa_eap_connection_base(NULL, - "open", - flags_for_idx(idx), - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - error_code_for_idx(idx, 3)); -} - -static void -test_ap_wpa_eap_connection_4(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - - test_ap_wpa_eap_connection_base(NULL, - "shared", - flags_for_idx(idx), - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - error_code_for_idx(idx, 4)); -} - -static void -test_ap_wpa_eap_connection_5(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - - test_ap_wpa_eap_connection_base("wpa-eap", - "open", - flags_for_idx(idx), - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - error_code_for_idx(idx, 5)); -} - -/*****************************************************************************/ - -static void -test_priv_ap_empty_connection(void) -{ - NMConnection *src, *expected; - const char * bssid = "01:02:03:04:05:06"; - const char * ssid = "blahblah"; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", 0}, {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that an empty connection is completed to a valid Static WEP - * connection when completed with an AP with the Privacy bit set. - */ - - src = nm_simple_connection_new(); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - - /* Static WEP connection expected */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); - fill_wsec(expected, exp_wsec); - COMPARE(src, expected, success, error, 0, 0); - - g_object_unref(src); - g_object_unref(expected); -} - -/*****************************************************************************/ - -static void -test_priv_ap_leap_connection_1(gconstpointer add_wifi) -{ - NMConnection *src, *expected; - const char * ssid = "blahblah"; - const char * bssid = "01:02:03:04:05:06"; - const char * leap_username = "Bill Smith"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, - {NULL}}; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0}, - {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that an minimal LEAP connection specifying only key management and - * the LEAP username is completed to a full LEAP connection when completed - * with an AP with the Privacy bit set. - */ - - src = nm_simple_connection_new(); - if (add_wifi) - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - /* We expect success here; since LEAP APs just set the 'privacy' flag - * there's no way to determine from the AP's beacon whether it's static WEP, - * dynamic WEP, or LEAP. - */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); - fill_wsec(expected, exp_wsec); - COMPARE(src, expected, success, error, 0, 0); - - g_object_unref(src); - g_object_unref(expected); -} - -/*****************************************************************************/ - -static void -test_priv_ap_leap_connection_2(void) -{ - NMConnection *src; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that an minimal LEAP connection specifying only key management and - * the LEAP auth alg is completed to a full LEAP connection when completed - * with an AP with the Privacy bit set. - */ - - src = nm_simple_connection_new(); - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - success = complete_connection("blahblah", - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - /* We expect failure here, we need a LEAP username */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY); - - g_object_unref(src); -} - -/*****************************************************************************/ - -static void -test_priv_ap_dynamic_wep_1(void) -{ - NMConnection *src, *expected; - const char * ssid = "blahblah"; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - const KeyData both_8021x[] = {{NM_SETTING_802_1X_EAP, "peap", 0}, - {NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0}, - {NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0}, - {NULL}}; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that an minimal Dynamic WEP connection specifying key management, - * the auth algorithm, and valid 802.1x setting is completed to a valid - * Dynamic WEP connection when completed with an AP with the Privacy bit set. - */ - - src = nm_simple_connection_new(); - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - fill_8021x(src, both_8021x); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - - /* We expect a completed Dynamic WEP connection */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); - fill_wsec(expected, exp_wsec); - fill_8021x(expected, both_8021x); - COMPARE(src, expected, success, error, 0, 0); - - g_object_unref(src); - g_object_unref(expected); -} - -/*****************************************************************************/ - -static void -test_priv_ap_dynamic_wep_2(void) -{ - NMConnection *src, *expected; - const char * ssid = "blahblah"; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, {NULL}}; - const KeyData both_8021x[] = {{NM_SETTING_802_1X_EAP, "peap", 0}, - {NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0}, - {NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0}, - {NULL}}; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that an minimal Dynamic WEP connection specifying only the auth - * algorithm and a valid 802.1x setting is completed to a valid Dynamic - * WEP connection when completed with an AP with the Privacy bit set. - */ - - src = nm_simple_connection_new(); - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - fill_8021x(src, both_8021x); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - - /* We expect a completed Dynamic WEP connection */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); - fill_wsec(expected, exp_wsec); - fill_8021x(expected, both_8021x); - COMPARE(src, expected, success, error, 0, 0); - - g_object_unref(src); - g_object_unref(expected); -} - -/*****************************************************************************/ - -static void -test_priv_ap_dynamic_wep_3(void) -{ - NMConnection *src; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", 0}, {NULL}}; - const KeyData src_8021x[] = {{NM_SETTING_802_1X_EAP, "peap", 0}, - {NM_SETTING_802_1X_IDENTITY, "Bill Smith", 0}, - {NM_SETTING_802_1X_PHASE2_AUTH, "mschapv2", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Ensure that a basic connection specifying 'shared' auth and an 802.1x - * setting is rejected, as 802.1x is incompatible with 'shared' auth. - */ - - src = nm_simple_connection_new(); - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - fill_8021x(src, src_8021x); - success = complete_connection("blahblah", - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - src, - &error); - /* Expect failure; shared is not compatible with dynamic WEP */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); - - g_object_unref(src); -} - -/*****************************************************************************/ - -static void -test_priv_ap_wpa_psk_connection_1(void) -{ - /* Test that a basic WPA-PSK connection is rejected when completion is - * attempted with an AP with just the Privacy bit set. Lack of WPA/RSN - * flags means the AP provides Static/Dynamic WEP or LEAP, not WPA. - */ - test_ap_wpa_psk_connection_base(NULL, - NULL, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - NULL); -} - -static void -test_priv_ap_wpa_psk_connection_2(void) -{ - /* Test that a basic WPA-PSK connection is rejected when completion is - * attempted with an AP with just the Privacy bit set. Lack of WPA/RSN - * flags means the AP provides Static/Dynamic WEP or LEAP, not WPA. - */ - test_ap_wpa_psk_connection_base(NULL, - NULL, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - TRUE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - NULL); -} - -static void -test_priv_ap_wpa_psk_connection_3(void) -{ - /* Test that a basic WPA-PSK connection specifying only the auth algorithm - * is rejected when completion is attempted with an AP with just the Privacy - * bit set. Lack of WPA/RSN flags means the AP provides Static/Dynamic WEP - * or LEAP, not WPA. - */ - test_ap_wpa_psk_connection_base(NULL, - "open", - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - NULL); -} - -static void -test_priv_ap_wpa_psk_connection_4(void) -{ - /* Test that a basic WPA-PSK connection specifying only the auth algorithm - * is rejected when completion is attempted with an AP with just the Privacy - * bit set. Lack of WPA/RSN flags means the AP provides Static/Dynamic WEP - * or LEAP, not WPA. Second, 'shared' auth is incompatible with WPA. - */ - test_ap_wpa_psk_connection_base(NULL, - "shared", - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - NULL); -} - -static void -test_priv_ap_wpa_psk_connection_5(void) -{ - /* Test that a WPA-PSK connection specifying both the key management and - * auth algorithm is rejected when completion is attempted with an AP with - * just the Privacy bit set. Lack of WPA/RSN flags means the AP provides - * Static/Dynamic WEP or LEAP, not WPA. - */ - test_ap_wpa_psk_connection_base("wpa-psk", - "open", - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_SEC_NONE, - NM_802_11_AP_SEC_NONE, - FALSE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - NULL); -} - -/*****************************************************************************/ - -static void -test_wpa_ap_empty_connection(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - NMConnection *src, *expected; - const char * bssid = "01:02:03:04:05:06"; - const char * ssid = "blahblah"; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that a basic WPA-PSK connection specifying just key management and - * the auth algorithm is completed successfully when given an AP with WPA - * or RSN flags. - */ - - src = nm_simple_connection_new(); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - src, - &error); - - /* WPA connection expected */ - expected = create_basic(ssid, NULL, NM_802_11_MODE_INFRA); - fill_wsec(expected, exp_wsec); - COMPARE(src, expected, success, error, 0, 0); - - g_object_unref(src); - g_object_unref(expected); -} - -/*****************************************************************************/ - -static void -test_wpa_ap_leap_connection_1(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - NMConnection *src; - const char * ssid = "blahblah"; - const char * bssid = "01:02:03:04:05:06"; - const char * leap_username = "Bill Smith"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, leap_username, 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that completion of a LEAP connection with a WPA-enabled AP is - * rejected since WPA APs (usually) do not support LEAP. - */ - - src = nm_simple_connection_new(); - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - success = complete_connection(ssid, - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - src, - &error); - /* Expect failure here; WPA APs don't support old-school LEAP */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); - - g_object_unref(src); -} - -/*****************************************************************************/ - -static void -test_wpa_ap_leap_connection_2(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - NMConnection *src; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap", 0}, - {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that completion of a LEAP connection with a WPA-enabled AP is - * rejected since WPA APs (usually) do not support LEAP. - */ - - src = nm_simple_connection_new(); - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - success = complete_connection("blahblah", - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - src, - &error); - /* We expect failure here, we need a LEAP username */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); - - g_object_unref(src); -} - -/*****************************************************************************/ - -static void -test_wpa_ap_dynamic_wep_connection(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - NMConnection *src; - const char * bssid = "01:02:03:04:05:06"; - const KeyData src_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", 0}, {NULL}}; - gboolean success; - GError * error = NULL; - - /* Test that completion of a Dynamic WEP connection with a WPA-enabled AP is - * rejected since WPA APs (usually) do not support Dynamic WEP. - */ - - src = nm_simple_connection_new(); - fill_wifi_empty(src); - fill_wsec(src, src_wsec); - success = complete_connection("blahblah", - bssid, - NM_802_11_MODE_INFRA, - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - src, - &error); - /* We expect failure here since Dynamic WEP is incompatible with WPA */ - COMPARE(src, NULL, success, error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY); - - g_object_unref(src); -} - -/*****************************************************************************/ - -static void -test_wpa_ap_wpa_psk_connection_1(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - NMConnection *expected; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - - expected = nm_simple_connection_new(); - fill_wsec(expected, exp_wsec); - test_ap_wpa_psk_connection_base(NULL, - NULL, - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - expected); - g_object_unref(expected); -} - -static void -test_wpa_ap_wpa_psk_connection_2(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - NMConnection *expected; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - - expected = nm_simple_connection_new(); - fill_wsec(expected, exp_wsec); - test_ap_wpa_psk_connection_base(NULL, - NULL, - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - TRUE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - expected); - g_object_unref(expected); -} - -static void -test_wpa_ap_wpa_psk_connection_3(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - NMConnection *expected; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - - expected = nm_simple_connection_new(); - fill_wsec(expected, exp_wsec); - test_ap_wpa_psk_connection_base(NULL, - "open", - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - expected); - g_object_unref(expected); -} - -static void -test_wpa_ap_wpa_psk_connection_4(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - test_ap_wpa_psk_connection_base(NULL, - "shared", - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - NULL); -} - -static void -test_wpa_ap_wpa_psk_connection_5(gconstpointer data) -{ - guint idx = GPOINTER_TO_UINT(data); - NMConnection *expected; - const KeyData exp_wsec[] = {{NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", 0}, - {NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", 0}, - {NULL}}; - - expected = nm_simple_connection_new(); - fill_wsec(expected, exp_wsec); - test_ap_wpa_psk_connection_base("wpa-psk", - "open", - NM_802_11_AP_FLAGS_PRIVACY, - wpa_flags_for_idx(idx), - rsn_flags_for_idx(idx), - FALSE, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - expected); - g_object_unref(expected); -} - -/*****************************************************************************/ - -static void -test_strength_dbm(void) -{ - /* boundary conditions first */ - g_assert_cmpint(nm_wifi_utils_level_to_quality(-1), ==, 100); - g_assert_cmpint(nm_wifi_utils_level_to_quality(-40), ==, 100); - g_assert_cmpint(nm_wifi_utils_level_to_quality(-30), ==, 100); - g_assert_cmpint(nm_wifi_utils_level_to_quality(-100), ==, 0); - g_assert_cmpint(nm_wifi_utils_level_to_quality(-200), ==, 0); - - g_assert_cmpint(nm_wifi_utils_level_to_quality(-81), ==, 32); - g_assert_cmpint(nm_wifi_utils_level_to_quality(-92), ==, 14); - g_assert_cmpint(nm_wifi_utils_level_to_quality(-74), ==, 44); - g_assert_cmpint(nm_wifi_utils_level_to_quality(-81), ==, 32); - g_assert_cmpint(nm_wifi_utils_level_to_quality(-66), ==, 57); -} - -static void -test_strength_percent(void) -{ - int i; - - /* boundary conditions first */ - g_assert_cmpint(nm_wifi_utils_level_to_quality(0), ==, 0); - g_assert_cmpint(nm_wifi_utils_level_to_quality(100), ==, 100); - g_assert_cmpint(nm_wifi_utils_level_to_quality(110), ==, 100); - - for (i = 0; i <= 100; i++) - g_assert_cmpint(nm_wifi_utils_level_to_quality(i), ==, i); -} - -static void -test_strength_wext(void) -{ - /* boundary conditions that we assume aren't WEXT first */ - g_assert_cmpint(nm_wifi_utils_level_to_quality(256), ==, 100); - g_assert_cmpint(nm_wifi_utils_level_to_quality(110), ==, 100); - - /* boundary conditions that we assume are WEXT */ - g_assert_cmpint(nm_wifi_utils_level_to_quality(111), ==, 0); - g_assert_cmpint(nm_wifi_utils_level_to_quality(150), ==, 0); - g_assert_cmpint(nm_wifi_utils_level_to_quality(225), ==, 100); - g_assert_cmpint(nm_wifi_utils_level_to_quality(255), ==, 100); - - g_assert_cmpint(nm_wifi_utils_level_to_quality(157), ==, 2); - g_assert_cmpint(nm_wifi_utils_level_to_quality(200), ==, 74); - g_assert_cmpint(nm_wifi_utils_level_to_quality(215), ==, 99); -} - -#define _assert_strength_in_range(x) \ - ({ \ - guint32 _x = (x); \ - g_assert_cmpint(_x, >=, 0); \ - g_assert_cmpint(_x, <=, 100); \ - }) - -static void -test_strength_all(void) -{ - int val; - - for (val = -200; val < 300; val++) - _assert_strength_in_range(nm_wifi_utils_level_to_quality(val)); - _assert_strength_in_range(nm_wifi_utils_level_to_quality(G_MININT)); - _assert_strength_in_range(nm_wifi_utils_level_to_quality(G_MAXINT)); - _assert_strength_in_range(nm_wifi_utils_level_to_quality(G_MININT32)); - _assert_strength_in_range(nm_wifi_utils_level_to_quality(G_MAXINT32)); - _assert_strength_in_range(nm_wifi_utils_level_to_quality(G_MININT16)); - _assert_strength_in_range(nm_wifi_utils_level_to_quality(G_MAXINT16)); -} - -/*****************************************************************************/ - -static void -do_test_ssids_options_to_ptrarray(const char *const *ssids) -{ - GVariantBuilder builder; - gs_unref_variant GVariant *variant = NULL; - gs_unref_ptrarray GPtrArray *ssids_arr = NULL; - gs_free_error GError *error = NULL; - gsize len; - gsize i; - - g_assert(ssids); - - len = NM_PTRARRAY_LEN(ssids); - - g_variant_builder_init(&builder, G_VARIANT_TYPE("aay")); - for (i = 0; i < len; i++) { - const char *ssid = ssids[i]; - - g_variant_builder_add( - &builder, - "@ay", - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, ssid, strlen(ssid), 1)); - } - variant = g_variant_builder_end(&builder); - - if (nmtst_get_rand_bool()) - g_variant_ref_sink(variant); - - ssids_arr = nmtst_ssids_options_to_ptrarray(variant, &error); - g_assert(!error); - if (len == 0) { - g_assert(!ssids_arr); - return; - } - g_assert_cmpint(len, ==, ssids_arr->len); - for (i = 0; i < len; i++) { - const char *ssid = ssids[i]; - GBytes * bytes = ssids_arr->pdata[i]; - - g_assert(nm_utils_gbytes_equal_mem(bytes, ssid, strlen(ssid))); - } -} - -static void -test_ssids_options_to_ptrarray(void) -{ - do_test_ssids_options_to_ptrarray(NM_PTRARRAY_EMPTY(const char *)); - do_test_ssids_options_to_ptrarray(NM_MAKE_STRV("ab")); - do_test_ssids_options_to_ptrarray(NM_MAKE_STRV("ab", "cd", "fsdfdsf")); -} - -/*****************************************************************************/ - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - gsize i; - - nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); - - g_test_add_func("/wifi/lock_bssid", test_lock_bssid); - - /* Open AP tests; make sure that connections to be completed that have - * various security-related settings already set cause the completion - * to fail. - */ - g_test_add_func("/wifi/open_ap/empty_connection", test_open_ap_empty_connection); - g_test_add_data_func("/wifi/open_ap/leap_connection/1", - (gconstpointer) TRUE, - test_open_ap_leap_connection_1); - g_test_add_data_func("/wifi/open_ap/leap_connection/1_no_add_wifi", - (gconstpointer) FALSE, - test_open_ap_leap_connection_1); - g_test_add_func("/wifi/open_ap/leap_connection/2", test_open_ap_leap_connection_2); - g_test_add_data_func("/wifi/open_ap/wep_connection_true", - (gconstpointer) TRUE, - test_open_ap_wep_connection); - g_test_add_data_func("/wifi/open_ap/wep_connection_false", - (gconstpointer) FALSE, - test_open_ap_wep_connection); - - g_test_add_func("/wifi/open_ap/wpa_psk_connection/1", test_open_ap_wpa_psk_connection_1); - g_test_add_func("/wifi/open_ap/wpa_psk_connection/2", test_open_ap_wpa_psk_connection_2); - g_test_add_func("/wifi/open_ap/wpa_psk_connection/3", test_open_ap_wpa_psk_connection_3); - g_test_add_func("/wifi/open_ap/wpa_psk_connection/4", test_open_ap_wpa_psk_connection_4); - g_test_add_func("/wifi/open_ap/wpa_psk_connection/5", test_open_ap_wpa_psk_connection_5); - - g_test_add_data_func("/wifi/open_ap/wpa_eap_connection/1", - (gconstpointer) IDX_OPEN, - test_ap_wpa_eap_connection_1); - g_test_add_data_func("/wifi/open_ap/wpa_eap_connection/2", - (gconstpointer) IDX_OPEN, - test_ap_wpa_eap_connection_2); - g_test_add_data_func("/wifi/open_ap/wpa_eap_connection/3", - (gconstpointer) IDX_OPEN, - test_ap_wpa_eap_connection_3); - g_test_add_data_func("/wifi/open_ap/wpa_eap_connection/4", - (gconstpointer) IDX_OPEN, - test_ap_wpa_eap_connection_4); - g_test_add_data_func("/wifi/open_ap/wpa_eap_connection/5", - (gconstpointer) IDX_OPEN, - test_ap_wpa_eap_connection_5); - - /* WEP AP tests */ - g_test_add_func("/wifi/priv_ap/empty_connection", test_priv_ap_empty_connection); - g_test_add_data_func("/wifi/priv_ap/leap_connection/1", - (gconstpointer) FALSE, - test_priv_ap_leap_connection_1); - g_test_add_func("/wifi/priv_ap/leap_connection/2", test_priv_ap_leap_connection_2); - - g_test_add_func("/wifi/priv_ap/dynamic_wep/1", test_priv_ap_dynamic_wep_1); - g_test_add_func("/wifi/priv_ap/dynamic_wep/2", test_priv_ap_dynamic_wep_2); - g_test_add_func("/wifi/priv_ap/dynamic_wep/3", test_priv_ap_dynamic_wep_3); - - g_test_add_func("/wifi/priv_ap/wpa_psk_connection/1", test_priv_ap_wpa_psk_connection_1); - g_test_add_func("/wifi/priv_ap/wpa_psk_connection/2", test_priv_ap_wpa_psk_connection_2); - g_test_add_func("/wifi/priv_ap/wpa_psk_connection/3", test_priv_ap_wpa_psk_connection_3); - g_test_add_func("/wifi/priv_ap/wpa_psk_connection/4", test_priv_ap_wpa_psk_connection_4); - g_test_add_func("/wifi/priv_ap/wpa_psk_connection/5", test_priv_ap_wpa_psk_connection_5); - - g_test_add_data_func("/wifi/priv_ap/wpa_eap_connection/1", - (gconstpointer) IDX_PRIV, - test_ap_wpa_eap_connection_1); - g_test_add_data_func("/wifi/priv_ap/wpa_eap_connection/2", - (gconstpointer) IDX_PRIV, - test_ap_wpa_eap_connection_2); - g_test_add_data_func("/wifi/priv_ap/wpa_eap_connection/3", - (gconstpointer) IDX_PRIV, - test_ap_wpa_eap_connection_3); - g_test_add_data_func("/wifi/priv_ap/wpa_eap_connection/4", - (gconstpointer) IDX_PRIV, - test_ap_wpa_eap_connection_4); - g_test_add_data_func("/wifi/priv_ap/wpa_eap_connection/5", - (gconstpointer) IDX_PRIV, - test_ap_wpa_eap_connection_5); - -#define ADD_FUNC(func) \ - do { \ - char *name_idx = g_strdup_printf("/wifi/wpa_psk/" G_STRINGIFY(func) "/%zd", i); \ - g_test_add_data_func(name_idx, (gconstpointer) i, func); \ - g_free(name_idx); \ - } while (0) - - /* WPA-PSK tests */ - for (i = IDX_WPA_PSK_PTKIP_GTKIP; i <= IDX_WPA_RSN_PSK_PCCMP_GCCMP; i++) { - ADD_FUNC(test_wpa_ap_empty_connection); - ADD_FUNC(test_wpa_ap_leap_connection_1); - ADD_FUNC(test_wpa_ap_leap_connection_2); - ADD_FUNC(test_wpa_ap_dynamic_wep_connection); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_1); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_2); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_3); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_4); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_5); - ADD_FUNC(test_ap_wpa_eap_connection_1); - ADD_FUNC(test_ap_wpa_eap_connection_2); - ADD_FUNC(test_ap_wpa_eap_connection_3); - ADD_FUNC(test_ap_wpa_eap_connection_4); - ADD_FUNC(test_ap_wpa_eap_connection_5); - } - -#undef ADD_FUNC -#define ADD_FUNC(func) \ - do { \ - char *name_idx = g_strdup_printf("/wifi/rsn_psk/" G_STRINGIFY(func) "/%zd", i); \ - g_test_add_data_func(name_idx, (gconstpointer) i, func); \ - g_free(name_idx); \ - } while (0) - - /* RSN-PSK tests */ - for (i = IDX_WPA_RSN_PSK_PTKIP_PCCMP_GTKIP; i <= IDX_RSN_PSK_PTKIP_PCCMP_GTKIP; i++) { - ADD_FUNC(test_wpa_ap_empty_connection); - ADD_FUNC(test_wpa_ap_leap_connection_1); - ADD_FUNC(test_wpa_ap_leap_connection_2); - ADD_FUNC(test_wpa_ap_dynamic_wep_connection); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_1); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_2); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_3); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_4); - ADD_FUNC(test_wpa_ap_wpa_psk_connection_5); - ADD_FUNC(test_ap_wpa_eap_connection_1); - ADD_FUNC(test_ap_wpa_eap_connection_2); - ADD_FUNC(test_ap_wpa_eap_connection_3); - ADD_FUNC(test_ap_wpa_eap_connection_4); - ADD_FUNC(test_ap_wpa_eap_connection_5); - } - -#undef ADD_FUNC - - /* Scanned signal strength conversion tests */ - g_test_add_func("/wifi/strength/dbm", test_strength_dbm); - g_test_add_func("/wifi/strength/percent", test_strength_percent); - g_test_add_func("/wifi/strength/wext", test_strength_wext); - g_test_add_func("/wifi/strength/all", test_strength_all); - - g_test_add_func("/wifi/ssids_options_to_ptrarray", test_ssids_options_to_ptrarray); - - return g_test_run(); -} diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver deleted file mode 100644 index c368a590..00000000 --- a/src/devices/wwan/libnm-wwan.ver +++ /dev/null @@ -1,41 +0,0 @@ -{ -global: - nm_modem_act_stage1_prepare; - nm_modem_act_stage2_config; - nm_modem_check_connection_compatible; - nm_modem_claim; - nm_modem_complete_connection; - nm_modem_deactivate; - nm_modem_deactivate_async; - nm_modem_device_state_changed; - nm_modem_get_apn; - nm_modem_get_capabilities; - nm_modem_get_configured_mtu; - nm_modem_get_control_port; - nm_modem_get_device_id; - nm_modem_get_driver; - nm_modem_get_iid; - nm_modem_get_ip_ifindex; - nm_modem_get_operator_code; - nm_modem_get_path; - nm_modem_get_secrets; - nm_modem_get_state; - nm_modem_get_type; - nm_modem_get_uid; - nm_modem_ip4_pre_commit; - nm_modem_is_claimed; - nm_modem_manager_get; - nm_modem_manager_get_modems; - nm_modem_manager_get_type; - nm_modem_manager_name_owner_get; - nm_modem_manager_name_owner_ref; - nm_modem_manager_name_owner_unref; - nm_modem_owns_port; - nm_modem_set_mm_enabled; - nm_modem_stage3_ip4_config_start; - nm_modem_stage3_ip6_config_start; - nm_modem_state_to_string; - nm_modem_unclaim; -local: - *; -}; diff --git a/src/devices/wwan/meson.build b/src/devices/wwan/meson.build deleted file mode 100644 index 97252edc..00000000 --- a/src/devices/wwan/meson.build +++ /dev/null @@ -1,92 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -nm_service_providers_source = files('nm-service-providers.c') - -sources = nm_service_providers_source + files( - 'nm-modem-broadband.c', - 'nm-modem.c', - 'nm-modem-manager.c', -) - -deps = [ - daemon_nm_default_dep, - libsystemd_dep, - mm_glib_dep, -] - -if enable_ofono - sources += files('nm-modem-ofono.c') -endif - -linker_script = join_paths(meson.current_source_dir(), 'libnm-wwan.ver') - -libnm_wwan = shared_module( - 'nm-wwan', - sources: sources, - dependencies: deps, - c_args: daemon_c_flags, - link_args: '-Wl,--version-script,@0@'.format(linker_script), - link_depends: linker_script, - install: true, - install_dir: nm_plugindir, -) - -wwan_inc = include_directories('.') - -libnm_wwan_dep = declare_dependency( - include_directories: wwan_inc, - link_with: libnm_wwan, -) - -core_plugins += libnm_wwan - -test( - 'check-wwan', - check_exports, - args: [libnm_wwan.full_path(), linker_script], -) - -sources = files( - 'nm-device-modem.c', - 'nm-wwan-factory.c', -) - -libnm_device_plugin_wwan = shared_module( - 'nm-device-plugin-wwan', - sources: sources, - dependencies: deps, - c_args: daemon_c_flags, - link_with: libnm_wwan, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_plugindir, - install_rpath: nm_plugindir, -) - -core_plugins += libnm_device_plugin_wwan - -run_target( - 'check-local-devices-wwan', - command: [check_exports, libnm_device_plugin_wwan.full_path(), linker_script_devices], - depends: libnm_device_plugin_wwan, -) - -if enable_tests - test_unit = 'test-service-providers' - - exe = executable( - test_unit, - ['tests/' + test_unit + '.c'] + nm_service_providers_source, - include_directories: wwan_inc, - dependencies: libnetwork_manager_test_dep, - c_args: test_c_flags, - ) - - test( - 'wwan/' + test_unit, - test_script, - timeout: default_test_timeout, - args: test_args + [exe.full_path()], - ) -endif diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c deleted file mode 100644 index f77de85a..00000000 --- a/src/devices/wwan/nm-device-modem.c +++ /dev/null @@ -1,957 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2019 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-modem.h" - -#include "nm-modem.h" -#include "nm-ip4-config.h" -#include "devices/nm-device-private.h" -#include "nm-rfkill-manager.h" -#include "settings/nm-settings-connection.h" -#include "nm-modem-broadband.h" -#include "NetworkManagerUtils.h" -#include "nm-core-internal.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceModem); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceModem, - PROP_MODEM, - PROP_CAPABILITIES, - PROP_CURRENT_CAPABILITIES, - PROP_DEVICE_ID, - PROP_OPERATOR_CODE, - PROP_APN, ); - -typedef struct { - NMModem * modem; - NMDeviceModemCapabilities caps; - NMDeviceModemCapabilities current_caps; - char * device_id; - char * operator_code; - char * apn; - bool rf_enabled : 1; - NMDeviceStageState stage1_state : 3; -} NMDeviceModemPrivate; - -struct _NMDeviceModem { - NMDevice parent; - NMDeviceModemPrivate _priv; -}; - -struct _NMDeviceModemClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE) - -#define NM_DEVICE_MODEM_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceModem, NM_IS_DEVICE_MODEM, NMDevice) - -/*****************************************************************************/ - -static void -ppp_failed(NMModem *modem, guint i_reason, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDeviceStateReason reason = i_reason; - - switch (nm_device_get_state(device)) { - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_CONFIG: - case NM_DEVICE_STATE_NEED_AUTH: - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, reason); - break; - case NM_DEVICE_STATE_IP_CONFIG: - case NM_DEVICE_STATE_IP_CHECK: - case NM_DEVICE_STATE_SECONDARIES: - case NM_DEVICE_STATE_ACTIVATED: - if (nm_device_activate_ip4_state_in_conf(device)) - nm_device_activate_schedule_ip_config_timeout(device, AF_INET); - else if (nm_device_activate_ip6_state_in_conf(device)) - nm_device_activate_schedule_ip_config_timeout(device, AF_INET6); - else if (nm_device_activate_ip4_state_done(device)) { - nm_device_ip_method_failed(device, - AF_INET, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else if (nm_device_activate_ip6_state_done(device)) { - nm_device_ip_method_failed(device, - AF_INET6, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else { - _LOGW(LOGD_MB, - "PPP failure in unexpected state %u", - (guint) nm_device_get_state(device)); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } - break; - default: - break; - } -} - -static void -modem_prepare_result(NMModem *modem, gboolean success, guint i_reason, gpointer user_data) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMDeviceStateReason reason = i_reason; - - if (nm_device_get_state(device) != NM_DEVICE_STATE_PREPARE - || priv->stage1_state != NM_DEVICE_STAGE_STATE_PENDING) { - nm_assert_not_reached(); - success = FALSE; - } - - if (!success) { - /* There are several reasons to block autoconnection at device level: - * - * - Wrong SIM-PIN: The device won't autoconnect because it doesn't make sense - * to retry the connection with the same PIN. This error also makes autoconnection - * blocked at settings level, so not even a modem unplug and replug will allow - * autoconnection again. It is somewhat redundant to block autoconnection at - * both device and setting level really. - * - * - SIM wrong or not inserted: If the modem is reporting a SIM not inserted error, - * we can block autoconnection at device level, so that if the same device is - * unplugged and replugged with a SIM (or if a SIM hotplug event happens in MM, - * recreating the device completely), we can try the autoconnection again. - * - * - Modem initialization failed: For some reason unknown to NM, the modem wasn't - * initialized correctly, which leads to an unusable device. A device unplug and - * replug may solve the issue, so make it a device-level autoconnection blocking - * reason. - */ - switch (nm_device_state_reason_check(reason)) { - case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED: - case NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED: - case NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: - nm_device_autoconnect_blocked_set(device, NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN); - break; - case NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED: - case NM_DEVICE_STATE_REASON_GSM_SIM_WRONG: - nm_device_autoconnect_blocked_set(device, NM_DEVICE_AUTOCONNECT_BLOCKED_SIM_MISSING); - break; - case NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED: - nm_device_autoconnect_blocked_set(device, NM_DEVICE_AUTOCONNECT_BLOCKED_INIT_FAILED); - break; - default: - break; - } - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, reason); - return; - } - - priv->stage1_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -modem_auth_requested(NMModem *modem, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - /* Auth requests (PIN, PAP/CHAP passwords, etc) only get handled - * during activation. - */ - if (!nm_device_is_activating(device)) - return; - - nm_device_state_changed(device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); -} - -static void -modem_auth_result(NMModem *modem, GError *error, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - g_return_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_NEED_AUTH); - - if (error) { - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT; - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -modem_ip4_config_result(NMModem *modem, NMIP4Config *config, GError *error, gpointer user_data) -{ - NMDeviceModem *self = NM_DEVICE_MODEM(user_data); - NMDevice * device = NM_DEVICE(self); - - g_return_if_fail(nm_device_activate_ip4_state_in_conf(device) == TRUE); - - if (error) { - _LOGW(LOGD_MB | LOGD_IP4, "retrieving IPv4 configuration failed: %s", error->message); - nm_device_ip_method_failed(device, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else { - nm_device_set_dev2_ip_config(device, AF_INET, NM_IP_CONFIG_CAST(config)); - nm_device_activate_schedule_ip_config_result(device, AF_INET, NULL); - } -} - -static void -modem_ip6_config_result(NMModem * modem, - NMIP6Config *config, - gboolean do_slaac, - GError * error, - gpointer user_data) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDevice * device = NM_DEVICE(self); - NMActStageReturn ret; - NMDeviceStateReason failure_reason = NM_DEVICE_STATE_REASON_NONE; - gs_unref_object NMIP6Config *ignored = NULL; - gboolean got_config = !!config; - - g_return_if_fail(nm_device_activate_ip6_state_in_conf(device) == TRUE); - - if (error) { - _LOGW(LOGD_MB | LOGD_IP6, "retrieving IPv6 configuration failed: %s", error->message); - nm_device_ip_method_failed(device, AF_INET6, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - /* Re-enable IPv6 on the interface */ - nm_device_sysctl_ip_conf_set(device, AF_INET6, "disable_ipv6", "0"); - - if (config) - nm_device_set_dev2_ip_config(device, AF_INET6, NM_IP_CONFIG_CAST(config)); - - if (do_slaac == FALSE) { - if (got_config) - nm_device_activate_schedule_ip_config_result(device, AF_INET6, NULL); - else { - _LOGW(LOGD_MB | LOGD_IP6, - "retrieving IPv6 configuration failed: SLAAC not requested and no addresses"); - nm_device_ip_method_failed(device, - AF_INET6, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } - return; - } - - /* Start SLAAC now that we have a link-local address from the modem */ - ret = - NM_DEVICE_CLASS(nm_device_modem_parent_class) - ->act_stage3_ip_config_start(device, AF_INET6, (gpointer *) &ignored, &failure_reason); - - nm_assert(ignored == NULL); - - switch (ret) { - case NM_ACT_STAGE_RETURN_FAILURE: - nm_device_ip_method_failed(device, AF_INET6, failure_reason); - break; - case NM_ACT_STAGE_RETURN_IP_FAIL: - /* all done */ - nm_device_activate_schedule_ip_config_result(device, AF_INET6, NULL); - break; - case NM_ACT_STAGE_RETURN_POSTPONE: - /* let SLAAC run */ - break; - default: - /* Should never get here since we've assured that the IPv6 method - * will either be "auto" or "ignored" when starting IPv6 configuration. - */ - nm_assert_not_reached(); - } -} - -static void -ip_ifindex_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - if (!nm_device_is_activating(device)) - return; - - if (!nm_device_set_ip_ifindex(device, nm_modem_get_ip_ifindex(modem))) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - /* Disable IPv6 immediately on the interface since NM handles IPv6 - * internally, and leaving it enabled could allow the kernel's IPv6 - * RA handling code to run before NM is ready. - */ - nm_device_sysctl_ip_conf_set(device, AF_INET6, "disable_ipv6", "1"); -} - -static void -operator_code_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - const char * operator_code = nm_modem_get_operator_code(modem); - - if (g_strcmp0(priv->operator_code, operator_code) != 0) { - g_free(priv->operator_code); - priv->operator_code = g_strdup(operator_code); - _notify(self, PROP_OPERATOR_CODE); - } -} - -static void -apn_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - const char * apn = nm_modem_get_apn(modem); - - if (g_strcmp0(priv->apn, apn) != 0) { - g_free(priv->apn); - priv->apn = g_strdup(apn); - _notify(self, PROP_APN); - } -} - -static void -ids_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - nm_device_recheck_available_connections(NM_DEVICE(user_data)); -} - -static void -modem_state_cb(NMModem *modem, int new_state_i, int old_state_i, gpointer user_data) -{ - NMModemState new_state = new_state_i; - NMModemState old_state = old_state_i; - NMDevice * device = NM_DEVICE(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - NMDeviceState dev_state = nm_device_get_state(device); - - if (new_state <= NM_MODEM_STATE_DISABLING && old_state > NM_MODEM_STATE_DISABLING - && priv->rf_enabled) { - /* Called when the ModemManager modem enabled state is changed externally - * to NetworkManager (eg something using MM's D-Bus API directly). - */ - if (nm_device_is_activating(device) || dev_state == NM_DEVICE_STATE_ACTIVATED) { - /* user-initiated action, hence DISCONNECTED not FAILED */ - nm_device_state_changed(device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - return; - } - } - - if (new_state < NM_MODEM_STATE_CONNECTING && old_state >= NM_MODEM_STATE_CONNECTING - && dev_state >= NM_DEVICE_STATE_NEED_AUTH && dev_state <= NM_DEVICE_STATE_ACTIVATED) { - /* Fail the device if the modem disconnects unexpectedly while the - * device is activating/activated. */ - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; - } - - if (new_state > NM_MODEM_STATE_LOCKED && old_state == NM_MODEM_STATE_LOCKED) { - /* If the modem is now unlocked, enable/disable it according to the - * device's enabled/disabled state. - */ - nm_modem_set_mm_enabled(priv->modem, priv->rf_enabled); - - if (dev_state == NM_DEVICE_STATE_NEED_AUTH) { - /* The modem was unlocked externally to NetworkManager, - * deactivate so the default connection can be - * automatically activated again */ - nm_device_state_changed(device, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_MODEM_AVAILABLE); - } - - /* Now allow connections without a PIN to be available */ - nm_device_recheck_available_connections(device); - } - - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, - NM_DEVICE_STATE_REASON_MODEM_FAILED); -} - -static void -modem_removed_cb(NMModem *modem, gpointer user_data) -{ - g_signal_emit_by_name(NM_DEVICE(user_data), NM_DEVICE_REMOVED); -} - -/*****************************************************************************/ - -static gboolean -owns_iface(NMDevice *device, const char *iface) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - g_return_val_if_fail(priv->modem, FALSE); - - return nm_modem_owns_port(priv->modem, iface); -} - -/*****************************************************************************/ - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - - g_return_if_fail(priv->modem); - - if (new_state == NM_DEVICE_STATE_UNAVAILABLE && old_state < NM_DEVICE_STATE_UNAVAILABLE) { - /* Log initial modem state */ - _LOGI(LOGD_MB, - "modem state '%s'", - nm_modem_state_to_string(nm_modem_get_state(priv->modem))); - } - nm_modem_device_state_changed(priv->modem, new_state, old_state); -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_NON_KERNEL; -} - -static const char * -get_type_description(NMDevice *device) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - if (NM_FLAGS_HAS(priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)) - return "gsm"; - if (NM_FLAGS_HAS(priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)) - return "cdma"; - return NM_DEVICE_CLASS(nm_device_modem_parent_class)->get_type_description(device); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - GError *local = NULL; - - if (!NM_DEVICE_CLASS(nm_device_modem_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (!nm_modem_check_connection_compatible(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem, - connection, - error ? &local : NULL)) { - if (error) { - g_set_error(error, - NM_UTILS_ERROR, - g_error_matches(local, - NM_UTILS_ERROR, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE) - ? NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE - : NM_UTILS_ERROR_UNKNOWN, - "modem is incompatible with connection: %s", - local->message); - g_error_free(local); - } - return FALSE; - } - return TRUE; -} - -static gboolean -check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - NMModemState state; - - if (!priv->rf_enabled) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "RFKILL for modem enabled"); - return FALSE; - } - - if (!priv->modem) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem not available"); - return FALSE; - } - - state = nm_modem_get_state(priv->modem); - if (state <= NM_MODEM_STATE_INITIALIZING) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem not initialized"); - return FALSE; - } - - if (state == NM_MODEM_STATE_LOCKED) { - if (!nm_connection_get_setting_gsm(connection)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem is locked without pin available"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - return nm_modem_complete_connection(priv->modem, - nm_device_get_iface(device), - connection, - existing_connections, - error); -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - nm_modem_deactivate(priv->modem, device); - priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT; -} - -/*****************************************************************************/ - -static void -modem_deactivate_async_cb(NMModem *modem, GError *error, gpointer user_data) -{ - gs_unref_object NMDevice * self = NULL; - NMDeviceDeactivateCallback callback; - gpointer callback_user_data; - - nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data); - callback(self, error, callback_user_data); -} - -static void -deactivate_async(NMDevice * self, - GCancellable * cancellable, - NMDeviceDeactivateCallback callback, - gpointer user_data) -{ - nm_assert(G_IS_CANCELLABLE(cancellable)); - nm_assert(callback); - - nm_modem_deactivate_async(NM_DEVICE_MODEM_GET_PRIVATE(self)->modem, - self, - cancellable, - modem_deactivate_async_cb, - nm_utils_user_data_pack(g_object_ref(self), callback, user_data)); -} - -/*****************************************************************************/ - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - NMActRequest * req; - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - if (priv->stage1_state == NM_DEVICE_STAGE_STATE_INIT) { - priv->stage1_state = NM_DEVICE_STAGE_STATE_PENDING; - return nm_modem_act_stage1_prepare(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem, - req, - out_failure_reason); - } - - if (priv->stage1_state == NM_DEVICE_STAGE_STATE_PENDING) - return NM_ACT_STAGE_RETURN_POSTPONE; - - nm_assert(priv->stage1_state == NM_DEVICE_STAGE_STATE_COMPLETED); - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - nm_modem_act_stage2_config(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem); - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - nm_assert_addr_family(addr_family); - - if (addr_family == AF_INET) { - return nm_modem_stage3_ip4_config_start(priv->modem, - device, - NM_DEVICE_CLASS(nm_device_modem_parent_class), - out_failure_reason); - } else { - return nm_modem_stage3_ip6_config_start(priv->modem, device, out_failure_reason); - } -} - -static void -ip4_config_pre_commit(NMDevice *device, NMIP4Config *config) -{ - nm_modem_ip4_pre_commit(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem, device, config); -} - -static gboolean -get_ip_iface_identifier(NMDevice *device, NMUtilsIPv6IfaceId *out_iid) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - gboolean success; - - g_return_val_if_fail(priv->modem, FALSE); - success = nm_modem_get_iid(priv->modem, out_iid); - if (!success) - success = - NM_DEVICE_CLASS(nm_device_modem_parent_class)->get_ip_iface_identifier(device, out_iid); - return success; -} - -/*****************************************************************************/ - -static gboolean -get_enabled(NMDevice *device) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - NMModemState modem_state = nm_modem_get_state(priv->modem); - - return priv->rf_enabled && (modem_state >= NM_MODEM_STATE_LOCKED); -} - -static void -set_enabled(NMDevice *device, gboolean enabled) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - - /* Called only by the Manager in response to rfkill switch changes or - * global user WWAN enable/disable preference changes. - */ - priv->rf_enabled = enabled; - - if (priv->modem) { - /* Sync the ModemManager modem enabled/disabled with rfkill/user preference */ - nm_modem_set_mm_enabled(priv->modem, enabled); - } - - if (enabled == FALSE) { - nm_device_state_changed(device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NONE); - } -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - NMModemState modem_state; - - if (!priv->rf_enabled) - return FALSE; - - g_assert(priv->modem); - modem_state = nm_modem_get_state(priv->modem); - if (modem_state <= NM_MODEM_STATE_INITIALIZING) - return FALSE; - - return TRUE; -} - -/*****************************************************************************/ - -static void -set_modem(NMDeviceModem *self, NMModem *modem) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - - g_return_if_fail(modem != NULL); - - priv->modem = nm_modem_claim(modem); - - g_signal_connect(modem, NM_MODEM_PPP_FAILED, G_CALLBACK(ppp_failed), self); - g_signal_connect(modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK(modem_prepare_result), self); - g_signal_connect(modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK(modem_ip4_config_result), self); - g_signal_connect(modem, NM_MODEM_IP6_CONFIG_RESULT, G_CALLBACK(modem_ip6_config_result), self); - g_signal_connect(modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK(modem_auth_requested), self); - g_signal_connect(modem, NM_MODEM_AUTH_RESULT, G_CALLBACK(modem_auth_result), self); - g_signal_connect(modem, NM_MODEM_STATE_CHANGED, G_CALLBACK(modem_state_cb), self); - g_signal_connect(modem, NM_MODEM_REMOVED, G_CALLBACK(modem_removed_cb), self); - - g_signal_connect(modem, - "notify::" NM_MODEM_IP_IFINDEX, - G_CALLBACK(ip_ifindex_changed_cb), - self); - g_signal_connect(modem, "notify::" NM_MODEM_DEVICE_ID, G_CALLBACK(ids_changed_cb), self); - g_signal_connect(modem, "notify::" NM_MODEM_SIM_ID, G_CALLBACK(ids_changed_cb), self); - g_signal_connect(modem, "notify::" NM_MODEM_SIM_OPERATOR_ID, G_CALLBACK(ids_changed_cb), self); - g_signal_connect(modem, - "notify::" NM_MODEM_OPERATOR_CODE, - G_CALLBACK(operator_code_changed_cb), - self); - g_signal_connect(modem, "notify::" NM_MODEM_APN, G_CALLBACK(apn_changed_cb), self); -} - -static guint32 -get_dhcp_timeout_for_device(NMDevice *device, int addr_family) -{ - /* DHCP is always done by the modem firmware, not by the network, and - * by the time we get around to DHCP the firmware should already know - * the IP addressing details. So the DHCP timeout can be much shorter. - */ - return 15; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_MODEM: - g_value_set_object(value, priv->modem); - break; - case PROP_CAPABILITIES: - g_value_set_uint(value, priv->caps); - break; - case PROP_CURRENT_CAPABILITIES: - g_value_set_uint(value, priv->current_caps); - break; - case PROP_DEVICE_ID: - g_value_set_string(value, priv->device_id); - break; - case PROP_OPERATOR_CODE: - g_value_set_string(value, priv->operator_code); - break; - case PROP_APN: - g_value_set_string(value, priv->apn); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_MODEM: - /* construct-only */ - set_modem(NM_DEVICE_MODEM(object), g_value_get_object(value)); - break; - case PROP_CAPABILITIES: - priv->caps = g_value_get_uint(value); - break; - case PROP_CURRENT_CAPABILITIES: - priv->current_caps = g_value_get_uint(value); - break; - case PROP_DEVICE_ID: - /* construct-only */ - priv->device_id = g_value_dup_string(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_modem_init(NMDeviceModem *self) -{} - -NMDevice * -nm_device_modem_new(NMModem *modem) -{ - NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE; - NMDeviceModemCapabilities current_caps = NM_DEVICE_MODEM_CAPABILITY_NONE; - - g_return_val_if_fail(NM_IS_MODEM(modem), NULL); - - /* Load capabilities */ - nm_modem_get_capabilities(modem, &caps, ¤t_caps); - - return g_object_new(NM_TYPE_DEVICE_MODEM, - NM_DEVICE_UDI, - nm_modem_get_path(modem), - NM_DEVICE_IFACE, - nm_modem_get_uid(modem), - NM_DEVICE_DRIVER, - nm_modem_get_driver(modem), - NM_DEVICE_TYPE_DESC, - "Broadband", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_MODEM, - NM_DEVICE_RFKILL_TYPE, - RFKILL_TYPE_WWAN, - NM_DEVICE_MODEM_MODEM, - modem, - NM_DEVICE_MODEM_CAPABILITIES, - caps, - NM_DEVICE_MODEM_CURRENT_CAPABILITIES, - current_caps, - NM_DEVICE_MODEM_DEVICE_ID, - nm_modem_get_device_id(modem), - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(object); - - if (priv->modem) { - g_signal_handlers_disconnect_by_data(priv->modem, NM_DEVICE_MODEM(object)); - nm_clear_pointer(&priv->modem, nm_modem_unclaim); - } - - nm_clear_g_free(&priv->device_id); - nm_clear_g_free(&priv->operator_code); - nm_clear_g_free(&priv->apn); - - G_OBJECT_CLASS(nm_device_modem_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_modem = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_MODEM, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ModemCapabilities", - "u", - NM_DEVICE_MODEM_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("CurrentCapabilities", - "u", - NM_DEVICE_MODEM_CURRENT_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DeviceId", - "s", - NM_DEVICE_MODEM_DEVICE_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("OperatorCode", - "s", - NM_DEVICE_MODEM_OPERATOR_CODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Apn", "s", NM_DEVICE_MODEM_APN), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_modem_class_init(NMDeviceModemClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_modem); - - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->get_type_description = get_type_description; - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - device_class->deactivate_async = deactivate_async; - device_class->deactivate = deactivate; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->ip4_config_pre_commit = ip4_config_pre_commit; - device_class->get_enabled = get_enabled; - device_class->set_enabled = set_enabled; - device_class->owns_iface = owns_iface; - device_class->is_available = is_available; - device_class->get_ip_iface_identifier = get_ip_iface_identifier; - device_class->get_configured_mtu = nm_modem_get_configured_mtu; - device_class->get_dhcp_timeout_for_device = get_dhcp_timeout_for_device; - - device_class->state_changed = device_state_changed; - - obj_properties[PROP_MODEM] = - g_param_spec_object(NM_DEVICE_MODEM_MODEM, - "", - "", - NM_TYPE_MODEM, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_CAPABILITIES] = - g_param_spec_uint(NM_DEVICE_MODEM_CAPABILITIES, - "", - "", - 0, - G_MAXUINT32, - NM_DEVICE_MODEM_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_CURRENT_CAPABILITIES] = - g_param_spec_uint(NM_DEVICE_MODEM_CURRENT_CAPABILITIES, - "", - "", - 0, - G_MAXUINT32, - NM_DEVICE_MODEM_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_DEVICE_ID] = - g_param_spec_string(NM_DEVICE_MODEM_DEVICE_ID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_OPERATOR_CODE] = - g_param_spec_string(NM_DEVICE_MODEM_OPERATOR_CODE, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_APN] = g_param_spec_string(NM_DEVICE_MODEM_APN, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/wwan/nm-device-modem.h b/src/devices/wwan/nm-device-modem.h deleted file mode 100644 index caabeb6c..00000000 --- a/src/devices/wwan/nm-device-modem.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_MODEM_H__ -#define __NETWORKMANAGER_DEVICE_MODEM_H__ - -#include "devices/nm-device.h" -#include "nm-modem.h" - -#define NM_TYPE_DEVICE_MODEM (nm_device_modem_get_type()) -#define NM_DEVICE_MODEM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) -#define NM_DEVICE_MODEM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) -#define NM_IS_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MODEM)) -#define NM_IS_DEVICE_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_MODEM)) -#define NM_DEVICE_MODEM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) - -#define NM_DEVICE_MODEM_MODEM "modem" -#define NM_DEVICE_MODEM_CAPABILITIES "modem-capabilities" -#define NM_DEVICE_MODEM_CURRENT_CAPABILITIES "current-capabilities" -#define NM_DEVICE_MODEM_DEVICE_ID "device-id" -#define NM_DEVICE_MODEM_OPERATOR_CODE "operator-code" -#define NM_DEVICE_MODEM_APN "apn" - -typedef struct _NMDeviceModem NMDeviceModem; -typedef struct _NMDeviceModemClass NMDeviceModemClass; - -GType nm_device_modem_get_type(void); - -NMDevice *nm_device_modem_new(NMModem *modem); - -#endif /* __NETWORKMANAGER_DEVICE_MODEM_H__ */ diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c deleted file mode 100644 index 7b3a13a3..00000000 --- a/src/devices/wwan/nm-modem-broadband.c +++ /dev/null @@ -1,1625 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org> - */ - -#include "nm-default.h" - -#include "nm-modem-broadband.h" -#include "nm-service-providers.h" - -#include <arpa/inet.h> -#include <libmm-glib.h> - -#include "nm-core-internal.h" -#include "NetworkManagerUtils.h" -#include "devices/nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" - -#define NM_MODEM_BROADBAND_MODEM "modem" - -static gboolean -MODEM_CAPS_3GPP(MMModemCapability caps) -{ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - /* MM_MODEM_CAPABILITY_LTE_ADVANCED is marked as deprecated since ModemManager 1.14.0. - * - * The flag probably was never used, it certainly isn't used since 1.14.0. - * - * Still, just to be sure, there is no harm in checking it here. Suppress the - * warning, it should have no bad effect. - */ - return NM_FLAGS_ANY(caps, - (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_LTE - | MM_MODEM_CAPABILITY_LTE_ADVANCED)); - G_GNUC_END_IGNORE_DEPRECATIONS -} - -#define MODEM_CAPS_3GPP2(caps) (caps & (MM_MODEM_CAPABILITY_CDMA_EVDO)) - -/* Maximum time to keep the DBus call waiting for a connection result. - * This value is greater than the default timeout in ModemManager (180s since - * 1.16), so that whenever possible the timeout happens first there instead of - * in NetworkManager. */ -#define MODEM_CONNECT_TIMEOUT_SECS 200 - -/*****************************************************************************/ - -typedef enum { - CONNECT_STEP_FIRST, - CONNECT_STEP_WAIT_FOR_SIM, - CONNECT_STEP_UNLOCK, - CONNECT_STEP_WAIT_FOR_READY, - CONNECT_STEP_CONNECT, - CONNECT_STEP_LAST, -} ConnectStep; - -typedef struct { - NMModemBroadband *self; - ConnectStep step; - - MMModemCapability caps; - NMConnection * connection; - GCancellable * cancellable; - MMSimpleConnectProperties *connect_properties; - GArray * ip_types; - guint ip_types_i; - guint ip_type_tries; - GError * first_error; -} ConnectContext; - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_MODEM, ); - -typedef struct { - /* The modem object from dbus */ - MMObject *modem_object; - /* Per-interface objects */ - MMModem * modem_iface; - MMModem3gpp * modem_3gpp_iface; - MMModemSimple *simple_iface; - MMSim * sim_iface; - - /* Connection setup */ - ConnectContext *ctx; - - MMBearer * bearer; - MMBearerIpConfig *ipv4_config; - MMBearerIpConfig *ipv6_config; - - guint idle_id_ip4; - guint idle_id_ip6; - - guint32 pin_tries; -} NMModemBroadbandPrivate; - -struct _NMModemBroadband { - NMModem parent; - NMModemBroadbandPrivate _priv; -}; - -struct _NMModemBroadbandClass { - NMModemClass parent; -}; - -G_DEFINE_TYPE(NMModemBroadband, nm_modem_broadband, NM_TYPE_MODEM) - -#define NM_MODEM_BROADBAND_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMModemBroadband, NM_IS_MODEM_BROADBAND) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_MB -#define _NMLOG_PREFIX_NAME "modem-broadband" -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - \ - if (nm_logging_enabled(_level, (_NMLOG_DOMAIN))) { \ - NMModemBroadband *const __self = (self); \ - char __prefix_name[128]; \ - const char * __uid; \ - \ - _nm_log(_level, \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - ((__self && __self->_priv.ctx) \ - ? nm_connection_get_uuid(__self->_priv.ctx->connection) \ - : NULL), \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - (__self ? ({ \ - ((__uid = nm_modem_get_uid((NMModem *) __self)) \ - ? nm_sprintf_buf(__prefix_name, "[%s]", __uid) \ - : "(null)"); \ - }) \ - : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static NMDeviceStateReason -translate_mm_error(NMModemBroadband *self, GError *error) -{ - NMDeviceStateReason reason; - - g_return_val_if_fail(error != NULL, NM_DEVICE_STATE_REASON_UNKNOWN); - - if (g_error_matches(error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_CARRIER)) - reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER; - else if (g_error_matches(error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_DIALTONE)) - reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE; - else if (g_error_matches(error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_BUSY)) - reason = NM_DEVICE_STATE_REASON_MODEM_BUSY; - else if (g_error_matches(error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_ANSWER)) - reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED; - else if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED; - else if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED; - else if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD)) - reason = NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT; - else { - /* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */ - _LOGD("unmapped error detected: '%s'", error->message); - reason = NM_DEVICE_STATE_REASON_UNKNOWN; - } - - return reason; -} - -/*****************************************************************************/ - -static void -get_capabilities(NMModem * _self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(_self); - MMModemCapability all_supported = MM_MODEM_CAPABILITY_NONE; - MMModemCapability *supported; - guint n_supported; - - /* For now, we don't care about the capability combinations, just merge all - * combinations in a single mask */ - if (mm_modem_get_supported_capabilities(self->_priv.modem_iface, &supported, &n_supported)) { - guint i; - - for (i = 0; i < n_supported; i++) - all_supported |= supported[i]; - - g_free(supported); - } - - *modem_caps = (NMDeviceModemCapabilities) all_supported; - *current_caps = - (NMDeviceModemCapabilities) mm_modem_get_current_capabilities(self->_priv.modem_iface); -} - -static gboolean -owns_port(NMModem *_self, const char *iface) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(_self); - const MMModemPortInfo *ports = NULL; - guint n_ports = 0, i; - - mm_modem_peek_ports(self->_priv.modem_iface, &ports, &n_ports); - for (i = 0; i < n_ports; i++) { - if (nm_streq0(iface, ports[i].name)) - return TRUE; - } - return FALSE; -} - -/*****************************************************************************/ - -static void -ask_for_pin(NMModemBroadband *self) -{ - guint32 tries; - - tries = self->_priv.pin_tries++; - nm_modem_get_secrets(NM_MODEM(self), - NM_SETTING_GSM_SETTING_NAME, - tries ? TRUE : FALSE, - NM_SETTING_GSM_PIN); -} - -static NMModemIPMethod -get_bearer_ip_method(MMBearerIpConfig *config) -{ - MMBearerIpMethod mm_method; - - mm_method = mm_bearer_ip_config_get_method(config); - if (mm_method == MM_BEARER_IP_METHOD_PPP) - return NM_MODEM_IP_METHOD_PPP; - else if (mm_method == MM_BEARER_IP_METHOD_STATIC) - return NM_MODEM_IP_METHOD_STATIC; - else if (mm_method == MM_BEARER_IP_METHOD_DHCP) - return NM_MODEM_IP_METHOD_AUTO; - return NM_MODEM_IP_METHOD_UNKNOWN; -} - -static MMSimpleConnectProperties * -create_cdma_connect_properties(NMConnection *connection) -{ - MMSimpleConnectProperties *properties; - - properties = mm_simple_connect_properties_new(); - -#if !MM_CHECK_VERSION(1, 9, 1) - { - NMSettingCdma *setting; - const char * str; - - setting = nm_connection_get_setting_cdma(connection); - str = nm_setting_cdma_get_number(setting); - if (str) - mm_simple_connect_properties_set_number(properties, str); - } -#endif - - return properties; -} - -static MMSimpleConnectProperties * -create_gsm_connect_properties(NMConnection *connection, - const char * apn, - const char * username, - const char * password) -{ - NMSettingGsm * setting; - NMSettingPpp * s_ppp; - MMSimpleConnectProperties *properties; - const char * str; - - setting = nm_connection_get_setting_gsm(connection); - - properties = mm_simple_connect_properties_new(); - - mm_simple_connect_properties_set_apn(properties, apn ?: ""); - if (username) - mm_simple_connect_properties_set_user(properties, username); - if (password) - mm_simple_connect_properties_set_password(properties, password); - - str = nm_setting_gsm_get_network_id(setting); - if (str) - mm_simple_connect_properties_set_operator_id(properties, str); - - str = nm_setting_gsm_get_pin(setting); - if (str) - mm_simple_connect_properties_set_pin(properties, str); - - /* Roaming */ - if (nm_setting_gsm_get_home_only(setting)) - mm_simple_connect_properties_set_allow_roaming(properties, FALSE); - - /* For IpMethod == STATIC or DHCP */ - s_ppp = nm_connection_get_setting_ppp(connection); - if (s_ppp) { - MMBearerAllowedAuth allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; - - if (nm_setting_ppp_get_noauth(s_ppp)) - allowed_auth = MM_BEARER_ALLOWED_AUTH_NONE; - if (!nm_setting_ppp_get_refuse_pap(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_PAP; - if (!nm_setting_ppp_get_refuse_chap(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_CHAP; - if (!nm_setting_ppp_get_refuse_mschap(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAP; - if (!nm_setting_ppp_get_refuse_mschapv2(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAPV2; - if (!nm_setting_ppp_get_refuse_eap(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_EAP; - - mm_simple_connect_properties_set_allowed_auth(properties, allowed_auth); - } - - return properties; -} - -static void -connect_context_clear(NMModemBroadband *self) -{ - if (self->_priv.ctx) { - ConnectContext *ctx = self->_priv.ctx; - - g_clear_error(&ctx->first_error); - nm_clear_pointer(&ctx->ip_types, g_array_unref); - nm_clear_g_cancellable(&ctx->cancellable); - g_clear_object(&ctx->connection); - g_clear_object(&ctx->connect_properties); - g_clear_object(&ctx->self); - g_slice_free(ConnectContext, ctx); - self->_priv.ctx = NULL; - } -} - -static void connect_context_step(NMModemBroadband *self); - -static void -connect_ready(MMModemSimple *simple_iface, GAsyncResult *res, NMModemBroadband *self) -{ - ConnectContext *ctx; - GError * error = NULL; - NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; - NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - MMBearer * bearer; - - bearer = mm_modem_simple_connect_finish(simple_iface, res, &error); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free(error); - return; - } - - ctx = self->_priv.ctx; - - if (!ctx) - return; - - self->_priv.bearer = bearer; - - if (!self->_priv.bearer) { - if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) - || (g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) - && mm_modem_get_unlock_required(self->_priv.modem_iface) - == MM_MODEM_LOCK_SIM_PIN)) { - g_error_free(error); - - /* Request PIN */ - ask_for_pin(self); - connect_context_clear(self); - return; - } - - /* Save the error, if it's the first one */ - if (!ctx->first_error) { - /* Strip remote error info before saving it */ - if (g_dbus_error_is_remote_error(error)) - g_dbus_error_strip_remote_error(error); - ctx->first_error = error; - } else - g_clear_error(&error); - - if (ctx->ip_type_tries == 0 && g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) { - /* Try one more time */ - ctx->ip_type_tries++; - } else { - /* If the modem/provider lies and the IP type we tried isn't supported, - * retry with the next one, if any. - */ - ctx->ip_types_i++; - ctx->ip_type_tries = 0; - } - connect_context_step(self); - return; - } - - /* Grab IP configurations */ - self->_priv.ipv4_config = mm_bearer_get_ipv4_config(self->_priv.bearer); - if (self->_priv.ipv4_config) - ip4_method = get_bearer_ip_method(self->_priv.ipv4_config); - - self->_priv.ipv6_config = mm_bearer_get_ipv6_config(self->_priv.bearer); - if (self->_priv.ipv6_config) - ip6_method = get_bearer_ip_method(self->_priv.ipv6_config); - - if (!nm_modem_set_data_port(NM_MODEM(self), - NM_PLATFORM_GET, - mm_bearer_get_interface(self->_priv.bearer), - ip4_method, - ip6_method, - mm_bearer_get_ip_timeout(self->_priv.bearer), - &error)) { - _LOGW("failed to connect modem: %s", error->message); - g_error_free(error); - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - connect_context_clear(self); - return; - } - - ctx->step++; - connect_context_step(self); -} - -static void -send_pin_ready(MMSim *sim, GAsyncResult *result, NMModemBroadband *self) -{ - gs_free_error GError *error = NULL; - - mm_sim_send_pin_finish(sim, result, &error); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - if (!self->_priv.ctx || self->_priv.ctx->step != CONNECT_STEP_UNLOCK) - g_return_if_reached(); - - if (error) { - if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) - || (g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) - && mm_modem_get_unlock_required(self->_priv.modem_iface) == MM_MODEM_LOCK_SIM_PIN)) - ask_for_pin(self); - else - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, translate_mm_error(self, error)); - return; - } - - self->_priv.ctx->step++; - connect_context_step(self); -} - -static void -find_gsm_apn_cb(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data) -{ - NMModemBroadband * self = user_data; - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - ConnectContext * ctx = priv->ctx; - - if (error) { - _LOGW("failed to connect '%s': APN not found: %s", - nm_connection_get_id(ctx->connection), - error->message); - - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); - connect_context_clear(self); - return; - } - - /* Blank APN ("") means the default subscription APN */ - ctx->connect_properties = - create_gsm_connect_properties(ctx->connection, apn, username, password); - g_return_if_fail(ctx->connect_properties); - connect_context_step(self); -} - -static gboolean -try_create_connect_properties(NMModemBroadband *self) -{ - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - ConnectContext * ctx = priv->ctx; - - if (MODEM_CAPS_3GPP(ctx->caps)) { - NMSettingGsm *s_gsm = nm_connection_get_setting_gsm(ctx->connection); - - if (!s_gsm || nm_setting_gsm_get_auto_config(s_gsm)) { - gs_unref_object MMModem3gpp *modem_3gpp = NULL; - const char * network_id = NULL; - - s_gsm = nm_connection_get_setting_gsm(ctx->connection); - if (s_gsm) - network_id = nm_setting_gsm_get_network_id(s_gsm); - if (!network_id) { - if (mm_modem_get_state(self->_priv.modem_iface) < MM_MODEM_STATE_REGISTERED) - return FALSE; - modem_3gpp = mm_object_get_modem_3gpp(priv->modem_object); - network_id = mm_modem_3gpp_get_operator_code(modem_3gpp); - } - if (!network_id) { - _LOGW("failed to connect '%s': unable to determine the network id", - nm_connection_get_id(ctx->connection)); - goto out; - } - - nm_service_providers_find_gsm_apn(MOBILE_BROADBAND_PROVIDER_INFO_DATABASE, - network_id, - ctx->cancellable, - find_gsm_apn_cb, - self); - } else { - ctx->connect_properties = - create_gsm_connect_properties(ctx->connection, - nm_setting_gsm_get_apn(s_gsm), - nm_setting_gsm_get_username(s_gsm), - nm_setting_gsm_get_password(s_gsm)); - g_return_val_if_fail(ctx->connect_properties, TRUE); - } - - return TRUE; - } else if (MODEM_CAPS_3GPP2(ctx->caps)) { - ctx->connect_properties = create_cdma_connect_properties(ctx->connection); - g_return_val_if_fail(ctx->connect_properties, FALSE); - return TRUE; - } else { - _LOGW("failed to connect '%s': not a mobile broadband modem", - nm_connection_get_id(ctx->connection)); - } - -out: - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); - connect_context_clear(self); - return TRUE; -} - -static void -connect_context_step(NMModemBroadband *self) -{ - ConnectContext *ctx = self->_priv.ctx; - - switch (ctx->step) { - case CONNECT_STEP_FIRST: - ctx->step++; - /* fall-through */ - - case CONNECT_STEP_WAIT_FOR_SIM: - if (MODEM_CAPS_3GPP(ctx->caps) && !self->_priv.sim_iface) { - /* Have to wait for the SIM to show up */ - break; - } - ctx->step++; - /* fall-through */ - - case CONNECT_STEP_UNLOCK: - if (MODEM_CAPS_3GPP(ctx->caps) - && mm_modem_get_unlock_required(self->_priv.modem_iface) == MM_MODEM_LOCK_SIM_PIN) { - NMSettingGsm *s_gsm = nm_connection_get_setting_gsm(ctx->connection); - const char * pin = nm_setting_gsm_get_pin(s_gsm); - - /* If we have a PIN already, send it. If we don't, get it. */ - if (pin) { - mm_sim_send_pin(self->_priv.sim_iface, - pin, - ctx->cancellable, - (GAsyncReadyCallback) send_pin_ready, - self); - } else { - ask_for_pin(self); - } - break; - } - ctx->step++; - /* fall-through */ - case CONNECT_STEP_WAIT_FOR_READY: - { - GError *error = NULL; - - if (mm_modem_get_state(self->_priv.modem_iface) <= MM_MODEM_STATE_LOCKED) - break; - - if (!try_create_connect_properties(self)) - break; - - if (!self->_priv.ctx) - break; - - /* Build up list of IP types that we need to use in the retries */ - ctx->ip_types = nm_modem_get_connection_ip_type(NM_MODEM(self), ctx->connection, &error); - if (!ctx->ip_types) { - _LOGW("failed to connect '%s': %s", - nm_connection_get_id(ctx->connection), - error->message); - g_clear_error(&error); - - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); - connect_context_clear(self); - break; - } - - ctx->step++; - } - /* fall-through */ - case CONNECT_STEP_CONNECT: - if (!ctx->connect_properties) - break; - - if (ctx->ip_types_i < ctx->ip_types->len) { - NMModemIPType current; - - current = g_array_index(ctx->ip_types, NMModemIPType, ctx->ip_types_i); - - if (current == NM_MODEM_IP_TYPE_IPV4) - mm_simple_connect_properties_set_ip_type(ctx->connect_properties, - MM_BEARER_IP_FAMILY_IPV4); - else if (current == NM_MODEM_IP_TYPE_IPV6) - mm_simple_connect_properties_set_ip_type(ctx->connect_properties, - MM_BEARER_IP_FAMILY_IPV6); - else if (current == NM_MODEM_IP_TYPE_IPV4V6) - mm_simple_connect_properties_set_ip_type(ctx->connect_properties, - MM_BEARER_IP_FAMILY_IPV4V6); - else - g_return_if_reached(); - - _nm_modem_set_apn(NM_MODEM(self), - mm_simple_connect_properties_get_apn(ctx->connect_properties)); - - _LOGD("launching connection with ip type '%s' (try %d)", - nm_modem_ip_type_to_string(current), - ctx->ip_type_tries + 1); - - mm_modem_simple_connect(self->_priv.simple_iface, - ctx->connect_properties, - ctx->cancellable, - (GAsyncReadyCallback) connect_ready, - self); - break; - } - - ctx->step++; - /* fall-through */ - - case CONNECT_STEP_LAST: - if (self->_priv.ipv4_config || self->_priv.ipv6_config) - nm_modem_emit_prepare_result(NM_MODEM(self), TRUE, NM_DEVICE_STATE_REASON_NONE); - else { - /* If we have a saved error from a previous attempt, use it */ - if (!ctx->first_error) - ctx->first_error = g_error_new_literal(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "invalid bearer IP configuration"); - - _LOGW("failed to connect modem: %s", ctx->first_error->message); - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - translate_mm_error(self, ctx->first_error)); - } - - connect_context_clear(self); - break; - } -} - -static NMActStageReturn -modem_act_stage1_prepare(NMModem * _self, - NMConnection * connection, - NMDeviceStateReason *out_failure_reason) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(_self); - - /* Make sure we can get the Simple interface from the modem */ - if (!self->_priv.simple_iface) { - self->_priv.simple_iface = mm_object_get_modem_simple(self->_priv.modem_object); - if (!self->_priv.simple_iface) { - _LOGW("cannot access the Simple mobile broadband modem interface"); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - } - - connect_context_clear(self); - - /* Allocate new context for this connect stage attempt */ - self->_priv.ctx = g_slice_new0(ConnectContext); - self->_priv.ctx->caps = mm_modem_get_current_capabilities(self->_priv.modem_iface); - self->_priv.ctx->cancellable = g_cancellable_new(); - self->_priv.ctx->connection = g_object_ref(connection); - - g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(self->_priv.simple_iface), - MODEM_CONNECT_TIMEOUT_SECS * 1000); - connect_context_step(self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static gboolean -check_connection_compatible_with_modem(NMModem *_self, NMConnection *connection, GError **error) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(_self); - MMModemCapability modem_caps; - - modem_caps = mm_modem_get_current_capabilities(self->_priv.modem_iface); - - if (MODEM_CAPS_3GPP(modem_caps)) { - if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, error)) - return FALSE; - - return TRUE; - } - - if (MODEM_CAPS_3GPP2(modem_caps)) { - if (!_nm_connection_check_main_setting(connection, NM_SETTING_CDMA_SETTING_NAME, error)) - return FALSE; - - return TRUE; - } - - if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, NULL) - && !_nm_connection_check_main_setting(connection, NM_SETTING_CDMA_SETTING_NAME, NULL)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "connection type %s is not supported by modem", - nm_connection_get_connection_type(connection)); - return FALSE; - } - - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem lacks capabilities for %s profile", - nm_connection_get_connection_type(connection)); - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -complete_connection(NMModem * modem, - const char * iface, - NMConnection * connection, - NMConnection *const *existing_connections, - GError ** error) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(modem); - MMModemCapability modem_caps; - NMSettingPpp * s_ppp; - - modem_caps = mm_modem_get_current_capabilities(self->_priv.modem_iface); - - /* PPP settings common to 3GPP and 3GPP2 */ - s_ppp = nm_connection_get_setting_ppp(connection); - if (!s_ppp) { - s_ppp = (NMSettingPpp *) nm_setting_ppp_new(); - g_object_set(G_OBJECT(s_ppp), - NM_SETTING_PPP_LCP_ECHO_FAILURE, - 5, - NM_SETTING_PPP_LCP_ECHO_INTERVAL, - 30, - NULL); - nm_connection_add_setting(connection, NM_SETTING(s_ppp)); - } - - if (MODEM_CAPS_3GPP(modem_caps)) { - NMSettingGsm *s_gsm; - - s_gsm = nm_connection_get_setting_gsm(connection); - if (!s_gsm) { - s_gsm = (NMSettingGsm *) nm_setting_gsm_new(); - nm_connection_add_setting(connection, NM_SETTING(s_gsm)); - g_object_set(G_OBJECT(s_gsm), NM_SETTING_GSM_AUTO_CONFIG, TRUE, NULL); - } - - if (!nm_setting_gsm_get_device_id(s_gsm)) { - g_object_set(G_OBJECT(s_gsm), - NM_SETTING_GSM_DEVICE_ID, - nm_modem_get_device_id(modem), - NULL); - } - - nm_utils_complete_generic(NM_PLATFORM_GET, - connection, - NM_SETTING_GSM_SETTING_NAME, - existing_connections, - NULL, - _("GSM connection"), - NULL, - NULL, - FALSE); /* No IPv6 yet by default */ - - return TRUE; - } - - if (MODEM_CAPS_3GPP2(modem_caps)) { - NMSettingCdma *s_cdma; - - s_cdma = nm_connection_get_setting_cdma(connection); - if (!s_cdma) { - s_cdma = (NMSettingCdma *) nm_setting_cdma_new(); - nm_connection_add_setting(connection, NM_SETTING(s_cdma)); - } - - if (!nm_setting_cdma_get_number(s_cdma)) - g_object_set(G_OBJECT(s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL); - - nm_utils_complete_generic(NM_PLATFORM_GET, - connection, - NM_SETTING_CDMA_SETTING_NAME, - existing_connections, - NULL, - _("CDMA connection"), - NULL, - iface, - FALSE); /* No IPv6 yet by default */ - - return TRUE; - } - - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Device is not a mobile broadband modem"); - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -get_user_pass(NMModem *modem, NMConnection *connection, const char **user, const char **pass) -{ - NMSettingGsm * s_gsm; - NMSettingCdma *s_cdma; - - s_gsm = nm_connection_get_setting_gsm(connection); - s_cdma = nm_connection_get_setting_cdma(connection); - if (!s_gsm && !s_cdma) - return FALSE; - - if (user) { - if (s_gsm) - *user = nm_setting_gsm_get_username(s_gsm); - else if (s_cdma) - *user = nm_setting_cdma_get_username(s_cdma); - } - if (pass) { - if (s_gsm) - *pass = nm_setting_gsm_get_password(s_gsm); - else if (s_cdma) - *pass = nm_setting_cdma_get_password(s_cdma); - } - - return TRUE; -} - -/*****************************************************************************/ -/* Query/Update enabled state */ - -static void -set_power_state_low_ready(MMModem *modem, GAsyncResult *result, NMModemBroadband *self) -{ - GError *error = NULL; - - if (!mm_modem_set_power_state_finish(modem, result, &error)) { - /* Log but ignore errors; not all modems support low power state */ - _LOGD("failed to set modem low power state: %s", NM_G_ERROR_MSG(error)); - g_clear_error(&error); - } - - /* Balance refcount */ - g_object_unref(self); -} - -static void -modem_disable_ready(MMModem *modem_iface, GAsyncResult *res, NMModemBroadband *self) -{ - GError *error = NULL; - - if (mm_modem_disable_finish(modem_iface, res, &error)) { - /* Once disabled, move to low-power mode */ - mm_modem_set_power_state(modem_iface, - MM_MODEM_POWER_STATE_LOW, - NULL, - (GAsyncReadyCallback) set_power_state_low_ready, - g_object_ref(self)); - } else { - _LOGW("failed to disable modem: %s", NM_G_ERROR_MSG(error)); - nm_modem_set_prev_state(NM_MODEM(self), "disable failed"); - g_clear_error(&error); - } - - /* Balance refcount */ - g_object_unref(self); -} - -static void -modem_enable_ready(MMModem *modem_iface, GAsyncResult *res, NMModemBroadband *self) -{ - GError *error = NULL; - - if (!mm_modem_enable_finish(modem_iface, res, &error)) { - _LOGW("failed to enable modem: %s", NM_G_ERROR_MSG(error)); - nm_modem_set_prev_state(NM_MODEM(self), "enable failed"); - g_clear_error(&error); - } - - /* Balance refcount */ - g_object_unref(self); -} - -static void -set_mm_enabled(NMModem *_self, gboolean enabled) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(_self); - - if (enabled) { - mm_modem_enable(self->_priv.modem_iface, - NULL, /* cancellable */ - (GAsyncReadyCallback) modem_enable_ready, - g_object_ref(self)); - } else { - mm_modem_disable(self->_priv.modem_iface, - NULL, /* cancellable */ - (GAsyncReadyCallback) modem_disable_ready, - g_object_ref(self)); - } -} - -/*****************************************************************************/ -/* IPv4 method static */ - -static gboolean -static_stage3_ip4_done(NMModemBroadband *self) -{ - GError * error = NULL; - gs_unref_object NMIP4Config *config = NULL; - const char * data_port; - const char * address_string; - const char * gw_string; - guint32 address_network; - guint32 gw = 0; - NMPlatformIP4Address address; - const char ** dns; - guint i; - guint32 ip4_route_table, ip4_route_metric; - NMPlatformIP4Route * r; - guint32 mtu_n; - - g_return_val_if_fail(self->_priv.ipv4_config, FALSE); - g_return_val_if_fail(self->_priv.bearer, FALSE); - - self->_priv.idle_id_ip4 = 0; - - _LOGI("IPv4 static configuration:"); - - /* Fully fail if invalid IP address retrieved */ - address_string = mm_bearer_ip_config_get_address(self->_priv.ipv4_config); - if (!address_string - || !nm_utils_parse_inaddr_bin(AF_INET, address_string, NULL, &address_network)) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IP4 configuration failed: invalid address given %s%s%s", - nm_modem_get_uid(NM_MODEM(self)), - NM_PRINT_FMT_QUOTE_STRING(address_string)); - goto out; - } - - /* Missing gateway not a hard failure */ - gw_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv4_config); - if (gw_string && !nm_utils_parse_inaddr_bin(AF_INET, gw_string, NULL, &gw)) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IP4 configuration failed: invalid gateway address \"%s\"", - nm_modem_get_uid(NM_MODEM(self)), - gw_string); - goto out; - } - - data_port = mm_bearer_get_interface(self->_priv.bearer); - g_return_val_if_fail(data_port, FALSE); - config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), - nm_platform_link_get_ifindex(NM_PLATFORM_GET, data_port)); - - memset(&address, 0, sizeof(address)); - address.address = address_network; - address.peer_address = address_network; - address.plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv4_config); - address.addr_source = NM_IP_CONFIG_SOURCE_WWAN; - if (address.plen <= 32) - nm_ip4_config_add_address(config, &address); - - _LOGI(" address %s/%d", address_string, address.plen); - - nm_modem_get_route_parameters(NM_MODEM(self), &ip4_route_table, &ip4_route_metric, NULL, NULL); - r = &(NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_WWAN, - .gateway = gw, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, - }; - nm_ip4_config_add_route(config, r, NULL); - _LOGI(" gateway %s", gw_string); - - /* DNS servers */ - dns = mm_bearer_ip_config_get_dns(self->_priv.ipv4_config); - for (i = 0; dns && dns[i]; i++) { - if (nm_utils_parse_inaddr_bin(AF_INET, dns[i], NULL, &address_network) - && address_network > 0) { - nm_ip4_config_add_nameserver(config, address_network); - _LOGI(" DNS %s", dns[i]); - } - } - -#if MM_CHECK_VERSION(1, 4, 0) - mtu_n = mm_bearer_ip_config_get_mtu(self->_priv.ipv4_config); - if (mtu_n) { - nm_ip4_config_set_mtu(config, mtu_n, NM_IP_CONFIG_SOURCE_WWAN); - _LOGI(" MTU %u", mtu_n); - } -#endif - -out: - g_signal_emit_by_name(self, NM_MODEM_IP4_CONFIG_RESULT, config, error); - g_clear_error(&error); - return FALSE; -} - -static NMActStageReturn -static_stage3_ip4_config_start(NMModem * modem, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(modem); - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - - /* We schedule it in an idle just to follow the same logic as in the - * generic modem implementation. */ - nm_clear_g_source(&priv->idle_id_ip4); - priv->idle_id_ip4 = g_idle_add((GSourceFunc) static_stage3_ip4_done, self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ -/* IPv6 method static */ - -static gboolean -stage3_ip6_done(NMModemBroadband *self) -{ - GError * error = NULL; - NMIP6Config * config = NULL; - const char * data_port; - const char * address_string; - NMPlatformIP6Address address; - NMModemIPMethod ip_method; - const char ** dns; - guint i; - - g_return_val_if_fail(self->_priv.ipv6_config, FALSE); - - self->_priv.idle_id_ip6 = 0; - memset(&address, 0, sizeof(address)); - - ip_method = get_bearer_ip_method(self->_priv.ipv6_config); - - address_string = mm_bearer_ip_config_get_address(self->_priv.ipv6_config); - if (!address_string) { - /* DHCP/SLAAC is allowed to skip addresses; other methods require it */ - if (ip_method != NM_MODEM_IP_METHOD_AUTO) { - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: no address given", - nm_modem_get_uid(NM_MODEM(self))); - } - goto out; - } - - /* Fail if invalid IP address retrieved */ - if (!inet_pton(AF_INET6, address_string, (void *) &(address.address))) { - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: invalid address given '%s'", - nm_modem_get_uid(NM_MODEM(self)), - address_string); - goto out; - } - - _LOGI("IPv6 base configuration:"); - - data_port = mm_bearer_get_interface(self->_priv.bearer); - g_return_val_if_fail(data_port, FALSE); - - config = nm_ip6_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), - nm_platform_link_get_ifindex(NM_PLATFORM_GET, data_port)); - - address.plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv6_config); - if (address.plen <= 128) - nm_ip6_config_add_address(config, &address); - - _LOGI(" address %s/%d", address_string, address.plen); - - address_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv6_config); - if (address_string) { - guint32 ip6_route_table, ip6_route_metric; - - if (inet_pton(AF_INET6, address_string, &address.address) != 1) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", - nm_modem_get_uid(NM_MODEM(self)), - address_string); - goto out; - } - - nm_modem_get_route_parameters(NM_MODEM(self), - NULL, - NULL, - &ip6_route_table, - &ip6_route_metric); - { - const NMPlatformIP6Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_WWAN, - .gateway = address.address, - .table_coerced = nm_platform_route_table_coerce(ip6_route_table), - .metric = ip6_route_metric, - }; - - _LOGI(" gateway %s", address_string); - nm_ip6_config_add_route(config, &r, NULL); - } - } else if (ip_method == NM_MODEM_IP_METHOD_STATIC) { - /* Gateway required for the 'static' method */ - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: missing gateway", - nm_modem_get_uid(NM_MODEM(self))); - goto out; - } - - /* DNS servers */ - dns = mm_bearer_ip_config_get_dns(self->_priv.ipv6_config); - for (i = 0; dns && dns[i]; i++) { - struct in6_addr addr; - - if (inet_pton(AF_INET6, dns[i], &addr)) { - nm_ip6_config_add_nameserver(config, &addr); - _LOGI(" DNS %s", dns[i]); - } - } - -out: - nm_modem_emit_ip6_config_result(NM_MODEM(self), config, error); - g_clear_object(&config); - g_clear_error(&error); - return FALSE; -} - -static NMActStageReturn -stage3_ip6_config_request(NMModem *modem, NMDeviceStateReason *out_failure_reason) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(modem); - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - - /* We schedule it in an idle just to follow the same logic as in the - * generic modem implementation. */ - nm_clear_g_source(&priv->idle_id_ip6); - priv->idle_id_ip6 = g_idle_add((GSourceFunc) stage3_ip6_done, self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ -/* Disconnect */ - -typedef struct { - NMModemBroadband * self; - _NMModemDisconnectCallback callback; - gpointer callback_user_data; - GCancellable * cancellable; - gboolean warn; -} DisconnectContext; - -static void -disconnect_context_complete(DisconnectContext *ctx, GError *error) -{ - if (ctx->callback) - ctx->callback(NM_MODEM(ctx->self), error, ctx->callback_user_data); - nm_g_object_unref(ctx->cancellable); - g_object_unref(ctx->self); - g_slice_free(DisconnectContext, ctx); -} - -static void -disconnect_context_complete_on_idle(gpointer user_data, GCancellable *cancellable) -{ - DisconnectContext *ctx = user_data; - gs_free_error GError *cancelled_error = NULL; - - g_cancellable_set_error_if_cancelled(cancellable, &cancelled_error); - disconnect_context_complete(ctx, cancelled_error); -} - -static void -simple_disconnect_ready(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - MMModemSimple * modem_iface = MM_MODEM_SIMPLE(source_object); - DisconnectContext *ctx = user_data; - gs_free_error GError *error = NULL; - - if (!mm_modem_simple_disconnect_finish(modem_iface, res, &error)) { - if (ctx->warn && !g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { - NMModemBroadband *self = ctx->self; - - _LOGW("failed to disconnect modem: %s", error->message); - } - } - - disconnect_context_complete(ctx, error); -} - -static void -disconnect(NMModem * modem, - gboolean warn, - GCancellable * cancellable, - _NMModemDisconnectCallback callback, - gpointer user_data) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(modem); - DisconnectContext *ctx; - - connect_context_clear(self); - _nm_modem_set_apn(NM_MODEM(self), NULL); - - ctx = g_slice_new0(DisconnectContext); - ctx->self = g_object_ref(self); - ctx->cancellable = nm_g_object_ref(cancellable); - ctx->callback = callback; - ctx->callback_user_data = user_data; - - /* Don't bother warning on FAILED since the modem is already gone */ - ctx->warn = warn; - - /* Already cancelled or no simple-iface? We are done. */ - if (!ctx->self->_priv.simple_iface || g_cancellable_is_cancelled(cancellable)) { - nm_utils_invoke_on_idle(cancellable, disconnect_context_complete_on_idle, ctx); - return; - } - - _LOGD("notifying ModemManager about the modem disconnection"); - mm_modem_simple_disconnect(self->_priv.simple_iface, - NULL, /* bearer path; if NULL given ALL get disconnected */ - cancellable, - simple_disconnect_ready, - ctx); -} - -/*****************************************************************************/ - -static void -deactivate_cleanup(NMModem *modem, NMDevice *device, gboolean stop_ppp_manager) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(modem); - - /* TODO: cancel SimpleConnect() if any */ - - /* Cleanup IPv4 addresses and routes */ - g_clear_object(&self->_priv.ipv4_config); - g_clear_object(&self->_priv.ipv6_config); - g_clear_object(&self->_priv.bearer); - - self->_priv.pin_tries = 0; - - NM_MODEM_CLASS(nm_modem_broadband_parent_class) - ->deactivate_cleanup(modem, device, stop_ppp_manager); -} - -/*****************************************************************************/ - -#define MAP_STATE(name) \ - case MM_MODEM_STATE_##name: \ - return NM_MODEM_STATE_##name; - -static NMModemState -mm_state_to_nm(MMModemState mm_state) -{ - switch (mm_state) { - MAP_STATE(UNKNOWN) - MAP_STATE(FAILED) - MAP_STATE(INITIALIZING) - MAP_STATE(LOCKED) - MAP_STATE(DISABLED) - MAP_STATE(DISABLING) - MAP_STATE(ENABLING) - MAP_STATE(ENABLED) - MAP_STATE(SEARCHING) - MAP_STATE(REGISTERED) - MAP_STATE(DISCONNECTING) - MAP_STATE(CONNECTING) - MAP_STATE(CONNECTED) - } - return NM_MODEM_STATE_UNKNOWN; -} - -static void -modem_state_changed(MMModem * modem, - MMModemState old_state, - MMModemState new_state, - MMModemStateChangeReason reason, - NMModemBroadband * self) -{ - /* After the SIM is unlocked MM1 will move the device to INITIALIZING which - * is an unavailable state. That makes state handling confusing here, so - * suppress this state change and let the modem move from LOCKED to DISABLED. - */ - if (new_state == MM_MODEM_STATE_INITIALIZING && old_state == MM_MODEM_STATE_LOCKED) - return; - - nm_modem_set_state(NM_MODEM(self), - mm_state_to_nm(new_state), - mm_modem_state_change_reason_get_string(reason)); - - if (self->_priv.ctx && self->_priv.ctx->step == CONNECT_STEP_WAIT_FOR_READY) - connect_context_step(self); -} - -/*****************************************************************************/ - -static NMModemIPType -mm_ip_family_to_nm(MMBearerIpFamily family) -{ - NMModemIPType nm_type = NM_MODEM_IP_TYPE_UNKNOWN; - - if (family & MM_BEARER_IP_FAMILY_IPV4) - nm_type |= NM_MODEM_IP_TYPE_IPV4; - if (family & MM_BEARER_IP_FAMILY_IPV6) - nm_type |= NM_MODEM_IP_TYPE_IPV6; - if (family & MM_BEARER_IP_FAMILY_IPV4V6) - nm_type |= MM_BEARER_IP_FAMILY_IPV4V6; - - return nm_type; -} - -static void -get_sim_ready(MMModem *modem, GAsyncResult *res, NMModemBroadband *self) -{ - GError *error = NULL; - MMSim * new_sim; - - new_sim = mm_modem_get_sim_finish(modem, res, &error); - if (new_sim != self->_priv.sim_iface) { - g_clear_object(&self->_priv.sim_iface); - self->_priv.sim_iface = new_sim; - } else - g_clear_object(&new_sim); - - if (self->_priv.sim_iface) { - g_object_set(G_OBJECT(self), - NM_MODEM_SIM_ID, - mm_sim_get_identifier(self->_priv.sim_iface), - NM_MODEM_SIM_OPERATOR_ID, - mm_sim_get_operator_identifier(self->_priv.sim_iface), - NULL); - - /* If we're waiting for the SIM during a connect, proceed with the connect */ - if (self->_priv.ctx && self->_priv.ctx->step == CONNECT_STEP_WAIT_FOR_SIM) - connect_context_step(self); - } else { - _NMLOG(g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND) ? LOGL_INFO - : LOGL_WARN, - "failed to retrieve SIM object: %s", - NM_G_ERROR_MSG(error)); - } - g_clear_error(&error); - g_object_unref(self); -} - -static void -sim_changed(MMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(user_data); - - g_return_if_fail(modem == self->_priv.modem_iface); - - if (mm_modem_get_sim_path(self->_priv.modem_iface)) { - mm_modem_get_sim(self->_priv.modem_iface, - NULL, /* cancellable */ - (GAsyncReadyCallback) get_sim_ready, - g_object_ref(self)); - } else - g_object_set(G_OBJECT(self), NM_MODEM_SIM_ID, NULL, NM_MODEM_SIM_OPERATOR_ID, NULL, NULL); -} - -static void -supported_ip_families_changed(MMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(user_data); - - g_return_if_fail(modem == self->_priv.modem_iface); - - g_object_set(G_OBJECT(self), - NM_MODEM_IP_TYPES, - mm_ip_family_to_nm(mm_modem_get_supported_ip_families(modem)), - NULL); -} - -static void -operator_code_changed(MMModem3gpp *modem_3gpp, GParamSpec *pspec, gpointer user_data) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(user_data); - - g_return_if_fail(modem_3gpp == self->_priv.modem_3gpp_iface); - _nm_modem_set_operator_code(NM_MODEM(self), mm_modem_3gpp_get_operator_code(modem_3gpp)); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(object); - - switch (prop_id) { - case PROP_MODEM: - g_value_set_object(value, self->_priv.modem_object); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(object); - - switch (prop_id) { - case PROP_MODEM: - /* construct-only */ - self->_priv.modem_object = g_value_dup_object(value); - self->_priv.modem_iface = mm_object_get_modem(self->_priv.modem_object); - g_return_if_fail(self->_priv.modem_iface); - self->_priv.modem_3gpp_iface = mm_object_get_modem_3gpp(self->_priv.modem_object); - - g_signal_connect(self->_priv.modem_iface, - "state-changed", - G_CALLBACK(modem_state_changed), - self); - g_signal_connect(self->_priv.modem_iface, "notify::sim", G_CALLBACK(sim_changed), self); - sim_changed(self->_priv.modem_iface, NULL, self); - g_signal_connect(self->_priv.modem_iface, - "notify::supported-ip-families", - G_CALLBACK(supported_ip_families_changed), - self); - - if (self->_priv.modem_3gpp_iface) { - g_signal_connect(self->_priv.modem_3gpp_iface, - "notify::operator-code", - G_CALLBACK(operator_code_changed), - self); - } - - /* Note: don't grab the Simple iface here; the Modem interface is the - * only one assumed to be always valid and available */ - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_modem_broadband_init(NMModemBroadband *self) -{} - -NMModem * -nm_modem_broadband_new(GObject *object, GError **error) -{ - MMObject * modem_object; - MMModem * modem_iface; - MMModem3gpp * modem_3gpp_iface; - const char *const *drivers; - const char * operator_code = NULL; - gs_free char * driver = NULL; - - g_return_val_if_fail(MM_IS_OBJECT(object), NULL); - modem_object = MM_OBJECT(object); - - /* Ensure we have the 'Modem' interface and the primary port at least */ - modem_iface = mm_object_peek_modem(modem_object); - g_return_val_if_fail(modem_iface, NULL); - g_return_val_if_fail(mm_modem_get_primary_port(modem_iface), NULL); - - /* Build a single string with all drivers listed */ - drivers = mm_modem_get_drivers(modem_iface); - if (drivers) - driver = g_strjoinv(", ", (char **) drivers); - - modem_3gpp_iface = mm_object_peek_modem_3gpp(modem_object); - if (modem_3gpp_iface) - operator_code = mm_modem_3gpp_get_operator_code(modem_3gpp_iface); - - return g_object_new(NM_TYPE_MODEM_BROADBAND, - NM_MODEM_PATH, - mm_object_get_path(modem_object), - NM_MODEM_UID, - mm_modem_get_primary_port(modem_iface), - NM_MODEM_CONTROL_PORT, - mm_modem_get_primary_port(modem_iface), - NM_MODEM_IP_TYPES, - mm_ip_family_to_nm(mm_modem_get_supported_ip_families(modem_iface)), - NM_MODEM_STATE, - (int) mm_state_to_nm(mm_modem_get_state(modem_iface)), - NM_MODEM_DEVICE_ID, - mm_modem_get_device_identifier(modem_iface), - NM_MODEM_BROADBAND_MODEM, - modem_object, - NM_MODEM_DRIVER, - driver, - NM_MODEM_OPERATOR_CODE, - operator_code, - NULL); -} - -static void -dispose(GObject *object) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(object); - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - - nm_clear_g_source(&priv->idle_id_ip4); - nm_clear_g_source(&priv->idle_id_ip6); - - connect_context_clear(self); - g_clear_object(&self->_priv.ipv4_config); - g_clear_object(&self->_priv.ipv6_config); - g_clear_object(&self->_priv.bearer); - - if (self->_priv.modem_iface) { - g_signal_handlers_disconnect_by_data(self->_priv.modem_iface, self); - g_clear_object(&self->_priv.modem_iface); - } - - if (self->_priv.modem_3gpp_iface) { - g_signal_handlers_disconnect_by_data(self->_priv.modem_3gpp_iface, self); - g_clear_object(&self->_priv.modem_3gpp_iface); - } - - g_clear_object(&self->_priv.simple_iface); - g_clear_object(&self->_priv.sim_iface); - g_clear_object(&self->_priv.modem_object); - - G_OBJECT_CLASS(nm_modem_broadband_parent_class)->dispose(object); -} - -static void -nm_modem_broadband_class_init(NMModemBroadbandClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - NMModemClass *modem_class = NM_MODEM_CLASS(klass); - - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - modem_class->get_capabilities = get_capabilities; - modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; - modem_class->stage3_ip6_config_request = stage3_ip6_config_request; - modem_class->disconnect = disconnect; - modem_class->deactivate_cleanup = deactivate_cleanup; - modem_class->set_mm_enabled = set_mm_enabled; - modem_class->get_user_pass = get_user_pass; - modem_class->check_connection_compatible_with_modem = check_connection_compatible_with_modem; - modem_class->complete_connection = complete_connection; - modem_class->modem_act_stage1_prepare = modem_act_stage1_prepare; - modem_class->owns_port = owns_port; - - obj_properties[PROP_MODEM] = - g_param_spec_object(NM_MODEM_BROADBAND_MODEM, - "", - "", - MM_GDBUS_TYPE_OBJECT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/wwan/nm-modem-broadband.h b/src/devices/wwan/nm-modem-broadband.h deleted file mode 100644 index 5a822f6f..00000000 --- a/src/devices/wwan/nm-modem-broadband.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2012 - Aleksander Morgado <aleksander@gnu.org> - */ - -#ifndef __NETWORKMANAGER_MODEM_BROADBAND_H__ -#define __NETWORKMANAGER_MODEM_BROADBAND_H__ - -#include "nm-modem.h" - -#define NM_TYPE_MODEM_BROADBAND (nm_modem_broadband_get_type()) -#define NM_MODEM_BROADBAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) -#define NM_MODEM_BROADBAND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) -#define NM_IS_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_BROADBAND)) -#define NM_IS_MODEM_BROADBAND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM_BROADBAND)) -#define NM_MODEM_BROADBAND_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) - -typedef struct _NMModemBroadband NMModemBroadband; -typedef struct _NMModemBroadbandClass NMModemBroadbandClass; - -GType nm_modem_broadband_get_type(void); - -NMModem *nm_modem_broadband_new(GObject *object, GError **error); - -#endif /* __NETWORKMANAGER_MODEM_BROADBAND_H__ */ diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c deleted file mode 100644 index 65f7c9f9..00000000 --- a/src/devices/wwan/nm-modem-manager.c +++ /dev/null @@ -1,876 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2014 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - * Copyright (C) 2009 - 2013 Canonical Ltd. - */ - -#include "nm-default.h" - -#include "nm-modem-manager.h" - -#include <libmm-glib.h> - -#if HAVE_LIBSYSTEMD - #include <systemd/sd-daemon.h> -#else - #define sd_booted() FALSE -#endif - -#include "nm-std-aux/nm-dbus-compat.h" -#include "nm-modem.h" -#include "nm-modem-broadband.h" - -#if WITH_OFONO - #include "nm-modem-ofono.h" -#endif - -#define MODEM_POKE_INTERVAL 120 - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMModemManager, PROP_NAME_OWNER, ); - -enum { - MODEM_ADDED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct { - GDBusConnection *dbus_connection; - - /* used during g_bus_get() and later during mm_manager_new(). */ - GCancellable *main_cancellable; - - struct { - MMManager * manager; - GCancellable *poke_cancellable; - gulong handle_name_owner_changed_id; - gulong handle_object_added_id; - gulong handle_object_removed_id; - guint relaunch_id; - - /* this only has one use: that the <info> logging line about - * ModemManager available distinguishes between first-time - * and later name-owner-changed. */ - enum { - LOG_AVAILABLE_NOT_INITIALIZED = 0, - LOG_AVAILABLE_YES, - LOG_AVAILABLE_NO, - } log_available : 3; - - GDBusProxy * proxy; - GCancellable *proxy_cancellable; - guint proxy_ref_count; - char * proxy_name_owner; - } modm; - -#if WITH_OFONO - struct { - GDBusProxy * proxy; - GCancellable *cancellable; - } ofono; -#endif - - GHashTable *modems; -} NMModemManagerPrivate; - -struct _NMModemManager { - GObject parent; - NMModemManagerPrivate _priv; -}; - -struct _NMModemManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMModemManager, nm_modem_manager, G_TYPE_OBJECT) - -#define NM_MODEM_MANAGER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMModemManager, NM_IS_MODEM_MANAGER) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_MB -#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "modem-manager", __VA_ARGS__) - -/*****************************************************************************/ - -NM_DEFINE_SINGLETON_GETTER(NMModemManager, nm_modem_manager_get, NM_TYPE_MODEM_MANAGER); - -/*****************************************************************************/ - -static void modm_schedule_manager_relaunch(NMModemManager *self, guint n_seconds); -static void modm_ensure_manager(NMModemManager *self); - -/*****************************************************************************/ - -static void -handle_new_modem(NMModemManager *self, NMModem *modem) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - const char * path; - - path = nm_modem_get_path(modem); - if (g_hash_table_lookup(priv->modems, path)) { - g_warn_if_reached(); - return; - } - - /* Track the new modem */ - g_hash_table_insert(priv->modems, g_strdup(path), modem); - g_signal_emit(self, signals[MODEM_ADDED], 0, modem); -} - -static gboolean -remove_one_modem(gpointer key, gpointer value, gpointer user_data) -{ - nm_modem_emit_removed(NM_MODEM(value)); - return TRUE; -} - -/*****************************************************************************/ - -NMModem ** -nm_modem_manager_get_modems(NMModemManager *self, guint *out_len) -{ - g_return_val_if_fail(NM_IS_MODEM_MANAGER(self), NULL); - - return (NMModem **) nm_utils_hash_values_to_array(NM_MODEM_MANAGER_GET_PRIVATE(self)->modems, - NULL, - NULL, - out_len); -} - -/*****************************************************************************/ - -static void -modm_clear_manager(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - if (!priv->modm.manager) - return; - nm_clear_g_signal_handler(priv->modm.manager, &priv->modm.handle_name_owner_changed_id); - nm_clear_g_signal_handler(priv->modm.manager, &priv->modm.handle_object_added_id); - nm_clear_g_signal_handler(priv->modm.manager, &priv->modm.handle_object_removed_id); - g_clear_object(&priv->modm.manager); -} - -static void -modm_handle_object_added(MMManager *modem_manager, MMObject *modem_object, NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - const char * path; - MMModem * modem_iface; - NMModem * modem; - GError * error = NULL; - - /* Ensure we don't have the same modem already */ - path = mm_object_get_path(modem_object); - if (g_hash_table_lookup(priv->modems, path)) { - _LOGW("modem with path %s already exists, ignoring", path); - return; - } - - /* Ensure we have the 'Modem' interface at least */ - modem_iface = mm_object_peek_modem(modem_object); - if (!modem_iface) { - _LOGW("modem with path %s doesn't have the Modem interface, ignoring", path); - return; - } - - /* Ensure we have a primary port reported */ - if (!mm_modem_get_primary_port(modem_iface)) { - _LOGW("modem with path %s has unknown primary port, ignoring", path); - return; - } - - /* Create a new modem object */ - modem = nm_modem_broadband_new(G_OBJECT(modem_object), &error); - if (modem) - handle_new_modem(self, modem); - else - _LOGW("failed to create modem: %s", error->message); - g_clear_error(&error); -} - -static void -modm_handle_object_removed(MMManager *manager, MMObject *modem_object, NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - NMModem * modem; - const char * path; - - path = mm_object_get_path(modem_object); - modem = (NMModem *) g_hash_table_lookup(priv->modems, path); - if (!modem) - return; - - nm_modem_emit_removed(modem); - g_hash_table_remove(priv->modems, path); -} - -static void -modm_manager_available(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - GList * modems, *l; - - if (priv->modm.log_available != LOG_AVAILABLE_YES) { - _LOGI("ModemManager %savailable", priv->modm.log_available ? "now " : ""); - priv->modm.log_available = LOG_AVAILABLE_YES; - } - - /* Update initial modems list */ - modems = g_dbus_object_manager_get_objects(G_DBUS_OBJECT_MANAGER(priv->modm.manager)); - for (l = modems; l; l = g_list_next(l)) - modm_handle_object_added(priv->modm.manager, MM_OBJECT(l->data), self); - g_list_free_full(modems, (GDestroyNotify) g_object_unref); -} - -static void -modm_handle_name_owner_changed(MMManager *modem_manager, GParamSpec *pspec, NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - char * name_owner; - - /* Quit poking, if any */ - nm_clear_g_source(&priv->modm.relaunch_id); - - name_owner = - g_dbus_object_manager_client_get_name_owner(G_DBUS_OBJECT_MANAGER_CLIENT(modem_manager)); - if (!name_owner) { - if (priv->modm.log_available != LOG_AVAILABLE_NO) { - _LOGI("ModemManager %savailable", priv->modm.log_available ? "no longer " : "not "); - priv->modm.log_available = LOG_AVAILABLE_NO; - } - - /* If not managed by systemd, schedule relaunch */ - if (!sd_booted()) - modm_schedule_manager_relaunch(self, 0); - - return; - } - - /* Available! */ - g_free(name_owner); - - /* Hack alert: GDBusObjectManagerClient won't signal neither 'object-added' - * nor 'object-removed' if it was created while there was no ModemManager in - * the bus. This hack avoids this issue until we get a GIO with the fix - * included... */ - modm_clear_manager(self); - modm_ensure_manager(self); - - /* Whenever GDBusObjectManagerClient is fixed, we can just do the following: - * modm_manager_available (self); - */ -} - -static void -modm_manager_poke_cb(GObject *connection, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *result = NULL; - - result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(connection), res, &error); - - if (!result && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->modm.poke_cancellable); - - if (error) { - _LOGW("error poking ModemManager: %s", error->message); - - /* Don't reschedule poke is MM service doesn't exist. */ - if (!g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) - && !g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { - /* Setup timeout to relaunch */ - modm_schedule_manager_relaunch(self, MODEM_POKE_INTERVAL); - } - } -} - -static void -modm_manager_poke(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - nm_clear_g_cancellable(&priv->modm.poke_cancellable); - priv->modm.poke_cancellable = g_cancellable_new(); - - /* If there is no current owner right away, ensure we poke to get one */ - g_dbus_connection_call(priv->dbus_connection, - NM_MODEM_MANAGER_MM_DBUS_SERVICE, - NM_MODEM_MANAGER_MM_DBUS_PATH, - DBUS_INTERFACE_PEER, - "Ping", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->modm.poke_cancellable, - modm_manager_poke_cb, - self); -} - -static void -modm_manager_check_name_owner(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - gs_free char * name_owner = NULL; - - name_owner = g_dbus_object_manager_client_get_name_owner( - G_DBUS_OBJECT_MANAGER_CLIENT(priv->modm.manager)); - if (name_owner) { - modm_manager_available(self); - return; - } - - /* If the lifecycle is not managed by systemd, poke */ - if (!sd_booted()) - modm_manager_poke(self); -} - -static void -modm_manager_new_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - MMManager * modem_manager; - - modem_manager = mm_manager_new_finish(res, &error); - if (!modem_manager && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - nm_assert(!priv->modm.manager); - - g_clear_object(&priv->main_cancellable); - - if (!modem_manager) { - /* We're not really supposed to get any error here. If we do get one, - * though, just re-schedule the MMManager creation after some time. - * During this period, name-owner changes won't be followed. */ - _LOGW("error creating ModemManager client: %s", error->message); - /* Setup timeout to relaunch */ - modm_schedule_manager_relaunch(self, MODEM_POKE_INTERVAL); - return; - } - - priv->modm.manager = modem_manager; - - /* Setup signals in the GDBusObjectManagerClient */ - priv->modm.handle_name_owner_changed_id = - g_signal_connect(priv->modm.manager, - "notify::name-owner", - G_CALLBACK(modm_handle_name_owner_changed), - self); - priv->modm.handle_object_added_id = g_signal_connect(priv->modm.manager, - "object-added", - G_CALLBACK(modm_handle_object_added), - self); - priv->modm.handle_object_removed_id = g_signal_connect(priv->modm.manager, - "object-removed", - G_CALLBACK(modm_handle_object_removed), - self); - - modm_manager_check_name_owner(self); -} - -static void -modm_ensure_manager(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_assert(priv->dbus_connection); - - /* Create the GDBusObjectManagerClient. We do not request to autostart, as - * we don't really want the MMManager creation to fail. We can always poke - * later on if we want to request the autostart */ - if (!priv->modm.manager) { - if (!priv->main_cancellable) - priv->main_cancellable = g_cancellable_new(); - mm_manager_new(priv->dbus_connection, - G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, - priv->main_cancellable, - modm_manager_new_cb, - self); - return; - } - - /* If already available, recheck name owner! */ - modm_manager_check_name_owner(self); -} - -static gboolean -modm_schedule_manager_relaunch_cb(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - priv->modm.relaunch_id = 0; - modm_ensure_manager(self); - return G_SOURCE_REMOVE; -} - -static void -modm_schedule_manager_relaunch(NMModemManager *self, guint n_seconds) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - /* No need to pass an extra reference to self; timeout/idle will be - * cancelled if the object gets disposed. */ - if (n_seconds) - priv->modm.relaunch_id = - g_timeout_add_seconds(n_seconds, (GSourceFunc) modm_schedule_manager_relaunch_cb, self); - else - priv->modm.relaunch_id = g_idle_add((GSourceFunc) modm_schedule_manager_relaunch_cb, self); -} - -/*****************************************************************************/ - -static void -modm_proxy_name_owner_reset(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - char * name = NULL; - - if (priv->modm.proxy) - name = g_dbus_proxy_get_name_owner(priv->modm.proxy); - - if (nm_streq0(priv->modm.proxy_name_owner, name)) { - g_free(name); - return; - } - g_free(priv->modm.proxy_name_owner); - priv->modm.proxy_name_owner = name; - - _notify(self, PROP_NAME_OWNER); -} - -static void -modm_proxy_name_owner_changed_cb(GObject *object, GParamSpec *pspec, gpointer user_data) -{ - modm_proxy_name_owner_reset(user_data); -} - -static void -modm_proxy_new_cb(GObject *source_object, GAsyncResult *result, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - GDBusProxy * proxy; - gs_free_error GError *error = NULL; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->modm.proxy_cancellable); - - if (!proxy) { - _LOGW("could not obtain D-Bus proxy for ModemManager: %s", error->message); - return; - } - - priv->modm.proxy = proxy; - g_signal_connect(priv->modm.proxy, - "notify::g-name-owner", - G_CALLBACK(modm_proxy_name_owner_changed_cb), - self); - - modm_proxy_name_owner_reset(self); -} - -void -nm_modem_manager_name_owner_ref(NMModemManager *self) -{ - NMModemManagerPrivate *priv; - - g_return_if_fail(NM_IS_MODEM_MANAGER(self)); - - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - if (priv->modm.proxy_ref_count++ > 0) { - /* only try once to create the proxy. If proxy creation - * for the first "ref" failed, it's unclear what to do. - * The proxy is hosed. */ - return; - } - - nm_assert(!priv->modm.proxy && !priv->modm.proxy_cancellable); - - priv->modm.proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - NM_MODEM_MANAGER_MM_DBUS_SERVICE, - NM_MODEM_MANAGER_MM_DBUS_PATH, - NM_MODEM_MANAGER_MM_DBUS_INTERFACE, - priv->modm.proxy_cancellable, - modm_proxy_new_cb, - self); -} - -void -nm_modem_manager_name_owner_unref(NMModemManager *self) -{ - NMModemManagerPrivate *priv; - - g_return_if_fail(NM_IS_MODEM_MANAGER(self)); - - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_return_if_fail(priv->modm.proxy_ref_count > 0); - - if (--priv->modm.proxy_ref_count > 0) - return; - - nm_clear_g_cancellable(&priv->modm.proxy_cancellable); - g_clear_object(&priv->modm.proxy); - - modm_proxy_name_owner_reset(self); -} - -const char * -nm_modem_manager_name_owner_get(NMModemManager *self) -{ - g_return_val_if_fail(NM_IS_MODEM_MANAGER(self), NULL); - nm_assert(NM_MODEM_MANAGER_GET_PRIVATE(self)->modm.proxy_ref_count > 0); - - return NM_MODEM_MANAGER_GET_PRIVATE(self)->modm.proxy_name_owner; -} - -/*****************************************************************************/ - -#if WITH_OFONO - -static void -ofono_create_modem(NMModemManager *self, const char *path) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - NMModem * modem = NULL; - - /* Ensure duplicate modems aren't created. Because we're not using the - * ObjectManager interface there's a race during oFono startup where we - * receive ModemAdded signals before GetModems() returns, so some of the - * modems returned from GetModems() may already have been created. - */ - if (!g_hash_table_lookup(priv->modems, path)) { - modem = nm_modem_ofono_new(path); - if (modem) - handle_new_modem(self, modem); - else - _LOGW("Failed to create oFono modem for %s", path); - } -} - -static void -ofono_signal_cb(GDBusProxy *proxy, - char * sender_name, - char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMModemManager * self = NM_MODEM_MANAGER(user_data); - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - char * object_path; - NMModem * modem; - - if (g_strcmp0(signal_name, "ModemAdded") == 0) { - g_variant_get(parameters, "(oa{sv})", &object_path, NULL); - _LOGI("oFono modem appeared: %s", object_path); - - ofono_create_modem(NM_MODEM_MANAGER(user_data), object_path); - g_free(object_path); - } else if (g_strcmp0(signal_name, "ModemRemoved") == 0) { - g_variant_get(parameters, "(o)", &object_path); - _LOGI("oFono modem removed: %s", object_path); - - modem = (NMModem *) g_hash_table_lookup(priv->modems, object_path); - if (modem) { - nm_modem_emit_removed(modem); - g_hash_table_remove(priv->modems, object_path); - } else { - _LOGW("could not remove modem %s, not found in table", object_path); - } - g_free(object_path); - } -} - -static void -ofono_enumerate_devices_done(GObject *proxy, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - GVariant * results; - GVariantIter * iter; - const char * path; - - results = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error); - if (!results && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_MANAGER(user_data); - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->ofono.cancellable); - - if (!results) { - _LOGW("failed to enumerate oFono devices: %s", error->message); - return; - } - - g_variant_get(results, "(a(oa{sv}))", &iter); - while (g_variant_iter_loop(iter, "(&oa{sv})", &path, NULL)) - ofono_create_modem(self, path); - g_variant_iter_free(iter); - g_variant_unref(results); -} - -static void -ofono_check_name_owner(NMModemManager *self, gboolean first_invocation) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - gs_free char * name_owner = NULL; - - name_owner = g_dbus_proxy_get_name_owner(G_DBUS_PROXY(priv->ofono.proxy)); - if (name_owner) { - _LOGI("oFono is %savailable", first_invocation ? "" : "now "); - - nm_clear_g_cancellable(&priv->ofono.cancellable); - priv->ofono.cancellable = g_cancellable_new(); - - g_dbus_proxy_call(priv->ofono.proxy, - "GetModems", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->ofono.cancellable, - ofono_enumerate_devices_done, - self); - } else { - GHashTableIter iter; - NMModem * modem; - - _LOGI("oFono is %savailable", first_invocation ? "not " : "no longer "); - - /* Remove any oFono modems that might be left around */ - g_hash_table_iter_init(&iter, priv->modems); - while (g_hash_table_iter_next(&iter, NULL, (gpointer) &modem)) { - if (NM_IS_MODEM_OFONO(modem)) { - nm_modem_emit_removed(modem); - g_hash_table_iter_remove(&iter); - } - } - } -} - -static void -ofono_name_owner_changed(GDBusProxy *ofono_proxy, GParamSpec *pspec, NMModemManager *self) -{ - ofono_check_name_owner(self, FALSE); -} - -static void -ofono_proxy_new_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_finish(res, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_MANAGER(user_data); - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->ofono.cancellable); - - if (!proxy) { - _LOGW("error getting oFono bus proxy: %s", error->message); - return; - } - - priv->ofono.proxy = proxy; - - g_signal_connect(priv->ofono.proxy, - "notify::g-name-owner", - G_CALLBACK(ofono_name_owner_changed), - self); - - g_signal_connect(priv->ofono.proxy, "g-signal", G_CALLBACK(ofono_signal_cb), self); - - ofono_check_name_owner(self, TRUE); -} - -static void -ofono_init_proxy(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - nm_assert(priv->dbus_connection); - nm_assert(!priv->ofono.cancellable); - - priv->ofono.cancellable = g_cancellable_new(); - - g_dbus_proxy_new(priv->dbus_connection, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - OFONO_DBUS_PATH, - OFONO_DBUS_INTERFACE, - priv->ofono.cancellable, - ofono_proxy_new_cb, - self); -} -#endif - -/*****************************************************************************/ - -static void -bus_get_ready(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - GDBusConnection * connection; - - connection = g_bus_get_finish(res, &error); - if (!connection && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_MANAGER(user_data); - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - if (!connection) { - _LOGW("error getting bus connection: %s", error->message); - return; - } - - priv->dbus_connection = connection; - - modm_ensure_manager(self); -#if WITH_OFONO - ofono_init_proxy(self); -#endif -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMModemManager * self = NM_MODEM_MANAGER(object); - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_NAME_OWNER: - g_value_set_string(value, priv->modm.proxy_name_owner); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_modem_manager_init(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - priv->modems = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref); - - priv->main_cancellable = g_cancellable_new(); - - g_bus_get(G_BUS_TYPE_SYSTEM, priv->main_cancellable, bus_get_ready, self); -} - -static void -dispose(GObject *object) -{ - NMModemManager * self = NM_MODEM_MANAGER(object); - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - nm_clear_g_cancellable(&priv->main_cancellable); - nm_clear_g_cancellable(&priv->modm.poke_cancellable); - - nm_clear_g_source(&priv->modm.relaunch_id); - - nm_clear_g_cancellable(&priv->modm.proxy_cancellable); - g_clear_object(&priv->modm.proxy); - nm_clear_g_free(&priv->modm.proxy_name_owner); - - modm_clear_manager(self); - -#if WITH_OFONO - if (priv->ofono.proxy) { - g_signal_handlers_disconnect_by_func(priv->ofono.proxy, ofono_name_owner_changed, self); - g_signal_handlers_disconnect_by_func(priv->ofono.proxy, ofono_signal_cb, self); - g_clear_object(&priv->ofono.proxy); - } - nm_clear_g_cancellable(&priv->ofono.cancellable); -#endif - - g_clear_object(&priv->dbus_connection); - - if (priv->modems) { - g_hash_table_foreach_remove(priv->modems, remove_one_modem, object); - g_hash_table_destroy(priv->modems); - priv->modems = NULL; - } - - G_OBJECT_CLASS(nm_modem_manager_parent_class)->dispose(object); -} - -static void -nm_modem_manager_class_init(NMModemManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->dispose = dispose; - object_class->get_property = get_property; - - obj_properties[PROP_NAME_OWNER] = - g_param_spec_string(NM_MODEM_MANAGER_NAME_OWNER, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[MODEM_ADDED] = g_signal_new(NM_MODEM_MANAGER_MODEM_ADDED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - NM_TYPE_MODEM); -} diff --git a/src/devices/wwan/nm-modem-manager.h b/src/devices/wwan/nm-modem-manager.h deleted file mode 100644 index 895d4ced..00000000 --- a/src/devices/wwan/nm-modem-manager.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2014 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - * Copyright (C) 2009 Canonical Ltd. - */ - -#ifndef __NETWORKMANAGER_MODEM_MANAGER_H__ -#define __NETWORKMANAGER_MODEM_MANAGER_H__ - -#include "nm-modem.h" - -#define NM_TYPE_MODEM_MANAGER (nm_modem_manager_get_type()) -#define NM_MODEM_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) -#define NM_MODEM_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) -#define NM_IS_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_MANAGER)) -#define NM_IS_MODEM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM_MANAGER)) -#define NM_MODEM_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) - -#define NM_MODEM_MANAGER_MODEM_ADDED "modem-added" - -#define NM_MODEM_MANAGER_NAME_OWNER "name-owner" - -#define NM_MODEM_MANAGER_MM_DBUS_SERVICE "org.freedesktop.ModemManager1" -#define NM_MODEM_MANAGER_MM_DBUS_PATH "/org/freedesktop/ModemManager1" -#define NM_MODEM_MANAGER_MM_DBUS_INTERFACE "org.freedesktop.ModemManager1" - -typedef struct _NMModemManager NMModemManager; -typedef struct _NMModemManagerClass NMModemManagerClass; - -GType nm_modem_manager_get_type(void); - -NMModemManager *nm_modem_manager_get(void); - -void nm_modem_manager_name_owner_ref(NMModemManager *self); -void nm_modem_manager_name_owner_unref(NMModemManager *self); - -const char *nm_modem_manager_name_owner_get(NMModemManager *self); - -NMModem **nm_modem_manager_get_modems(NMModemManager *self, guint *out_len); - -#endif /* __NETWORKMANAGER_MODEM_MANAGER_H__ */ diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c deleted file mode 100644 index d8d0893b..00000000 --- a/src/devices/wwan/nm-modem-ofono.c +++ /dev/null @@ -1,1239 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - 2016 Canonical Ltd. - */ - -#include "nm-default.h" - -#include "nm-modem-ofono.h" - -#include "nm-core-internal.h" -#include "devices/nm-device-private.h" -#include "nm-modem.h" -#include "platform/nm-platform.h" -#include "nm-ip4-config.h" - -#define VARIANT_IS_OF_TYPE_BOOLEAN(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_BOOLEAN))) -#define VARIANT_IS_OF_TYPE_STRING(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_STRING))) -#define VARIANT_IS_OF_TYPE_OBJECT_PATH(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_OBJECT_PATH))) -#define VARIANT_IS_OF_TYPE_STRING_ARRAY(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_STRING_ARRAY))) -#define VARIANT_IS_OF_TYPE_DICTIONARY(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_DICTIONARY))) - -/*****************************************************************************/ - -typedef struct { - GHashTable *connect_properties; - - GDBusProxy *modem_proxy; - GDBusProxy *connman_proxy; - GDBusProxy *context_proxy; - GDBusProxy *sim_proxy; - - GCancellable *modem_proxy_cancellable; - GCancellable *connman_proxy_cancellable; - GCancellable *context_proxy_cancellable; - GCancellable *sim_proxy_cancellable; - - GError *property_error; - - char *context_path; - char *imsi; - - gboolean modem_online; - gboolean gprs_attached; - - NMIP4Config *ip4_config; -} NMModemOfonoPrivate; - -struct _NMModemOfono { - NMModem parent; - NMModemOfonoPrivate _priv; -}; - -struct _NMModemOfonoClass { - NMModemClass parent; -}; - -G_DEFINE_TYPE(NMModemOfono, nm_modem_ofono, NM_TYPE_MODEM) - -#define NM_MODEM_OFONO_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMModemOfono, NM_IS_MODEM_OFONO) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_MB -#define _NMLOG_PREFIX_NAME "modem-ofono" -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - \ - if (nm_logging_enabled(_level, (_NMLOG_DOMAIN))) { \ - NMModemOfono *const __self = (self); \ - char __prefix_name[128]; \ - const char * __uid; \ - \ - _nm_log(_level, \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - (__self ? ({ \ - ((__uid = nm_modem_get_uid((NMModem *) __self)) \ - ? nm_sprintf_buf(__prefix_name, "[%s]", __uid) \ - : "(null)"); \ - }) \ - : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static void -get_capabilities(NMModem * _self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps) -{ - /* FIXME: auto-detect capabilities to allow LTE */ - *modem_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; - *current_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; -} - -static void -update_modem_state(NMModemOfono *self) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - NMModemState state = nm_modem_get_state(NM_MODEM(self)); - NMModemState new_state = NM_MODEM_STATE_DISABLED; - const char * reason = NULL; - - _LOGI("'Attached': %s 'Online': %s 'IMSI': %s", - priv->gprs_attached ? "true" : "false", - priv->modem_online ? "true" : "false", - priv->imsi); - - if (priv->modem_online == FALSE) { - reason = "modem 'Online=false'"; - } else if (priv->imsi == NULL && state != NM_MODEM_STATE_ENABLING) { - reason = "modem not ready"; - } else if (priv->gprs_attached == FALSE) { - new_state = NM_MODEM_STATE_SEARCHING; - reason = "modem searching"; - } else { - new_state = NM_MODEM_STATE_REGISTERED; - reason = "modem ready"; - } - - if (state != new_state) - nm_modem_set_state(NM_MODEM(self), new_state, reason); -} - -/* Disconnect */ -typedef struct { - NMModemOfono * self; - _NMModemDisconnectCallback callback; - gpointer callback_user_data; - GCancellable * cancellable; - gboolean warn; -} DisconnectContext; - -static void -disconnect_context_complete(DisconnectContext *ctx, GError *error) -{ - if (ctx->callback) - ctx->callback(NM_MODEM(ctx->self), error, ctx->callback_user_data); - nm_g_object_unref(ctx->cancellable); - g_object_unref(ctx->self); - g_slice_free(DisconnectContext, ctx); -} - -static void -disconnect_context_complete_on_idle(gpointer user_data, GCancellable *cancellable) -{ - DisconnectContext *ctx = user_data; - gs_free_error GError *error = NULL; - - if (!g_cancellable_set_error_if_cancelled(cancellable, &error)) { - g_set_error_literal(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - ("modem is currently not connected")); - } - disconnect_context_complete(ctx, error); -} - -static void -disconnect_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - DisconnectContext *ctx = user_data; - NMModemOfono * self = ctx->self; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v = NULL; - - v = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, &error); - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - disconnect_context_complete(ctx, error); - return; - } - - if (error && ctx->warn) - _LOGW("failed to disconnect modem: %s", error->message); - - _LOGD("modem disconnected"); - - update_modem_state(self); - disconnect_context_complete(ctx, error); -} - -static void -disconnect(NMModem * modem, - gboolean warn, - GCancellable * cancellable, - _NMModemDisconnectCallback callback, - gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - DisconnectContext * ctx; - NMModemState state = nm_modem_get_state(NM_MODEM(self)); - - _LOGD("warn: %s modem_state: %s", warn ? "TRUE" : "FALSE", nm_modem_state_to_string(state)); - - ctx = g_slice_new0(DisconnectContext); - ctx->self = g_object_ref(self); - ctx->cancellable = nm_g_object_ref(cancellable); - ctx->warn = warn; - ctx->callback = callback; - ctx->callback_user_data = user_data; - - if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable)) { - nm_utils_invoke_on_idle(cancellable, disconnect_context_complete_on_idle, ctx); - return; - } - - nm_modem_set_state(NM_MODEM(self), - NM_MODEM_STATE_DISCONNECTING, - nm_modem_state_to_string(NM_MODEM_STATE_DISCONNECTING)); - - g_dbus_proxy_call(priv->context_proxy, - "SetProperty", - g_variant_new("(sv)", "Active", g_variant_new("b", warn)), - G_DBUS_CALL_FLAGS_NONE, - 20000, - ctx->cancellable, - disconnect_done, - ctx); -} - -static void -deactivate_cleanup(NMModem *modem, NMDevice *device, gboolean stop_ppp_manager) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - /* TODO: cancel SimpleConnect() if any */ - - g_clear_object(&priv->ip4_config); - - NM_MODEM_CLASS(nm_modem_ofono_parent_class) - ->deactivate_cleanup(modem, device, stop_ppp_manager); -} - -static gboolean -check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection, GError **error) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char * id; - - if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, NULL)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "connection type %s is not supported by ofono modem", - nm_connection_get_connection_type(connection)); - return FALSE; - } - - if (!priv->imsi) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem has no IMSI"); - return FALSE; - } - - id = nm_connection_get_id(connection); - - if (!strstr(id, "/context")) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID has no context"); - return FALSE; - } - - if (!strstr(id, priv->imsi)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID does not contain the IMSI"); - return FALSE; - } - - return TRUE; -} - -static void -handle_sim_property(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (g_strcmp0(property, "SubscriberIdentity") == 0 && VARIANT_IS_OF_TYPE_STRING(v)) { - gsize length; - const char *value_str = g_variant_get_string(v, &length); - - _LOGD("SubscriberIdentify found"); - - /* Check for empty DBus string value */ - if (length && g_strcmp0(value_str, "(null)") != 0 - && g_strcmp0(value_str, priv->imsi) != 0) { - if (priv->imsi != NULL) { - _LOGW("SimManager:'SubscriberIdentity' changed: %s", priv->imsi); - g_free(priv->imsi); - } - - priv->imsi = g_strdup(value_str); - update_modem_state(self); - } - } -} - -static void -sim_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - GVariant *v_child = g_variant_get_child_value(v, 0); - - handle_sim_property(proxy, property, v_child, user_data); - g_variant_unref(v_child); -} - -static void -sim_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v_properties = NULL; - gs_unref_variant GVariant *v_dict = NULL; - GVariant * v; - GVariantIter i; - const char * property; - - v_properties = - _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, G_VARIANT_TYPE("(a{sv})"), &error); - if (!v_properties && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->sim_proxy_cancellable); - - if (!v_properties) { - g_dbus_error_strip_remote_error(error); - _LOGW("error getting sim properties: %s", error->message); - return; - } - - _LOGD("sim v_properties is type: %s", g_variant_get_type_string(v_properties)); - - v_dict = g_variant_get_child_value(v_properties, 0); - if (!v_dict) { - _LOGW("error getting sim properties: no v_dict"); - return; - } - - _LOGD("sim v_dict is type: %s", g_variant_get_type_string(v_dict)); - - /* - * TODO: - * 1) optimize by looking up properties ( Online, Interfaces ), instead - * of iterating - * - * 2) reduce code duplication between all of the get_properties_done - * functions in this class. - */ - - g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { - handle_sim_property(NULL, property, v, self); - g_variant_unref(v); - } -} - -static void -_sim_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (!proxy) { - _LOGW("failed to create SimManager proxy: %s", error->message); - g_clear_object(&priv->sim_proxy_cancellable); - return; - } - - priv->sim_proxy = proxy; - - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->sim_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(sim_property_changed), - self); - - g_dbus_proxy_call(priv->sim_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - priv->sim_proxy_cancellable, - sim_get_properties_done, - self); -} - -static void -handle_sim_iface(NMModemOfono *self, gboolean found) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - _LOGD("SimManager interface %sfound", found ? "" : "not "); - - if (!found && (priv->sim_proxy || priv->sim_proxy_cancellable)) { - _LOGI("SimManager interface disappeared"); - nm_clear_g_cancellable(&priv->sim_proxy_cancellable); - if (priv->sim_proxy) { - g_signal_handlers_disconnect_by_data(priv->sim_proxy, self); - g_clear_object(&priv->sim_proxy); - } - nm_clear_g_free(&priv->imsi); - update_modem_state(self); - } else if (found && (!priv->sim_proxy && !priv->sim_proxy_cancellable)) { - _LOGI("found new SimManager interface"); - - priv->sim_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* GDBusInterfaceInfo */ - OFONO_DBUS_SERVICE, - nm_modem_get_path(NM_MODEM(self)), - OFONO_DBUS_INTERFACE_SIM_MANAGER, - priv->sim_proxy_cancellable, /* GCancellable */ - _sim_proxy_new_cb, - self); - } -} - -static void -handle_connman_property(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (g_strcmp0(property, "Attached") == 0 && VARIANT_IS_OF_TYPE_BOOLEAN(v)) { - gboolean attached = g_variant_get_boolean(v); - gboolean old_attached = priv->gprs_attached; - - _LOGD("Attached: %s", attached ? "True" : "False"); - - if (priv->gprs_attached != attached) { - priv->gprs_attached = attached; - - _LOGI("Attached %s -> %s", - old_attached ? "true" : "false", - attached ? "true" : "false"); - - update_modem_state(self); - } - } -} - -static void -connman_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - GVariant *v_child = g_variant_get_child_value(v, 0); - - handle_connman_property(proxy, property, v_child, user_data); - g_variant_unref(v_child); -} - -static void -connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v_properties = NULL; - gs_unref_variant GVariant *v_dict = NULL; - GVariant * v; - GVariantIter i; - const char * property; - - v_properties = - _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, G_VARIANT_TYPE("(a{sv})"), &error); - if (!v_properties && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->connman_proxy_cancellable); - - if (!v_properties) { - g_dbus_error_strip_remote_error(error); - _LOGW("error getting connman properties: %s", error->message); - return; - } - - v_dict = g_variant_get_child_value(v_properties, 0); - - /* - * TODO: - * 1) optimize by looking up properties ( Online, Interfaces ), instead - * of iterating - * - * 2) reduce code duplication between all of the get_properties_done - * functions in this class. - */ - - g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { - handle_connman_property(NULL, property, v, self); - g_variant_unref(v); - } -} - -static void -_connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (!proxy) { - _LOGW("failed to create ConnectionManager proxy: %s", error->message); - g_clear_object(&priv->connman_proxy_cancellable); - return; - } - - priv->connman_proxy = proxy; - - _nm_dbus_signal_connect(priv->connman_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(connman_property_changed), - self); - - g_dbus_proxy_call(priv->connman_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - priv->connman_proxy_cancellable, - connman_get_properties_done, - self); -} - -static void -handle_connman_iface(NMModemOfono *self, gboolean found) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - _LOGD("ConnectionManager interface %sfound", found ? "" : "not "); - - if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) { - _LOGI("ConnectionManager interface disappeared"); - nm_clear_g_cancellable(&priv->connman_proxy_cancellable); - if (priv->connman_proxy) { - g_signal_handlers_disconnect_by_data(priv->connman_proxy, self); - g_clear_object(&priv->connman_proxy); - } - - /* The connection manager proxy disappeared, we should - * consider the modem disabled. - */ - priv->gprs_attached = FALSE; - - update_modem_state(self); - } else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) { - _LOGI("found new ConnectionManager interface"); - - priv->connman_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* GDBusInterfaceInfo */ - OFONO_DBUS_SERVICE, - nm_modem_get_path(NM_MODEM(self)), - OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, - priv->connman_proxy_cancellable, - _connman_proxy_new_cb, - self); - } -} - -static void -handle_modem_property(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if ((g_strcmp0(property, "Online") == 0) && VARIANT_IS_OF_TYPE_BOOLEAN(v)) { - gboolean online = g_variant_get_boolean(v); - - _LOGD("Online: %s", online ? "True" : "False"); - - if (online != priv->modem_online) { - priv->modem_online = online; - _LOGI("modem is now %s", online ? "Online" : "Offline"); - update_modem_state(self); - } - - } else if ((g_strcmp0(property, "Interfaces") == 0) && VARIANT_IS_OF_TYPE_STRING_ARRAY(v)) { - const char **array, **iter; - gboolean found_connman = FALSE; - gboolean found_sim = FALSE; - - _LOGD("Interfaces found"); - - array = g_variant_get_strv(v, NULL); - if (array) { - for (iter = array; *iter; iter++) { - if (g_strcmp0(OFONO_DBUS_INTERFACE_SIM_MANAGER, *iter) == 0) - found_sim = TRUE; - else if (g_strcmp0(OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, *iter) == 0) - found_connman = TRUE; - } - g_free(array); - } - - handle_sim_iface(self, found_sim); - handle_connman_iface(self, found_connman); - } -} - -static void -modem_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - GVariant *v_child = g_variant_get_child_value(v, 0); - - handle_modem_property(proxy, property, v_child, user_data); - g_variant_unref(v_child); -} - -static void -modem_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v_properties = NULL; - gs_unref_variant GVariant *v_dict = NULL; - GVariant * v; - GVariantIter i; - const char * property; - - v_properties = - _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, G_VARIANT_TYPE("(a{sv})"), &error); - if (!v_properties && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->modem_proxy_cancellable); - - if (!v_properties) { - g_dbus_error_strip_remote_error(error); - _LOGW("error getting modem properties: %s", error->message); - return; - } - - v_dict = g_variant_get_child_value(v_properties, 0); - if (!v_dict) { - _LOGW("error getting modem properties: no v_dict"); - return; - } - - /* - * TODO: - * 1) optimize by looking up properties ( Online, Interfaces ), instead - * of iterating - * - * 2) reduce code duplication between all of the get_properties_done - * functions in this class. - */ - - g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { - handle_modem_property(NULL, property, v, self); - g_variant_unref(v); - } -} - -static void -stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v = NULL; - - v = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, &error); - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->context_proxy_cancellable); - - nm_clear_pointer(&priv->connect_properties, g_hash_table_destroy); - - if (error) { - _LOGW("connection failed: %s", error->message); - - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); - /* - * FIXME: add code to check for InProgress so that the - * connection doesn't continue to try and activate, - * leading to the connection being disabled, and a 5m - * timeout... - */ - } -} - -static void -context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - NMPlatformIP4Address addr; - gboolean ret = FALSE; - gs_unref_variant GVariant *v_dict = NULL; - const char * interface; - const char * s; - const char ** array, **iter; - guint32 address_network, gateway_network; - guint32 ip4_route_table, ip4_route_metric; - int ifindex; - GError * error = NULL; - - _LOGD("PropertyChanged: %s", property); - - /* - * TODO: might be a good idea and re-factor this to mimic bluez-device, - * ie. have this function just check the key, and call a sub-func to - * handle the action. - */ - - if (g_strcmp0(property, "Settings") != 0) - return; - - v_dict = g_variant_get_child_value(v, 0); - if (!v_dict) { - _LOGW("error getting IPv4 Settings: no v_dict"); - goto out; - } - - _LOGI("IPv4 static Settings:"); - - if (!g_variant_lookup(v_dict, "Interface", "&s", &interface)) { - _LOGW("Settings 'Interface' missing"); - goto out; - } - - _LOGD("Interface: %s", interface); - if (!nm_modem_set_data_port(NM_MODEM(self), - NM_PLATFORM_GET, - interface, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_UNKNOWN, - 0, - &error)) { - _LOGW("failed to connect to modem: %s", error->message); - g_clear_error(&error); - goto out; - } - - ifindex = nm_modem_get_ip_ifindex(NM_MODEM(self)); - nm_assert(ifindex > 0); - - /* TODO: verify handling of ip4_config; check other places it's used... */ - g_clear_object(&priv->ip4_config); - - priv->ip4_config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), ifindex); - - if (!g_variant_lookup(v_dict, "Address", "&s", &s)) { - _LOGW("Settings 'Address' missing"); - goto out; - } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { - _LOGW("can't convert 'Address' %s to addr", s ?: ""); - goto out; - } - memset(&addr, 0, sizeof(addr)); - addr.ifindex = ifindex; - addr.address = address_network; - addr.addr_source = NM_IP_CONFIG_SOURCE_WWAN; - - if (!g_variant_lookup(v_dict, "Netmask", "&s", &s)) { - _LOGW("Settings 'Netmask' missing"); - goto out; - } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { - _LOGW("invalid 'Netmask': %s", s ?: ""); - goto out; - } - addr.plen = nm_utils_ip4_netmask_to_prefix(address_network); - - _LOGI("Address: %s", nm_platform_ip4_address_to_string(&addr, NULL, 0)); - nm_ip4_config_add_address(priv->ip4_config, &addr); - - if (!g_variant_lookup(v_dict, "Gateway", "&s", &s) || !s) { - _LOGW("Settings 'Gateway' missing"); - goto out; - } - if (!nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &gateway_network)) { - _LOGW("invalid 'Gateway': %s", s); - goto out; - } - nm_modem_get_route_parameters(NM_MODEM(self), &ip4_route_table, &ip4_route_metric, NULL, NULL); - { - const NMPlatformIP4Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_WWAN, - .gateway = gateway_network, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, - }; - - _LOGI("Gateway: %s", s); - nm_ip4_config_add_route(priv->ip4_config, &r, NULL); - } - - if (!g_variant_lookup(v_dict, "DomainNameServers", "^a&s", &array)) { - _LOGW("Settings 'DomainNameServers' missing"); - goto out; - } - if (array) { - for (iter = array; *iter; iter++) { - if (nm_utils_parse_inaddr_bin(AF_INET, *iter, NULL, &address_network) - && address_network) { - _LOGI("DNS: %s", *iter); - nm_ip4_config_add_nameserver(priv->ip4_config, address_network); - } else { - _LOGW("invalid NameServer: %s", *iter); - } - } - - if (iter == array) { - _LOGW("Settings: 'DomainNameServers': none specified"); - g_free(array); - goto out; - } - g_free(array); - } - - if (g_variant_lookup(v_dict, "MessageProxy", "&s", &s)) { - _LOGI("MessageProxy: %s", s); - if (s && nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { - nm_modem_get_route_parameters(NM_MODEM(self), - &ip4_route_table, - &ip4_route_metric, - NULL, - NULL); - - { - const NMPlatformIP4Route mms_route = { - .network = address_network, - .plen = 32, - .gateway = gateway_network, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, - }; - - nm_ip4_config_add_route(priv->ip4_config, &mms_route, NULL); - } - } else { - _LOGW("invalid MessageProxy: %s", s); - } - } - - ret = TRUE; - -out: - if (nm_modem_get_state(NM_MODEM(self)) != NM_MODEM_STATE_CONNECTED) { - _LOGI("emitting PREPARE_RESULT: %s", ret ? "TRUE" : "FALSE"); - nm_modem_emit_prepare_result(NM_MODEM(self), - ret, - ret ? NM_DEVICE_STATE_REASON_NONE - : NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else { - _LOGW("MODEM_PPP_FAILED"); - nm_modem_emit_ppp_failed(NM_MODEM(self), NM_DEVICE_STATE_REASON_PPP_FAILED); - } -} - -static NMActStageReturn -static_stage3_ip4_config_start(NMModem * modem, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - GError * error = NULL; - - if (!priv->ip4_config) { - _LOGD("IP4 config not ready(?)"); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - _LOGD("IP4 config is done; setting modem_state -> CONNECTED"); - g_signal_emit_by_name(self, NM_MODEM_IP4_CONFIG_RESULT, priv->ip4_config, error); - - /* Signal listener takes ownership of the IP4Config */ - priv->ip4_config = NULL; - - nm_modem_set_state(NM_MODEM(self), - NM_MODEM_STATE_CONNECTED, - nm_modem_state_to_string(NM_MODEM_STATE_CONNECTED)); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy || g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (!proxy) { - _LOGE("failed to create ofono ConnectionContext DBus proxy: %s", error->message); - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); - return; - } - - priv->context_proxy = proxy; - - if (!priv->gprs_attached) { - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; - } - - /* We have an old copy of the settings from a previous activation, - * clear it so that we can gate getting the IP config from oFono - * on whether or not we have already received them - */ - g_clear_object(&priv->ip4_config); - - _nm_dbus_signal_connect(priv->context_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(context_property_changed), - self); - - g_dbus_proxy_call(priv->context_proxy, - "SetProperty", - g_variant_new("(sv)", "Active", g_variant_new("b", TRUE)), - G_DBUS_CALL_FLAGS_NONE, - 20000, - priv->context_proxy_cancellable, - stage1_prepare_done, - self); -} - -static void -do_context_activate(NMModemOfono *self) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_return_if_fail(NM_IS_MODEM_OFONO(self)); - - nm_clear_g_cancellable(&priv->context_proxy_cancellable); - g_clear_object(&priv->context_proxy); - - priv->context_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - priv->context_path, - OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, - priv->context_proxy_cancellable, - context_proxy_new_cb, - self); -} - -static GHashTable * -create_connect_properties(NMConnection *connection) -{ - NMSettingGsm *setting; - GHashTable * properties; - const char * str; - - setting = nm_connection_get_setting_gsm(connection); - properties = g_hash_table_new(nm_str_hash, g_str_equal); - - str = nm_setting_gsm_get_apn(setting); - if (str) - g_hash_table_insert(properties, "AccessPointName", g_strdup(str)); - - str = nm_setting_gsm_get_username(setting); - if (str) - g_hash_table_insert(properties, "Username", g_strdup(str)); - - str = nm_setting_gsm_get_password(setting); - if (str) - g_hash_table_insert(properties, "Password", g_strdup(str)); - - return properties; -} - -static NMActStageReturn -modem_act_stage1_prepare(NMModem * modem, - NMConnection * connection, - NMDeviceStateReason *out_failure_reason) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char * context_id; - char ** id = NULL; - - context_id = nm_connection_get_id(connection); - id = g_strsplit(context_id, "/", 0); - g_return_val_if_fail(id[2], NM_ACT_STAGE_RETURN_FAILURE); - - _LOGD("trying %s %s", id[1], id[2]); - - g_free(priv->context_path); - priv->context_path = g_strdup_printf("%s/%s", nm_modem_get_path(modem), id[2]); - g_strfreev(id); - - if (!priv->context_path) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (priv->connect_properties) - g_hash_table_destroy(priv->connect_properties); - - priv->connect_properties = create_connect_properties(connection); - - _LOGI("activating context %s", priv->context_path); - - if (nm_modem_get_state(modem) == NM_MODEM_STATE_REGISTERED) { - do_context_activate(self); - } else { - _LOGW("could not activate context: modem is not registered."); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (!proxy) { - _LOGE("failed to create ofono modem DBus proxy: %s", error->message); - g_clear_object(&priv->modem_proxy_cancellable); - return; - } - - priv->modem_proxy = proxy; - - _nm_dbus_signal_connect(priv->modem_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(modem_property_changed), - self); - - g_dbus_proxy_call(priv->modem_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - priv->modem_proxy_cancellable, - modem_get_properties_done, - self); -} - -/*****************************************************************************/ - -static void -nm_modem_ofono_init(NMModemOfono *self) -{} - -static void -constructed(GObject *object) -{ - NMModemOfono * self = NM_MODEM_OFONO(object); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - priv->modem_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - nm_modem_get_path(NM_MODEM(self)), - OFONO_DBUS_INTERFACE_MODEM, - priv->modem_proxy_cancellable, - modem_proxy_new_cb, - self); - - G_OBJECT_CLASS(nm_modem_ofono_parent_class)->constructed(object); -} - -NMModem * -nm_modem_ofono_new(const char *path) -{ - gs_free char *basename = NULL; - - g_return_val_if_fail(path != NULL, NULL); - - nm_log_info(LOGD_MB, "ofono: creating new Ofono modem path %s", path); - - /* Use short modem name (not its object path) as the NM device name (which - * comes from NM_MODEM_UID)and the device ID. - */ - basename = g_path_get_basename(path); - - return (NMModem *) g_object_new(NM_TYPE_MODEM_OFONO, - NM_MODEM_PATH, - path, - NM_MODEM_UID, - basename, - NM_MODEM_DEVICE_ID, - basename, - NM_MODEM_CONTROL_PORT, - "ofono", /* mandatory */ - NM_MODEM_DRIVER, - "ofono", - NM_MODEM_STATE, - (int) NM_MODEM_STATE_INITIALIZING, - NULL); -} - -static void -dispose(GObject *object) -{ - NMModemOfono * self = NM_MODEM_OFONO(object); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - nm_clear_g_cancellable(&priv->modem_proxy_cancellable); - nm_clear_g_cancellable(&priv->connman_proxy_cancellable); - nm_clear_g_cancellable(&priv->context_proxy_cancellable); - nm_clear_g_cancellable(&priv->sim_proxy_cancellable); - - if (priv->connect_properties) { - g_hash_table_destroy(priv->connect_properties); - priv->connect_properties = NULL; - } - - g_clear_object(&priv->ip4_config); - - if (priv->modem_proxy) { - g_signal_handlers_disconnect_by_data(priv->modem_proxy, self); - g_clear_object(&priv->modem_proxy); - } - - if (priv->connman_proxy) { - g_signal_handlers_disconnect_by_data(priv->connman_proxy, self); - g_clear_object(&priv->connman_proxy); - } - - if (priv->context_proxy) { - g_signal_handlers_disconnect_by_data(priv->context_proxy, self); - g_clear_object(&priv->context_proxy); - } - - if (priv->sim_proxy) { - g_signal_handlers_disconnect_by_data(priv->sim_proxy, self); - g_clear_object(&priv->sim_proxy); - } - - g_free(priv->imsi); - priv->imsi = NULL; - - G_OBJECT_CLASS(nm_modem_ofono_parent_class)->dispose(object); -} - -static void -nm_modem_ofono_class_init(NMModemOfonoClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - NMModemClass *modem_class = NM_MODEM_CLASS(klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - - modem_class->get_capabilities = get_capabilities; - modem_class->disconnect = disconnect; - modem_class->deactivate_cleanup = deactivate_cleanup; - modem_class->check_connection_compatible_with_modem = check_connection_compatible_with_modem; - - modem_class->modem_act_stage1_prepare = modem_act_stage1_prepare; - modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; -} diff --git a/src/devices/wwan/nm-modem-ofono.h b/src/devices/wwan/nm-modem-ofono.h deleted file mode 100644 index 10b4a385..00000000 --- a/src/devices/wwan/nm-modem-ofono.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - Canonical Ltd. - */ - -#ifndef NM_MODEM_OFONO_H -#define NM_MODEM_OFONO_H - -#include "nm-modem.h" - -#define NM_TYPE_MODEM_OFONO (nm_modem_ofono_get_type()) -#define NM_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_OFONO, NMModemOfono)) -#define NM_IS_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_OFONO)) -#define NM_MODEM_OFONO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_OFONO, NMModemOfonoClass)) -#define NM_IS_MODEM_OFONO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM_OFONO)) -#define NM_MODEM_OFONO_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MODEM_OFONO, NMModemOfonoClass)) - -#define OFONO_DBUS_SERVICE "org.ofono" -#define OFONO_DBUS_PATH "/" -#define OFONO_DBUS_INTERFACE "org.ofono.Manager" -#define OFONO_DBUS_INTERFACE_MODEM "org.ofono.Modem" -#define OFONO_DBUS_INTERFACE_CONNECTION_MANAGER "org.ofono.ConnectionManager" -#define OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT "org.ofono.ConnectionContext" -#define OFONO_DBUS_INTERFACE_SIM_MANAGER "org.ofono.SimManager" - -typedef struct _NMModemOfono NMModemOfono; -typedef struct _NMModemOfonoClass NMModemOfonoClass; - -GType nm_modem_ofono_get_type(void); - -NMModem *nm_modem_ofono_new(const char *path); - -#endif /* NM_MODEM_OFONO_H */ diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c deleted file mode 100644 index 9e16420e..00000000 --- a/src/devices/wwan/nm-modem.c +++ /dev/null @@ -1,2037 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2014 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#include "nm-default.h" - -#include "nm-modem.h" - -#include <fcntl.h> -#include <termios.h> -#include <linux/rtnetlink.h> - -#include "nm-core-internal.h" -#include "platform/nm-platform.h" -#include "nm-setting-connection.h" -#include "NetworkManagerUtils.h" -#include "devices/nm-device-private.h" -#include "nm-netns.h" -#include "nm-act-request.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" -#include "ppp/nm-ppp-manager-call.h" -#include "ppp/nm-ppp-status.h" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMModem, - PROP_CONTROL_PORT, - PROP_IP_IFINDEX, - PROP_PATH, - PROP_UID, - PROP_DRIVER, - PROP_STATE, - PROP_DEVICE_ID, - PROP_SIM_ID, - PROP_IP_TYPES, - PROP_SIM_OPERATOR_ID, - PROP_OPERATOR_CODE, - PROP_APN, ); - -enum { - PPP_STATS, - PPP_FAILED, - PREPARE_RESULT, - IP4_CONFIG_RESULT, - IP6_CONFIG_RESULT, - AUTH_REQUESTED, - AUTH_RESULT, - REMOVED, - STATE_CHANGED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct _NMModemPrivate { - char *uid; - char *path; - char *driver; - char *control_port; - char *data_port; - - /* TODO: ip_iface is solely used for nm_modem_owns_port(). - * We should rework the code that it's not necessary */ - char *ip_iface; - - int ip_ifindex; - NMModemIPMethod ip4_method; - NMModemIPMethod ip6_method; - NMUtilsIPv6IfaceId iid; - NMModemState state; - NMModemState prev_state; /* revert to this state if enable/disable fails */ - char * device_id; - char * sim_id; - NMModemIPType ip_types; - char * sim_operator_id; - char * operator_code; - char * apn; - - NMPPPManager *ppp_manager; - - NMActRequest * act_request; - guint32 secrets_tries; - NMActRequestGetSecretsCallId *secrets_id; - - guint mm_ip_timeout; - - guint32 ip4_route_table; - guint32 ip4_route_metric; - guint32 ip6_route_table; - guint32 ip6_route_metric; - - /* PPP stats */ - guint32 in_bytes; - guint32 out_bytes; - - bool claimed : 1; -} NMModemPrivate; - -G_DEFINE_TYPE(NMModem, nm_modem, G_TYPE_OBJECT) - -#define NM_MODEM_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMModem, NM_IS_MODEM) - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_BUFLEN 64 -#define _NMLOG_PREFIX_NAME "modem" -#define _NMLOG_DOMAIN LOGD_MB - -static const char * -_nmlog_prefix(char *prefix, NMModem *self) -{ - const char *uuid; - int c; - - if (!self) - return ""; - - uuid = nm_modem_get_uid(self); - - if (uuid) { - char pp[_NMLOG_PREFIX_BUFLEN - 5]; - - c = g_snprintf(prefix, _NMLOG_PREFIX_BUFLEN, "[%s]", nm_strquote(pp, sizeof(pp), uuid)); - } else - c = g_snprintf(prefix, _NMLOG_PREFIX_BUFLEN, "[%p]", self); - nm_assert(c < _NMLOG_PREFIX_BUFLEN); - - return prefix; -} - -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - char _prefix[_NMLOG_PREFIX_BUFLEN]; \ - \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - _nmlog_prefix(_prefix, (self)) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static void _set_ip_ifindex(NMModem *self, int ifindex, const char *ifname); - -/*****************************************************************************/ -/* State/enabled/connected */ - -static const char *state_table[] = { - [NM_MODEM_STATE_UNKNOWN] = "unknown", - [NM_MODEM_STATE_FAILED] = "failed", - [NM_MODEM_STATE_INITIALIZING] = "initializing", - [NM_MODEM_STATE_LOCKED] = "locked", - [NM_MODEM_STATE_DISABLED] = "disabled", - [NM_MODEM_STATE_DISABLING] = "disabling", - [NM_MODEM_STATE_ENABLING] = "enabling", - [NM_MODEM_STATE_ENABLED] = "enabled", - [NM_MODEM_STATE_SEARCHING] = "searching", - [NM_MODEM_STATE_REGISTERED] = "registered", - [NM_MODEM_STATE_DISCONNECTING] = "disconnecting", - [NM_MODEM_STATE_CONNECTING] = "connecting", - [NM_MODEM_STATE_CONNECTED] = "connected", -}; - -const char * -nm_modem_state_to_string(NMModemState state) -{ - if ((gsize) state < G_N_ELEMENTS(state_table)) - return state_table[state]; - return NULL; -} - -/*****************************************************************************/ - -gboolean -nm_modem_is_claimed(NMModem *self) -{ - g_return_val_if_fail(NM_IS_MODEM(self), FALSE); - - return NM_MODEM_GET_PRIVATE(self)->claimed; -} - -NMModem * -nm_modem_claim(NMModem *self) -{ - NMModemPrivate *priv; - - g_return_val_if_fail(NM_IS_MODEM(self), NULL); - - priv = NM_MODEM_GET_PRIVATE(self); - - g_return_val_if_fail(!priv->claimed, NULL); - - priv->claimed = TRUE; - return g_object_ref(self); -} - -void -nm_modem_unclaim(NMModem *self) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - - g_return_if_fail(priv->claimed); - - /* we don't actually unclaim the instance. This instance should not be re-used - * by another owner, that is because we only claim modems as we receive them. - * There is no mechanism that somebody else would later re-use them again. - * - * // priv->claimed = FALSE; */ - - g_object_unref(self); -} - -/*****************************************************************************/ - -NMModemState -nm_modem_get_state(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->state; -} - -void -nm_modem_set_state(NMModem *self, NMModemState new_state, const char *reason) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - NMModemState old_state = priv->state; - - priv->prev_state = NM_MODEM_STATE_UNKNOWN; - - if (new_state != old_state) { - _LOGI("modem state changed, '%s' --> '%s' (reason: %s)", - nm_modem_state_to_string(old_state), - nm_modem_state_to_string(new_state), - reason ?: "none"); - - priv->state = new_state; - _notify(self, PROP_STATE); - g_signal_emit(self, signals[STATE_CHANGED], 0, (int) new_state, (int) old_state); - } -} - -void -nm_modem_set_prev_state(NMModem *self, const char *reason) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - /* Reset modem to previous state if the state hasn't already changed */ - if (priv->prev_state != NM_MODEM_STATE_UNKNOWN) - nm_modem_set_state(self, priv->prev_state, reason); -} - -void -nm_modem_set_mm_enabled(NMModem *self, gboolean enabled) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - NMModemState prev_state = priv->state; - - if (enabled && priv->state >= NM_MODEM_STATE_ENABLING) { - _LOGD("cannot enable modem: already enabled"); - return; - } - if (!enabled && priv->state <= NM_MODEM_STATE_DISABLING) { - _LOGD("cannot disable modem: already disabled"); - return; - } - - if (priv->state <= NM_MODEM_STATE_INITIALIZING) { - _LOGD("cannot enable/disable modem: initializing or failed"); - return; - } else if (priv->state == NM_MODEM_STATE_LOCKED) { - /* Don't try to enable if the modem is locked since that will fail */ - _LOGW("cannot enable/disable modem: locked"); - - /* Try to unlock the modem if it's being enabled */ - if (enabled) - g_signal_emit(self, signals[AUTH_REQUESTED], 0); - return; - } - - /* Not all modem classes support set_mm_enabled */ - if (NM_MODEM_GET_CLASS(self)->set_mm_enabled) - NM_MODEM_GET_CLASS(self)->set_mm_enabled(self, enabled); - - /* Pre-empt the state change signal */ - nm_modem_set_state(self, - enabled ? NM_MODEM_STATE_ENABLING : NM_MODEM_STATE_DISABLING, - "user preference"); - priv->prev_state = prev_state; -} - -void -nm_modem_emit_removed(NMModem *self) -{ - g_signal_emit(self, signals[REMOVED], 0); -} - -void -nm_modem_emit_prepare_result(NMModem *self, gboolean success, NMDeviceStateReason reason) -{ - nm_assert(NM_IS_MODEM(self)); - - g_signal_emit(self, signals[PREPARE_RESULT], 0, success, (guint) reason); -} - -void -nm_modem_emit_ppp_failed(NMModem *self, NMDeviceStateReason reason) -{ - nm_assert(NM_IS_MODEM(self)); - - g_signal_emit(self, signals[PPP_FAILED], 0, (guint) reason); -} - -NMModemIPType -nm_modem_get_supported_ip_types(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->ip_types; -} - -const char * -nm_modem_ip_type_to_string(NMModemIPType ip_type) -{ - switch (ip_type) { - case NM_MODEM_IP_TYPE_IPV4: - return "ipv4"; - case NM_MODEM_IP_TYPE_IPV6: - return "ipv6"; - case NM_MODEM_IP_TYPE_IPV4V6: - return "ipv4v6"; - default: - g_return_val_if_reached("unknown"); - } -} - -static GArray * -build_single_ip_type_array(NMModemIPType type) -{ - return g_array_append_val(g_array_sized_new(FALSE, FALSE, sizeof(NMModemIPType), 1), type); -} - -/** - * nm_modem_get_connection_ip_type: - * @self: the #NMModem - * @connection: the #NMConnection to determine IP type to use - * - * Given a modem and a connection, determine which #NMModemIPTypes to use - * when connecting. - * - * Returns: an array of #NMModemIpType values, in the order in which they - * should be tried. - */ -GArray * -nm_modem_get_connection_ip_type(NMModem *self, NMConnection *connection, GError **error) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - NMSettingIPConfig *s_ip4, *s_ip6; - const char * method; - gboolean ip4 = TRUE, ip6 = TRUE; - gboolean ip4_may_fail = TRUE, ip6_may_fail = TRUE; - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (s_ip4) { - method = nm_setting_ip_config_get_method(s_ip4); - if (g_strcmp0(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) - ip4 = FALSE; - ip4_may_fail = nm_setting_ip_config_get_may_fail(s_ip4); - } - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - if (s_ip6) { - method = nm_setting_ip_config_get_method(s_ip6); - if (NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) - ip6 = FALSE; - ip6_may_fail = nm_setting_ip_config_get_may_fail(s_ip6); - } - - if (ip4 && !ip6) { - if (!(priv->ip_types & NM_MODEM_IP_TYPE_IPV4)) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Connection requested IPv4 but IPv4 is " - "unsupported by the modem."); - return NULL; - } - return build_single_ip_type_array(NM_MODEM_IP_TYPE_IPV4); - } - - if (ip6 && !ip4) { - if (!(priv->ip_types & NM_MODEM_IP_TYPE_IPV6)) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Connection requested IPv6 but IPv6 is " - "unsupported by the modem."); - return NULL; - } - return build_single_ip_type_array(NM_MODEM_IP_TYPE_IPV6); - } - - if (ip4 && ip6) { - NMModemIPType type; - GArray * out; - - out = g_array_sized_new(FALSE, FALSE, sizeof(NMModemIPType), 3); - - /* Modem supports dual-stack? */ - if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6) { - type = NM_MODEM_IP_TYPE_IPV4V6; - g_array_append_val(out, type); - } - - /* If IPv6 may-fail=false, we should NOT try IPv4 as fallback */ - if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV4) && ip6_may_fail) { - type = NM_MODEM_IP_TYPE_IPV4; - g_array_append_val(out, type); - } - - /* If IPv4 may-fail=false, we should NOT try IPv6 as fallback */ - if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV6) && ip4_may_fail) { - type = NM_MODEM_IP_TYPE_IPV6; - g_array_append_val(out, type); - } - - if (out->len > 0) - return out; - - /* Error... */ - g_array_unref(out); - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Connection requested both IPv4 and IPv6 " - "but dual-stack addressing is unsupported " - "by the modem."); - return NULL; - } - - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Connection specified no IP configuration!"); - return NULL; -} - -const char * -nm_modem_get_device_id(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->device_id; -} - -const char * -nm_modem_get_sim_id(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->sim_id; -} - -const char * -nm_modem_get_sim_operator_id(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->sim_operator_id; -} - -const char * -nm_modem_get_operator_code(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->operator_code; -} - -const char * -nm_modem_get_apn(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->apn; -} - -/*****************************************************************************/ -/* IP method PPP */ - -static void -ppp_state_changed(NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) -{ - switch (status) { - case NM_PPP_STATUS_DISCONNECT: - nm_modem_emit_ppp_failed(user_data, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); - break; - case NM_PPP_STATUS_DEAD: - nm_modem_emit_ppp_failed(user_data, NM_DEVICE_STATE_REASON_PPP_FAILED); - break; - default: - break; - } -} - -static void -ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpointer user_data) -{ - NMModem *self = NM_MODEM(user_data); - - nm_assert(ifindex >= 0); - nm_assert(NM_MODEM_GET_PRIVATE(self)->ppp_manager == ppp_manager); - - if (ifindex <= 0 && iface) { - /* this might happen, if the ifname was already deleted - * and we failed to resolve ifindex. - * - * Forget about the name. */ - iface = NULL; - } - _set_ip_ifindex(self, ifindex, iface); -} - -static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) -{ - NMModem *self = NM_MODEM(user_data); - guint32 i, num; - guint32 bad_dns1 = htonl(0x0A0B0C0D); - guint32 good_dns1 = htonl(0x04020201); /* GTE nameserver */ - guint32 bad_dns2 = htonl(0x0A0B0C0E); - guint32 good_dns2 = htonl(0x04020202); /* GTE nameserver */ - gboolean dns_workaround = FALSE; - - /* Work around a PPP bug (#1732) which causes many mobile broadband - * providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers. - * Apparently fixed in ppp-2.4.5 but we've had some reports that this is - * not the case. - * - * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=2e09ef6886bbf00bc5a9a641110f801e372ffde6 - * http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=f8191bf07df374f119a07910a79217c7618f113e - */ - - num = nm_ip4_config_get_num_nameservers(config); - if (num == 2) { - gboolean found1 = FALSE, found2 = FALSE; - - for (i = 0; i < num; i++) { - guint32 ns = nm_ip4_config_get_nameserver(config, i); - - if (ns == bad_dns1) - found1 = TRUE; - else if (ns == bad_dns2) - found2 = TRUE; - } - - /* Be somewhat conservative about substitutions; the "bad" nameservers - * could actually be valid in some cases, so only substitute if ppp - * returns *only* the two bad nameservers. - */ - dns_workaround = (found1 && found2); - } - - if (!num || dns_workaround) { - _LOGW("compensating for invalid PPP-provided nameservers"); - nm_ip4_config_reset_nameservers(config); - nm_ip4_config_add_nameserver(config, good_dns1); - nm_ip4_config_add_nameserver(config, good_dns2); - } - - g_signal_emit(self, signals[IP4_CONFIG_RESULT], 0, config, NULL); -} - -static void -ppp_ip6_config(NMPPPManager * ppp_manager, - const NMUtilsIPv6IfaceId *iid, - NMIP6Config * config, - gpointer user_data) -{ - NMModem *self = NM_MODEM(user_data); - - NM_MODEM_GET_PRIVATE(self)->iid = *iid; - - nm_modem_emit_ip6_config_result(self, config, NULL); -} - -static void -ppp_stats(NMPPPManager *ppp_manager, guint i_in_bytes, guint i_out_bytes, gpointer user_data) -{ - NMModem * self = NM_MODEM(user_data); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - guint32 in_bytes = i_in_bytes; - guint32 out_bytes = i_out_bytes; - - if (priv->in_bytes != in_bytes || priv->out_bytes != out_bytes) { - priv->in_bytes = in_bytes; - priv->out_bytes = out_bytes; - g_signal_emit(self, signals[PPP_STATS], 0, (guint) in_bytes, (guint) out_bytes); - } -} - -static gboolean -port_speed_is_zero(const char *port) -{ - struct termios options; - nm_auto_close int fd = -1; - gs_free char * path = NULL; - - nm_assert(port); - - if (port[0] != '/') { - if (!port[0] || strchr(port, '/') || NM_IN_STRSET(port, ".", "..")) - return FALSE; - path = g_build_path("/sys/class/tty", port, NULL); - port = path; - } - - fd = open(port, O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC); - if (fd < 0) - return FALSE; - - memset(&options, 0, sizeof(struct termios)); - if (tcgetattr(fd, &options) != 0) - return FALSE; - - return cfgetospeed(&options) == B0; -} - -static NMActStageReturn -ppp_stage3_ip_config_start(NMModem * self, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - const char * ppp_name = NULL; - GError * error = NULL; - guint ip_timeout = 30; - guint baud_override = 0; - - g_return_val_if_fail(NM_IS_MODEM(self), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail(NM_IS_ACT_REQUEST(req), NM_ACT_STAGE_RETURN_FAILURE); - - /* If we're already running PPP don't restart it; for example, if both - * IPv4 and IPv6 are requested, IPv4 gets started first, but we use the - * same pppd for both v4 and v6. - */ - if (priv->ppp_manager) - return NM_ACT_STAGE_RETURN_POSTPONE; - - if (NM_MODEM_GET_CLASS(self)->get_user_pass) { - NMConnection *connection = nm_act_request_get_applied_connection(req); - - g_assert(connection); - if (!NM_MODEM_GET_CLASS(self)->get_user_pass(self, connection, &ppp_name, NULL)) - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (!priv->data_port) { - _LOGE("error starting PPP (no data port)"); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - /* Check if ModemManager requested a specific IP timeout to be used. If 0 reported, - * use the default one (30s) */ - if (priv->mm_ip_timeout > 0) { - _LOGI("using modem-specified IP timeout: %u seconds", priv->mm_ip_timeout); - ip_timeout = priv->mm_ip_timeout; - } - - /* Some tty drivers and modems ignore port speed, but pppd requires the - * port speed to be > 0 or it exits. If the port speed is 0 pass an - * explicit speed to pppd to prevent the exit. - * https://bugzilla.redhat.com/show_bug.cgi?id=1281731 - */ - if (port_speed_is_zero(priv->data_port)) - baud_override = 57600; - - priv->ppp_manager = nm_ppp_manager_create(priv->data_port, &error); - - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } - - if (!priv->ppp_manager - || !nm_ppp_manager_start(priv->ppp_manager, - req, - ppp_name, - ip_timeout, - baud_override, - &error)) { - _LOGE("error starting PPP: %s", error->message); - g_error_free(error); - g_clear_object(&priv->ppp_manager); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, - G_CALLBACK(ppp_state_changed), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK(ppp_ifindex_set), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP6_CONFIG, - G_CALLBACK(ppp_ip6_config), - self); - g_signal_connect(priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATS, G_CALLBACK(ppp_stats), self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -NMActStageReturn -nm_modem_stage3_ip4_config_start(NMModem * self, - NMDevice * device, - NMDeviceClass * device_class, - NMDeviceStateReason *out_failure_reason) -{ - NMModemPrivate * priv; - NMActRequest * req; - NMConnection * connection; - const char * method; - NMActStageReturn ret; - - _LOGD("ip4_config_start"); - - g_return_val_if_fail(NM_IS_MODEM(self), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail(NM_IS_DEVICE(device), NM_ACT_STAGE_RETURN_FAILURE); - g_return_val_if_fail(NM_IS_DEVICE_CLASS(device_class), NM_ACT_STAGE_RETURN_FAILURE); - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - connection = nm_act_request_get_applied_connection(req); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - nm_modem_set_route_parameters_from_device(self, device); - - method = nm_utils_get_ip_config_method(connection, AF_INET); - - /* Only Disabled and Auto methods make sense for WWAN */ - if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - return NM_ACT_STAGE_RETURN_SUCCESS; - - if (!nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - _LOGE("unhandled WWAN IPv4 method '%s'; will fail", method); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - priv = NM_MODEM_GET_PRIVATE(self); - switch (priv->ip4_method) { - case NM_MODEM_IP_METHOD_PPP: - ret = ppp_stage3_ip_config_start(self, req, out_failure_reason); - break; - case NM_MODEM_IP_METHOD_STATIC: - _LOGD("MODEM_IP_METHOD_STATIC"); - ret = - NM_MODEM_GET_CLASS(self)->static_stage3_ip4_config_start(self, req, out_failure_reason); - break; - case NM_MODEM_IP_METHOD_AUTO: - _LOGD("MODEM_IP_METHOD_AUTO"); - ret = device_class->act_stage3_ip_config_start(device, AF_INET, NULL, out_failure_reason); - break; - default: - _LOGI("IPv4 configuration disabled"); - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - break; - } - - return ret; -} - -void -nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device, NMIP4Config *config) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(modem); - - /* If the modem has an ethernet-type data interface (ie, not PPP and thus - * not point-to-point) and IP config has a /32 prefix, then we assume that - * ARP will be pointless and we turn it off. - */ - if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC - || priv->ip4_method == NM_MODEM_IP_METHOD_AUTO) { - const NMPlatformIP4Address *address = nm_ip4_config_get_first_address(config); - - g_assert(address); - if (address->plen == 32) - nm_platform_link_set_noarp(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device)); - } -} - -/*****************************************************************************/ - -void -nm_modem_emit_ip6_config_result(NMModem *self, NMIP6Config *config, GError *error) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *addr; - gboolean do_slaac = TRUE; - - if (error) { - g_signal_emit(self, signals[IP6_CONFIG_RESULT], 0, NULL, FALSE, error); - return; - } - - if (config) { - /* If the IPv6 configuration only included a Link-Local address, then - * we have to run SLAAC to get the full IPv6 configuration. - */ - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, config, &addr) { - if (IN6_IS_ADDR_LINKLOCAL(&addr->address)) { - if (!priv->iid.id) - priv->iid.id = ((guint64 *) (&addr->address.s6_addr))[1]; - } else - do_slaac = FALSE; - } - } - g_assert(config || do_slaac); - - g_signal_emit(self, signals[IP6_CONFIG_RESULT], 0, config, do_slaac, NULL); -} - -static NMActStageReturn -stage3_ip6_config_request(NMModem *self, NMDeviceStateReason *out_failure_reason) -{ - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return NM_ACT_STAGE_RETURN_FAILURE; -} - -NMActStageReturn -nm_modem_stage3_ip6_config_start(NMModem * self, - NMDevice * device, - NMDeviceStateReason *out_failure_reason) -{ - NMModemPrivate * priv; - NMActRequest * req; - NMActStageReturn ret; - NMConnection * connection; - const char * method; - - g_return_val_if_fail(NM_IS_MODEM(self), NM_ACT_STAGE_RETURN_FAILURE); - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - connection = nm_act_request_get_applied_connection(req); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - nm_modem_set_route_parameters_from_device(self, device); - - method = nm_utils_get_ip_config_method(connection, AF_INET6); - - /* Only Ignore, Disabled and Auto methods make sense for WWAN */ - if (NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) - return NM_ACT_STAGE_RETURN_IP_DONE; - - if (!nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - _LOGW("unhandled WWAN IPv6 method '%s'; will fail", method); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - priv = NM_MODEM_GET_PRIVATE(self); - switch (priv->ip6_method) { - case NM_MODEM_IP_METHOD_PPP: - ret = ppp_stage3_ip_config_start(self, req, out_failure_reason); - break; - case NM_MODEM_IP_METHOD_STATIC: - case NM_MODEM_IP_METHOD_AUTO: - /* Both static and DHCP/Auto retrieve a base IP config from the modem - * which in the static case is the full config, and the DHCP/Auto case - * is just the IPv6LL address to use for SLAAC. - */ - ret = NM_MODEM_GET_CLASS(self)->stage3_ip6_config_request(self, out_failure_reason); - break; - default: - _LOGI("IPv6 configuration disabled"); - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - break; - } - - return ret; -} - -guint32 -nm_modem_get_configured_mtu(NMDevice *self, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - NMConnection *connection; - NMSetting * setting; - gint64 mtu_default; - guint mtu = 0; - const char * property_name; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(out_source); - - connection = nm_device_get_applied_connection(self); - if (!connection) - g_return_val_if_reached(0); - - setting = (NMSetting *) nm_connection_get_setting_gsm(connection); - if (!setting) - setting = (NMSetting *) nm_connection_get_setting_cdma(connection); - - if (setting) { - g_object_get(setting, "mtu", &mtu, NULL); - if (mtu) { - *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; - return mtu; - } - - property_name = NM_IS_SETTING_GSM(setting) ? "gsm.mtu" : "cdma.mtu"; - mtu_default = - nm_device_get_configured_mtu_from_connection_default(self, property_name, G_MAXUINT32); - if (mtu_default >= 0) { - *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; - return (guint32) mtu_default; - } - } - - *out_source = NM_DEVICE_MTU_SOURCE_NONE; - return 0; -} - -/*****************************************************************************/ - -static void -cancel_get_secrets(NMModem *self) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - if (priv->secrets_id) - nm_act_request_cancel_secrets(priv->act_request, priv->secrets_id); -} - -static void -modem_secrets_cb(NMActRequest * req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * connection, - GError * error, - gpointer user_data) -{ - NMModem * self = NM_MODEM(user_data); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - g_return_if_fail(call_id == priv->secrets_id); - - priv->secrets_id = NULL; - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED) - || g_error_matches(error, NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_NO_SECRETS)) - return; - - if (error) - _LOGW("modem-secrets: %s", error->message); - - g_signal_emit(self, signals[AUTH_RESULT], 0, error); -} - -void -nm_modem_get_secrets(NMModem * self, - const char *setting_name, - gboolean request_new, - const char *hint) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - - cancel_get_secrets(self); - - if (request_new) - flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - priv->secrets_id = nm_act_request_get_secrets(priv->act_request, - FALSE, - setting_name, - flags, - NM_MAKE_STRV(hint), - modem_secrets_cb, - self); - g_return_if_fail(priv->secrets_id); - g_signal_emit(self, signals[AUTH_REQUESTED], 0); -} - -/*****************************************************************************/ - -static NMActStageReturn -modem_act_stage1_prepare(NMModem * modem, - NMConnection * connection, - NMDeviceStateReason *out_failure_reason) -{ - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_UNKNOWN); - return NM_ACT_STAGE_RETURN_FAILURE; -} - -NMActStageReturn -nm_modem_act_stage1_prepare(NMModem * self, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - gs_unref_ptrarray GPtrArray *hints = NULL; - const char * setting_name = NULL; - NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - NMConnection * connection; - - g_return_val_if_fail(NM_IS_ACT_REQUEST(req), NM_ACT_STAGE_RETURN_FAILURE); - - if (priv->act_request) - g_object_unref(priv->act_request); - priv->act_request = g_object_ref(req); - - connection = nm_act_request_get_applied_connection(req); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - setting_name = nm_connection_need_secrets(connection, &hints); - if (!setting_name) { - nm_assert(!hints); - return NM_MODEM_GET_CLASS(self)->modem_act_stage1_prepare(self, - connection, - out_failure_reason); - } - - /* Secrets required... */ - if (priv->secrets_tries++) - flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - - if (hints) - g_ptr_array_add(hints, NULL); - - priv->secrets_id = nm_act_request_get_secrets(req, - FALSE, - setting_name, - flags, - hints ? (const char *const *) hints->pdata : NULL, - modem_secrets_cb, - self); - g_return_val_if_fail(priv->secrets_id, NM_ACT_STAGE_RETURN_FAILURE); - g_signal_emit(self, signals[AUTH_REQUESTED], 0); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -void -nm_modem_act_stage2_config(NMModem *self) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - /* Clear secrets tries counter since secrets were successfully used - * already if we get here. - */ - priv->secrets_tries = 0; -} - -/*****************************************************************************/ - -gboolean -nm_modem_check_connection_compatible(NMModem *self, NMConnection *connection, GError **error) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - if (nm_streq0(nm_connection_get_connection_type(connection), NM_SETTING_GSM_SETTING_NAME)) { - NMSettingGsm *s_gsm; - const char * str; - - s_gsm = _nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, error); - if (!s_gsm) - return FALSE; - - str = nm_setting_gsm_get_device_id(s_gsm); - if (str) { - if (!priv->device_id) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "GSM profile has device-id, device does not"); - return FALSE; - } - if (!nm_streq(str, priv->device_id)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has differing device-id than GSM profile"); - return FALSE; - } - } - - /* SIM properties may not be available before the SIM is unlocked, so - * to ensure that autoconnect works, the connection's SIM properties - * are only compared if present on the device. - */ - - if (priv->sim_id && (str = nm_setting_gsm_get_sim_id(s_gsm))) { - if (!nm_streq(str, priv->sim_id)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has differing sim-id than GSM profile"); - return FALSE; - } - } - - if (priv->sim_operator_id && (str = nm_setting_gsm_get_sim_operator_id(s_gsm))) { - if (!nm_streq(str, priv->sim_operator_id)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has differing sim-operator-id than GSM profile"); - return FALSE; - } - } - } - - return NM_MODEM_GET_CLASS(self)->check_connection_compatible_with_modem(self, - connection, - error); -} - -/*****************************************************************************/ - -gboolean -nm_modem_complete_connection(NMModem * self, - const char * iface, - NMConnection * connection, - NMConnection *const *existing_connections, - GError ** error) -{ - NMModemClass *klass; - - klass = NM_MODEM_GET_CLASS(self); - if (!klass->complete_connection) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "Modem class %s had no complete_connection method", - G_OBJECT_TYPE_NAME(self)); - return FALSE; - } - - return klass->complete_connection(self, iface, connection, existing_connections, error); -} - -/*****************************************************************************/ - -static void -deactivate_cleanup(NMModem *self, NMDevice *device, gboolean stop_ppp_manager) -{ - NMModemPrivate *priv; - int ifindex; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - - priv->secrets_tries = 0; - - if (priv->act_request) { - cancel_get_secrets(self); - g_object_unref(priv->act_request); - priv->act_request = NULL; - } - - priv->in_bytes = priv->out_bytes = 0; - - if (priv->ppp_manager) { - g_signal_handlers_disconnect_by_data(priv->ppp_manager, self); - if (stop_ppp_manager) - nm_ppp_manager_stop(priv->ppp_manager, NULL, NULL, NULL); - g_clear_object(&priv->ppp_manager); - } - - if (device) { - g_return_if_fail(NM_IS_DEVICE(device)); - - if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC - || priv->ip4_method == NM_MODEM_IP_METHOD_AUTO - || priv->ip6_method == NM_MODEM_IP_METHOD_STATIC - || priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) { - ifindex = nm_device_get_ip_ifindex(device); - if (ifindex > 0) { - NMPlatform *platform = nm_device_get_platform(device); - - nm_platform_ip_route_flush(platform, AF_UNSPEC, ifindex); - nm_platform_ip_address_flush(platform, AF_UNSPEC, ifindex); - nm_platform_link_set_down(platform, ifindex); - } - } - } - - nm_clear_g_free(&priv->data_port); - priv->mm_ip_timeout = 0; - priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; - priv->ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - _set_ip_ifindex(self, -1, NULL); -} - -/*****************************************************************************/ - -typedef struct { - NMModem * self; - NMDevice * device; - GCancellable * cancellable; - NMModemDeactivateCallback callback; - gpointer callback_user_data; -} DeactivateContext; - -static void -deactivate_context_complete(DeactivateContext *ctx, GError *error) -{ - NMModem *self = ctx->self; - - _LOGD("modem deactivation finished %s%s%s", - NM_PRINT_FMT_QUOTED(error, "with failure: ", error->message, "", "successfully")); - - if (ctx->callback) - ctx->callback(ctx->self, error, ctx->callback_user_data); - nm_g_object_unref(ctx->cancellable); - g_object_unref(ctx->device); - g_object_unref(ctx->self); - g_slice_free(DeactivateContext, ctx); -} - -static void -_deactivate_call_disconnect_cb(NMModem *self, GError *error, gpointer user_data) -{ - deactivate_context_complete(user_data, error); -} - -static void -_deactivate_call_disconnect(DeactivateContext *ctx) -{ - NM_MODEM_GET_CLASS(ctx->self)->disconnect(ctx->self, - FALSE, - ctx->cancellable, - _deactivate_call_disconnect_cb, - ctx); -} - -static void -_deactivate_ppp_manager_stop_cb(NMPPPManager * ppp_manager, - NMPPPManagerStopHandle *handle, - gboolean was_cancelled, - gpointer user_data) -{ - DeactivateContext *ctx = user_data; - - g_object_unref(ppp_manager); - - if (was_cancelled) { - gs_free_error GError *error = NULL; - - if (!g_cancellable_set_error_if_cancelled(ctx->cancellable, &error)) - nm_assert_not_reached(); - deactivate_context_complete(ctx, error); - return; - } - - nm_assert(!g_cancellable_is_cancelled(ctx->cancellable)); - _deactivate_call_disconnect(ctx); -} - -void -nm_modem_deactivate_async(NMModem * self, - NMDevice * device, - GCancellable * cancellable, - NMModemDeactivateCallback callback, - gpointer user_data) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - DeactivateContext *ctx; - NMPPPManager * ppp_manager; - - g_return_if_fail(NM_IS_MODEM(self)); - g_return_if_fail(NM_IS_DEVICE(device)); - g_return_if_fail(G_IS_CANCELLABLE(cancellable)); - - ctx = g_slice_new(DeactivateContext); - ctx->self = g_object_ref(self); - ctx->device = g_object_ref(device); - ctx->cancellable = g_object_ref(cancellable); - ctx->callback = callback; - ctx->callback_user_data = user_data; - - ppp_manager = nm_g_object_ref(priv->ppp_manager); - - NM_MODEM_GET_CLASS(self)->deactivate_cleanup(self, ctx->device, FALSE); - - if (ppp_manager) { - /* If we have a PPP manager, stop it. - * - * Pass on the reference in @ppp_manager. */ - nm_ppp_manager_stop(ppp_manager, ctx->cancellable, _deactivate_ppp_manager_stop_cb, ctx); - return; - } - - _deactivate_call_disconnect(ctx); -} - -/*****************************************************************************/ - -void -nm_modem_deactivate(NMModem *self, NMDevice *device) -{ - /* First cleanup */ - NM_MODEM_GET_CLASS(self)->deactivate_cleanup(self, device, TRUE); - /* Then disconnect without waiting */ - NM_MODEM_GET_CLASS(self)->disconnect(self, FALSE, NULL, NULL, NULL); -} - -/*****************************************************************************/ - -void -nm_modem_device_state_changed(NMModem *self, NMDeviceState new_state, NMDeviceState old_state) -{ - gboolean was_connected = FALSE, warn = TRUE; - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - if (old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_DEACTIVATING) - was_connected = TRUE; - - priv = NM_MODEM_GET_PRIVATE(self); - - /* Make sure we don't leave the serial device open */ - switch (new_state) { - case NM_DEVICE_STATE_UNMANAGED: - case NM_DEVICE_STATE_UNAVAILABLE: - case NM_DEVICE_STATE_FAILED: - case NM_DEVICE_STATE_DISCONNECTED: - if (priv->act_request) { - cancel_get_secrets(self); - g_object_unref(priv->act_request); - priv->act_request = NULL; - } - - if (was_connected) { - /* Don't bother warning on FAILED since the modem is already gone */ - if (new_state == NM_DEVICE_STATE_FAILED || new_state == NM_DEVICE_STATE_DISCONNECTED) - warn = FALSE; - /* First cleanup */ - NM_MODEM_GET_CLASS(self)->deactivate_cleanup(self, NULL, TRUE); - NM_MODEM_GET_CLASS(self)->disconnect(self, warn, NULL, NULL, NULL); - } - break; - default: - break; - } -} - -/*****************************************************************************/ - -const char * -nm_modem_get_uid(NMModem *self) -{ - g_return_val_if_fail(NM_IS_MODEM(self), NULL); - - return NM_MODEM_GET_PRIVATE(self)->uid; -} - -const char * -nm_modem_get_path(NMModem *self) -{ - g_return_val_if_fail(NM_IS_MODEM(self), NULL); - - return NM_MODEM_GET_PRIVATE(self)->path; -} - -const char * -nm_modem_get_driver(NMModem *self) -{ - g_return_val_if_fail(NM_IS_MODEM(self), NULL); - - return NM_MODEM_GET_PRIVATE(self)->driver; -} - -const char * -nm_modem_get_control_port(NMModem *self) -{ - g_return_val_if_fail(NM_IS_MODEM(self), NULL); - - return NM_MODEM_GET_PRIVATE(self)->control_port; -} - -int -nm_modem_get_ip_ifindex(NMModem *self) -{ - NMModemPrivate *priv; - - g_return_val_if_fail(NM_IS_MODEM(self), 0); - - priv = NM_MODEM_GET_PRIVATE(self); - - /* internally we track an unset ip_ifindex as -1. - * For the caller of nm_modem_get_ip_ifindex(), this - * shall be zero too. */ - return priv->ip_ifindex != -1 ? priv->ip_ifindex : 0; -} - -static void -_set_ip_ifindex(NMModem *self, int ifindex, const char *ifname) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - nm_assert(ifindex >= -1); - nm_assert((ifindex > 0) == !!ifname); - - if (!nm_streq0(priv->ip_iface, ifname)) { - g_free(priv->ip_iface); - priv->ip_iface = g_strdup(ifname); - } - - if (priv->ip_ifindex != ifindex) { - priv->ip_ifindex = ifindex; - _notify(self, PROP_IP_IFINDEX); - } -} - -gboolean -nm_modem_set_data_port(NMModem * self, - NMPlatform * platform, - const char * data_port, - NMModemIPMethod ip4_method, - NMModemIPMethod ip6_method, - guint timeout, - GError ** error) -{ - NMModemPrivate *priv; - gboolean is_ppp; - int ifindex = -1; - - g_return_val_if_fail(NM_IS_MODEM(self), FALSE); - g_return_val_if_fail(NM_IS_PLATFORM(platform), FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - - priv = NM_MODEM_GET_PRIVATE(self); - - if (priv->ppp_manager || priv->data_port || priv->ip_ifindex != -1) { - g_set_error_literal(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "cannot set data port in activated state"); - /* this really shouldn't happen. Assert. */ - g_return_val_if_reached(FALSE); - } - - if (!data_port) { - g_set_error_literal(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "missing data port"); - return FALSE; - } - - is_ppp = (ip4_method == NM_MODEM_IP_METHOD_PPP) || (ip6_method == NM_MODEM_IP_METHOD_PPP); - if (is_ppp) { - if (!NM_IN_SET(ip4_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_PPP) - || !NM_IN_SET(ip6_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_PPP)) { - g_set_error_literal(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "conflicting ip methods"); - return FALSE; - } - } else if (!NM_IN_SET(ip4_method, - NM_MODEM_IP_METHOD_UNKNOWN, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_AUTO) - || !NM_IN_SET(ip6_method, - NM_MODEM_IP_METHOD_UNKNOWN, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_AUTO) - || (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN - && ip6_method == NM_MODEM_IP_METHOD_UNKNOWN)) { - g_set_error_literal(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "invalid ip methods"); - return FALSE; - } - - if (!is_ppp) { - ifindex = nm_platform_if_nametoindex(platform, data_port); - if (ifindex <= 0) { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "cannot find network interface %s", - data_port); - return FALSE; - } - if (!nm_platform_process_events_ensure_link(platform, ifindex, data_port)) { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "cannot find network interface %s in platform cache", - data_port); - return FALSE; - } - } - - priv->mm_ip_timeout = timeout; - priv->ip4_method = ip4_method; - priv->ip6_method = ip6_method; - if (is_ppp) { - priv->data_port = g_strdup(data_port); - _set_ip_ifindex(self, -1, NULL); - } else { - priv->data_port = NULL; - _set_ip_ifindex(self, ifindex, data_port); - } - return TRUE; -} - -gboolean -nm_modem_owns_port(NMModem *self, const char *iface) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - g_return_val_if_fail(iface != NULL, FALSE); - - if (NM_MODEM_GET_CLASS(self)->owns_port) - return NM_MODEM_GET_CLASS(self)->owns_port(self, iface); - - return NM_IN_STRSET(iface, priv->ip_iface, priv->data_port, priv->control_port); -} - -gboolean -nm_modem_get_iid(NMModem *self, NMUtilsIPv6IfaceId *out_iid) -{ - g_return_val_if_fail(NM_IS_MODEM(self), FALSE); - - *out_iid = NM_MODEM_GET_PRIVATE(self)->iid; - return TRUE; -} - -/*****************************************************************************/ - -void -nm_modem_get_route_parameters(NMModem *self, - guint32 *out_ip4_route_table, - guint32 *out_ip4_route_metric, - guint32 *out_ip6_route_table, - guint32 *out_ip6_route_metric) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - NM_SET_OUT(out_ip4_route_table, priv->ip4_route_table); - NM_SET_OUT(out_ip4_route_metric, priv->ip4_route_metric); - NM_SET_OUT(out_ip6_route_table, priv->ip6_route_table); - NM_SET_OUT(out_ip6_route_metric, priv->ip6_route_metric); -} - -void -nm_modem_set_route_parameters(NMModem *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - if (priv->ip4_route_table != ip4_route_table || priv->ip4_route_metric != ip4_route_metric - || priv->ip6_route_table != ip6_route_table || priv->ip6_route_metric != ip6_route_metric) { - priv->ip4_route_table = ip4_route_table; - priv->ip4_route_metric = ip4_route_metric; - priv->ip6_route_table = ip6_route_table; - priv->ip6_route_metric = ip6_route_metric; - - _LOGT("route-parameters: table-v4: %u, metric-v4: %u, table-v6: %u, metric-v6: %u", - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } - - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } -} - -void -nm_modem_set_route_parameters_from_device(NMModem *self, NMDevice *device) -{ - g_return_if_fail(NM_IS_DEVICE(device)); - - nm_modem_set_route_parameters(self, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); -} - -/*****************************************************************************/ - -void -nm_modem_get_capabilities(NMModem * self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps) -{ - g_return_if_fail(NM_IS_MODEM(self)); - - NM_MODEM_GET_CLASS(self)->get_capabilities(self, modem_caps, current_caps); -} - -/*****************************************************************************/ - -void -_nm_modem_set_operator_code(NMModem *self, const char *operator_code) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - if (g_strcmp0(priv->operator_code, operator_code) != 0) { - g_free(priv->operator_code); - priv->operator_code = g_strdup(operator_code); - _notify(self, PROP_OPERATOR_CODE); - } -} - -void -_nm_modem_set_apn(NMModem *self, const char *apn) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - if (g_strcmp0(priv->apn, apn) != 0) { - g_free(priv->apn); - priv->apn = g_strdup(apn); - _notify(self, PROP_APN); - } -} - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMModem * self = NM_MODEM(object); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_PATH: - g_value_set_string(value, priv->path); - break; - case PROP_DRIVER: - g_value_set_string(value, priv->driver); - break; - case PROP_CONTROL_PORT: - g_value_set_string(value, priv->control_port); - break; - case PROP_IP_IFINDEX: - g_value_set_int(value, nm_modem_get_ip_ifindex(self)); - break; - case PROP_UID: - g_value_set_string(value, priv->uid); - break; - case PROP_STATE: - g_value_set_int(value, priv->state); - break; - case PROP_DEVICE_ID: - g_value_set_string(value, priv->device_id); - break; - case PROP_SIM_ID: - g_value_set_string(value, priv->sim_id); - break; - case PROP_IP_TYPES: - g_value_set_uint(value, priv->ip_types); - break; - case PROP_SIM_OPERATOR_ID: - g_value_set_string(value, priv->sim_operator_id); - break; - case PROP_OPERATOR_CODE: - g_value_set_string(value, priv->operator_code); - break; - case PROP_APN: - g_value_set_string(value, priv->apn); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(object); - const char * s; - - switch (prop_id) { - case PROP_PATH: - /* construct-only */ - priv->path = g_value_dup_string(value); - g_return_if_fail(priv->path); - break; - case PROP_DRIVER: - /* construct-only */ - priv->driver = g_value_dup_string(value); - break; - case PROP_CONTROL_PORT: - /* construct-only */ - priv->control_port = g_value_dup_string(value); - break; - case PROP_UID: - /* construct-only */ - priv->uid = g_value_dup_string(value); - break; - case PROP_STATE: - /* construct-only */ - priv->state = g_value_get_int(value); - break; - case PROP_DEVICE_ID: - /* construct-only */ - priv->device_id = g_value_dup_string(value); - break; - case PROP_SIM_ID: - g_free(priv->sim_id); - priv->sim_id = g_value_dup_string(value); - break; - case PROP_IP_TYPES: - priv->ip_types = g_value_get_uint(value); - break; - case PROP_SIM_OPERATOR_ID: - nm_clear_g_free(&priv->sim_operator_id); - s = g_value_get_string(value); - if (s && s[0]) - priv->sim_operator_id = g_strdup(s); - break; - case PROP_OPERATOR_CODE: - /* construct-only */ - priv->operator_code = g_value_dup_string(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_modem_init(NMModem *self) -{ - NMModemPrivate *priv; - - self->_priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_MODEM, NMModemPrivate); - priv = self->_priv; - - priv->ip_ifindex = -1; - priv->ip4_route_table = RT_TABLE_MAIN; - priv->ip4_route_metric = 700; - priv->ip6_route_table = RT_TABLE_MAIN; - priv->ip6_route_metric = 700; -} - -static void -constructed(GObject *object) -{ - NMModemPrivate *priv; - - G_OBJECT_CLASS(nm_modem_parent_class)->constructed(object); - - priv = NM_MODEM_GET_PRIVATE(NM_MODEM(object)); - - g_return_if_fail(priv->control_port); -} - -/*****************************************************************************/ - -static void -dispose(GObject *object) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(object); - - g_clear_object(&priv->act_request); - - G_OBJECT_CLASS(nm_modem_parent_class)->dispose(object); -} - -static void -finalize(GObject *object) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(object); - - g_free(priv->uid); - g_free(priv->path); - g_free(priv->driver); - g_free(priv->control_port); - g_free(priv->data_port); - g_free(priv->ip_iface); - g_free(priv->device_id); - g_free(priv->sim_id); - g_free(priv->sim_operator_id); - g_free(priv->operator_code); - g_free(priv->apn); - - G_OBJECT_CLASS(nm_modem_parent_class)->finalize(object); -} - -static void -nm_modem_class_init(NMModemClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - g_type_class_add_private(object_class, sizeof(NMModemPrivate)); - - object_class->constructed = constructed; - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - klass->modem_act_stage1_prepare = modem_act_stage1_prepare; - klass->stage3_ip6_config_request = stage3_ip6_config_request; - klass->deactivate_cleanup = deactivate_cleanup; - - obj_properties[PROP_UID] = - g_param_spec_string(NM_MODEM_UID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_PATH] = - g_param_spec_string(NM_MODEM_PATH, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_DRIVER] = - g_param_spec_string(NM_MODEM_DRIVER, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_CONTROL_PORT] = - g_param_spec_string(NM_MODEM_CONTROL_PORT, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IP_IFINDEX] = g_param_spec_int(NM_MODEM_IP_IFINDEX, - "", - "", - 0, - G_MAXINT, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_STATE] = - g_param_spec_int(NM_MODEM_STATE, - "", - "", - NM_MODEM_STATE_UNKNOWN, - _NM_MODEM_STATE_LAST, - NM_MODEM_STATE_UNKNOWN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_DEVICE_ID] = - g_param_spec_string(NM_MODEM_DEVICE_ID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SIM_ID] = - g_param_spec_string(NM_MODEM_SIM_ID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IP_TYPES] = - g_param_spec_uint(NM_MODEM_IP_TYPES, - "IP Types", - "Supported IP types", - 0, - G_MAXUINT32, - NM_MODEM_IP_TYPE_IPV4, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SIM_OPERATOR_ID] = - g_param_spec_string(NM_MODEM_SIM_OPERATOR_ID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_OPERATOR_CODE] = - g_param_spec_string(NM_MODEM_OPERATOR_CODE, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_APN] = - g_param_spec_string(NM_MODEM_APN, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[PPP_STATS] = g_signal_new(NM_MODEM_PPP_STATS, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_UINT /*guint32 in_bytes*/, - G_TYPE_UINT /*guint32 out_bytes*/); - - signals[PPP_FAILED] = g_signal_new(NM_MODEM_PPP_FAILED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_UINT); - - signals[IP4_CONFIG_RESULT] = g_signal_new(NM_MODEM_IP4_CONFIG_RESULT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_POINTER); - - /** - * NMModem::ip6-config-result: - * @modem: the #NMModem on which the signal is emitted - * @config: the #NMIP6Config to apply to the modem's data port - * @do_slaac: %TRUE if IPv6 SLAAC should be started - * @error: a #GError if any error occurred during IP configuration - * - * This signal is emitted when IPv6 configuration has completed or failed. - * If @error is set the configuration failed. If @config is set, then - * the details should be applied to the data port before any further - * configuration (like SLAAC) is done. @do_slaac indicates whether SLAAC - * should be started after applying @config to the data port. - */ - signals[IP6_CONFIG_RESULT] = g_signal_new(NM_MODEM_IP6_CONFIG_RESULT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_OBJECT, - G_TYPE_BOOLEAN, - G_TYPE_POINTER); - - signals[PREPARE_RESULT] = g_signal_new(NM_MODEM_PREPARE_RESULT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_BOOLEAN, - G_TYPE_UINT); - - signals[AUTH_REQUESTED] = g_signal_new(NM_MODEM_AUTH_REQUESTED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); - - signals[AUTH_RESULT] = g_signal_new(NM_MODEM_AUTH_RESULT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - signals[REMOVED] = g_signal_new(NM_MODEM_REMOVED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); - - signals[STATE_CHANGED] = g_signal_new(NM_MODEM_STATE_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_INT, - G_TYPE_INT); -} diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h deleted file mode 100644 index 4b275cf7..00000000 --- a/src/devices/wwan/nm-modem.h +++ /dev/null @@ -1,269 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2011 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_MODEM_H__ -#define __NETWORKMANAGER_MODEM_H__ - -#include "ppp/nm-ppp-manager.h" -#include "devices/nm-device.h" - -#define NM_TYPE_MODEM (nm_modem_get_type()) -#define NM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM, NMModem)) -#define NM_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM, NMModemClass)) -#define NM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM)) -#define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM)) -#define NM_MODEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MODEM, NMModemClass)) - -/* Properties */ -#define NM_MODEM_UID "uid" -#define NM_MODEM_PATH "path" -#define NM_MODEM_DRIVER "driver" -#define NM_MODEM_CONTROL_PORT "control-port" -#define NM_MODEM_IP_IFINDEX "ip-ifindex" -#define NM_MODEM_STATE "state" -#define NM_MODEM_DEVICE_ID "device-id" -#define NM_MODEM_SIM_ID "sim-id" -#define NM_MODEM_IP_TYPES "ip-types" /* Supported IP types */ -#define NM_MODEM_SIM_OPERATOR_ID "sim-operator-id" -#define NM_MODEM_OPERATOR_CODE "operator-code" -#define NM_MODEM_APN "apn" - -/* Signals */ -#define NM_MODEM_PPP_STATS "ppp-stats" -#define NM_MODEM_PPP_FAILED "ppp-failed" -#define NM_MODEM_PREPARE_RESULT "prepare-result" -#define NM_MODEM_IP4_CONFIG_RESULT "ip4-config-result" -#define NM_MODEM_IP6_CONFIG_RESULT "ip6-config-result" -#define NM_MODEM_AUTH_REQUESTED "auth-requested" -#define NM_MODEM_AUTH_RESULT "auth-result" -#define NM_MODEM_REMOVED "removed" -#define NM_MODEM_STATE_CHANGED "state-changed" - -typedef enum { - NM_MODEM_IP_METHOD_UNKNOWN = 0, - NM_MODEM_IP_METHOD_PPP, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_AUTO, /* DHCP and/or SLAAC */ -} NMModemIPMethod; - -/** - * NMModemIPType: - * @NM_MODEM_IP_TYPE_UNKNOWN: unknown or no IP support - * @NM_MODEM_IP_TYPE_IPV4: IPv4-only bearers are supported - * @NM_MODEM_IP_TYPE_IPV6: IPv6-only bearers are supported - * @NM_MODEM_IP_TYPE_IPV4V6: dual-stack IPv4 + IPv6 bearers are supported - * - * Indicates what IP protocols the modem supports for an IP bearer. Any - * combination of flags is possible. For example, (%NM_MODEM_IP_TYPE_IPV4 | - * %NM_MODEM_IP_TYPE_IPV6) indicates that the modem supports IPv4 and IPv6 - * but not simultaneously on the same bearer. - */ -typedef enum { - NM_MODEM_IP_TYPE_UNKNOWN = 0x0, - NM_MODEM_IP_TYPE_IPV4 = 0x1, - NM_MODEM_IP_TYPE_IPV6 = 0x2, - NM_MODEM_IP_TYPE_IPV4V6 = 0x4 -} NMModemIPType; - -typedef enum { /*< underscore_name=nm_modem_state >*/ - NM_MODEM_STATE_UNKNOWN = 0, - NM_MODEM_STATE_FAILED = 1, - NM_MODEM_STATE_INITIALIZING = 2, - NM_MODEM_STATE_LOCKED = 3, - NM_MODEM_STATE_DISABLED = 4, - NM_MODEM_STATE_DISABLING = 5, - NM_MODEM_STATE_ENABLING = 6, - NM_MODEM_STATE_ENABLED = 7, - NM_MODEM_STATE_SEARCHING = 8, - NM_MODEM_STATE_REGISTERED = 9, - NM_MODEM_STATE_DISCONNECTING = 10, - NM_MODEM_STATE_CONNECTING = 11, - NM_MODEM_STATE_CONNECTED = 12, - - _NM_MODEM_STATE_LAST0, - _NM_MODEM_STATE_LAST = _NM_MODEM_STATE_LAST0 - 1, -} NMModemState; - -struct _NMModemPrivate; - -struct _NMModem { - GObject parent; - struct _NMModemPrivate *_priv; -}; - -typedef struct _NMModem NMModem; - -typedef void (*_NMModemDisconnectCallback)(NMModem *modem, GError *error, gpointer user_data); - -typedef struct { - GObjectClass parent; - - void (*get_capabilities)(NMModem * self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps); - - gboolean (*get_user_pass)(NMModem * modem, - NMConnection *connection, - const char ** user, - const char ** pass); - - gboolean (*check_connection_compatible_with_modem)(NMModem * modem, - NMConnection *connection, - GError ** error); - - gboolean (*complete_connection)(NMModem * modem, - const char * iface, - NMConnection * connection, - NMConnection *const *existing_connections, - GError ** error); - - NMActStageReturn (*modem_act_stage1_prepare)(NMModem * modem, - NMConnection * connection, - NMDeviceStateReason *out_failure_reason); - - NMActStageReturn (*static_stage3_ip4_config_start)(NMModem * self, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason); - - /* Request the IP6 config; when the config returns the modem - * subclass should emit the ip6_config_result signal. - */ - NMActStageReturn (*stage3_ip6_config_request)(NMModem * self, - NMDeviceStateReason *out_failure_reason); - - void (*set_mm_enabled)(NMModem *self, gboolean enabled); - - void (*disconnect)(NMModem * self, - gboolean warn, - GCancellable * cancellable, - _NMModemDisconnectCallback callback, - gpointer user_data); - - void (*deactivate_cleanup)(NMModem *self, NMDevice *device, gboolean stop_ppp_manager); - - gboolean (*owns_port)(NMModem *self, const char *iface); -} NMModemClass; - -GType nm_modem_get_type(void); - -gboolean nm_modem_is_claimed(NMModem *modem); -NMModem *nm_modem_claim(NMModem *modem); -void nm_modem_unclaim(NMModem *modem); - -const char *nm_modem_get_path(NMModem *modem); -const char *nm_modem_get_uid(NMModem *modem); -const char *nm_modem_get_control_port(NMModem *modem); -int nm_modem_get_ip_ifindex(NMModem *modem); -const char *nm_modem_get_driver(NMModem *modem); -const char *nm_modem_get_device_id(NMModem *modem); -const char *nm_modem_get_sim_id(NMModem *modem); -const char *nm_modem_get_sim_operator_id(NMModem *modem); -gboolean nm_modem_get_iid(NMModem *modem, NMUtilsIPv6IfaceId *out_iid); -const char *nm_modem_get_operator_code(NMModem *modem); -const char *nm_modem_get_apn(NMModem *modem); - -gboolean nm_modem_set_data_port(NMModem * self, - NMPlatform * platform, - const char * data_port, - NMModemIPMethod ip4_method, - NMModemIPMethod ip6_method, - guint timeout, - GError ** error); - -gboolean nm_modem_owns_port(NMModem *modem, const char *iface); - -void nm_modem_get_capabilities(NMModem * self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps); - -gboolean -nm_modem_check_connection_compatible(NMModem *self, NMConnection *connection, GError **error); - -gboolean nm_modem_complete_connection(NMModem * self, - const char * iface, - NMConnection * connection, - NMConnection *const *existing_connections, - GError ** error); - -void nm_modem_get_route_parameters(NMModem *self, - guint32 *out_ip4_route_table, - guint32 *out_ip4_route_metric, - guint32 *out_ip6_route_table, - guint32 *out_ip6_route_metric); - -void nm_modem_set_route_parameters(NMModem *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric); - -void nm_modem_set_route_parameters_from_device(NMModem *modem, NMDevice *device); - -NMActStageReturn nm_modem_act_stage1_prepare(NMModem * modem, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason); - -void nm_modem_act_stage2_config(NMModem *modem); - -NMActStageReturn nm_modem_stage3_ip4_config_start(NMModem * modem, - NMDevice * device, - NMDeviceClass * device_class, - NMDeviceStateReason *out_failure_reason); - -NMActStageReturn nm_modem_stage3_ip6_config_start(NMModem * modem, - NMDevice * device, - NMDeviceStateReason *out_failure_reason); - -void nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device, NMIP4Config *config); - -void nm_modem_get_secrets(NMModem * modem, - const char *setting_name, - gboolean request_new, - const char *hint); - -void nm_modem_deactivate(NMModem *modem, NMDevice *device); - -typedef void (*NMModemDeactivateCallback)(NMModem *self, GError *error, gpointer user_data); - -void nm_modem_deactivate_async(NMModem * self, - NMDevice * device, - GCancellable * cancellable, - NMModemDeactivateCallback callback, - gpointer user_data); - -void -nm_modem_device_state_changed(NMModem *modem, NMDeviceState new_state, NMDeviceState old_state); - -void nm_modem_set_mm_enabled(NMModem *self, gboolean enabled); - -NMModemState nm_modem_get_state(NMModem *self); -void nm_modem_set_state(NMModem *self, NMModemState new_state, const char *reason); -void nm_modem_set_prev_state(NMModem *self, const char *reason); -const char * nm_modem_state_to_string(NMModemState state); - -NMModemIPType nm_modem_get_supported_ip_types(NMModem *self); - -/* For the modem-manager only */ -void nm_modem_emit_removed(NMModem *self); - -void nm_modem_emit_prepare_result(NMModem *self, gboolean success, NMDeviceStateReason reason); - -void nm_modem_emit_ppp_failed(NMModem *self, NMDeviceStateReason reason); - -GArray *nm_modem_get_connection_ip_type(NMModem *self, NMConnection *connection, GError **error); - -/* For subclasses */ -void nm_modem_emit_ip6_config_result(NMModem *self, NMIP6Config *config, GError *error); - -const char *nm_modem_ip_type_to_string(NMModemIPType ip_type); - -guint32 -nm_modem_get_configured_mtu(NMDevice *self, NMDeviceMtuSource *out_source, gboolean *out_force); - -void _nm_modem_set_operator_code(NMModem *self, const char *operator_code); -void _nm_modem_set_apn(NMModem *self, const char *apn); - -#endif /* __NETWORKMANAGER_MODEM_H__ */ diff --git a/src/devices/wwan/nm-service-providers.c b/src/devices/wwan/nm-service-providers.c deleted file mode 100644 index f7c6b5b8..00000000 --- a/src/devices/wwan/nm-service-providers.c +++ /dev/null @@ -1,455 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2009 Novell, Inc. - * Author: Tambet Ingo (tambet@gmail.com). - * Copyright (C) 2009 - 2019 Red Hat, Inc. - * Copyright (C) 2012 Lanedo GmbH - */ - -#include "nm-default.h" - -#include "nm-service-providers.h" - -typedef enum { - PARSER_TOPLEVEL = 0, - PARSER_COUNTRY, - PARSER_PROVIDER, - PARSER_METHOD_GSM, - PARSER_METHOD_GSM_APN, - PARSER_METHOD_CDMA, - PARSER_DONE, - PARSER_ERROR -} ParseContextState; - -typedef struct { - char * mccmnc; - NMServiceProvidersGsmApnCallback callback; - gpointer user_data; - GCancellable * cancellable; - GMarkupParseContext * ctx; - char buffer[4096]; - - char * text_buffer; - ParseContextState state; - - gboolean mccmnc_matched; - gboolean found_internet_apn; - char * apn; - char * username; - char * password; - char * gateway; - char * auth_method; - GSList * dns; -} ParseContext; - -/*****************************************************************************/ - -static void -parser_toplevel_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - int i; - - if (strcmp(name, "serviceproviders") == 0) { - for (i = 0; attribute_names && attribute_names[i]; i++) { - if (strcmp(attribute_names[i], "format") == 0) { - if (strcmp(attribute_values[i], "2.0")) { - g_warning("%s: mobile broadband provider database format '%s'" - " not supported.", - __func__, - attribute_values[i]); - parse_context->state = PARSER_ERROR; - break; - } - } - } - } else if (strcmp(name, "country") == 0) { - parse_context->state = PARSER_COUNTRY; - } -} - -static void -parser_country_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - if (strcmp(name, "provider") == 0) - parse_context->state = PARSER_PROVIDER; -} - -static void -parser_provider_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - parse_context->mccmnc_matched = FALSE; - if (strcmp(name, "gsm") == 0) - parse_context->state = PARSER_METHOD_GSM; - else if (strcmp(name, "cdma") == 0) - parse_context->state = PARSER_METHOD_CDMA; -} - -static void -parser_gsm_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - int i; - - if (strcmp(name, "network-id") == 0) { - const char *mcc = NULL, *mnc = NULL; - - for (i = 0; attribute_names && attribute_names[i]; i++) { - if (strcmp(attribute_names[i], "mcc") == 0) - mcc = attribute_values[i]; - else if (strcmp(attribute_names[i], "mnc") == 0) - mnc = attribute_values[i]; - if (mcc && strlen(mcc) && mnc && strlen(mnc)) { - char *mccmnc = g_strdup_printf("%s%s", mcc, mnc); - - if (strcmp(mccmnc, parse_context->mccmnc) == 0) - parse_context->mccmnc_matched = TRUE; - g_free(mccmnc); - break; - } - } - } else if (strcmp(name, "apn") == 0) { - parse_context->found_internet_apn = FALSE; - nm_clear_g_free(&parse_context->apn); - nm_clear_g_free(&parse_context->username); - nm_clear_g_free(&parse_context->password); - nm_clear_g_free(&parse_context->gateway); - nm_clear_g_free(&parse_context->auth_method); - g_slist_free_full(parse_context->dns, g_free); - parse_context->dns = NULL; - - for (i = 0; attribute_names && attribute_names[i]; i++) { - if (strcmp(attribute_names[i], "value") == 0) { - parse_context->state = PARSER_METHOD_GSM_APN; - parse_context->apn = g_strstrip(g_strdup(attribute_values[i])); - break; - } - } - } -} - -static void -parser_gsm_apn_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - int i; - - if (strcmp(name, "usage") == 0) { - for (i = 0; attribute_names && attribute_names[i]; i++) { - if ((strcmp(attribute_names[i], "type") == 0) - && (strcmp(attribute_values[i], "internet") == 0)) { - parse_context->found_internet_apn = TRUE; - break; - } - } - } else if (strcmp(name, "authentication") == 0) { - for (i = 0; attribute_names && attribute_names[i]; i++) { - if (strcmp(attribute_names[i], "method") == 0) { - nm_clear_g_free(&parse_context->auth_method); - parse_context->auth_method = g_strstrip(g_strdup(attribute_values[i])); - break; - } - } - } -} - -static void -parser_start_element(GMarkupParseContext *context, - const char * element_name, - const char ** attribute_names, - const char ** attribute_values, - gpointer user_data, - GError ** error) -{ - ParseContext *parse_context = user_data; - - nm_clear_g_free(&parse_context->text_buffer); - - switch (parse_context->state) { - case PARSER_TOPLEVEL: - parser_toplevel_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_COUNTRY: - parser_country_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_PROVIDER: - parser_provider_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_METHOD_GSM: - parser_gsm_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_METHOD_GSM_APN: - parser_gsm_apn_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_METHOD_CDMA: - break; - case PARSER_ERROR: - break; - case PARSER_DONE: - break; - } -} - -static void -parser_country_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "country") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - parse_context->state = PARSER_TOPLEVEL; - } -} - -static void -parser_provider_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "provider") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - parse_context->state = PARSER_COUNTRY; - } -} - -static void -parser_gsm_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "gsm") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - parse_context->state = PARSER_PROVIDER; - } -} - -static void -parser_gsm_apn_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "username") == 0) { - nm_clear_g_free(&parse_context->username); - parse_context->username = g_steal_pointer(&parse_context->text_buffer); - } else if (strcmp(name, "password") == 0) { - nm_clear_g_free(&parse_context->password); - parse_context->password = g_steal_pointer(&parse_context->text_buffer); - } else if (strcmp(name, "dns") == 0) { - parse_context->dns = - g_slist_prepend(parse_context->dns, g_steal_pointer(&parse_context->text_buffer)); - } else if (strcmp(name, "gateway") == 0) { - nm_clear_g_free(&parse_context->gateway); - parse_context->gateway = g_steal_pointer(&parse_context->text_buffer); - } else if (strcmp(name, "apn") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - - if (parse_context->mccmnc_matched && parse_context->found_internet_apn) - parse_context->state = PARSER_DONE; - else - parse_context->state = PARSER_METHOD_GSM; - } -} - -static void -parser_cdma_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "cdma") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - parse_context->state = PARSER_PROVIDER; - } -} - -static void -parser_end_element(GMarkupParseContext *context, - const char * element_name, - gpointer user_data, - GError ** error) -{ - ParseContext *parse_context = user_data; - - switch (parse_context->state) { - case PARSER_TOPLEVEL: - break; - case PARSER_COUNTRY: - parser_country_end(parse_context, element_name); - break; - case PARSER_PROVIDER: - parser_provider_end(parse_context, element_name); - break; - case PARSER_METHOD_GSM: - parser_gsm_end(parse_context, element_name); - break; - case PARSER_METHOD_GSM_APN: - parser_gsm_apn_end(parse_context, element_name); - break; - case PARSER_METHOD_CDMA: - parser_cdma_end(parse_context, element_name); - break; - case PARSER_ERROR: - break; - case PARSER_DONE: - break; - } -} - -static void -parser_text(GMarkupParseContext *context, - const char * text, - gsize text_len, - gpointer user_data, - GError ** error) -{ - ParseContext *parse_context = user_data; - - g_free(parse_context->text_buffer); - parse_context->text_buffer = g_strdup(text); -} - -static const GMarkupParser parser = { - .start_element = parser_start_element, - .end_element = parser_end_element, - .text = parser_text, - .passthrough = NULL, - .error = NULL, -}; - -/*****************************************************************************/ - -static void -finish_parse_context(ParseContext *parse_context, GError *error) -{ - if (parse_context->callback) { - if (error) { - parse_context - ->callback(NULL, NULL, NULL, NULL, NULL, NULL, error, parse_context->user_data); - } else { - parse_context->callback(parse_context->apn, - parse_context->username, - parse_context->password, - parse_context->gateway, - parse_context->auth_method, - parse_context->dns, - error, - parse_context->user_data); - } - } - - g_free(parse_context->mccmnc); - g_markup_parse_context_free(parse_context->ctx); - - g_free(parse_context->text_buffer); - g_free(parse_context->apn); - g_free(parse_context->username); - g_free(parse_context->password); - g_free(parse_context->gateway); - g_free(parse_context->auth_method); - g_slist_free_full(parse_context->dns, g_free); - - g_slice_free(ParseContext, parse_context); -} - -static void read_next_chunk(GInputStream *stream, ParseContext *parse_context); - -static void -stream_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - GInputStream *stream = G_INPUT_STREAM(source_object); - ParseContext *parse_context = user_data; - gssize len; - GError * error = NULL; - - len = g_input_stream_read_finish(stream, res, &error); - if (len == -1) { - g_prefix_error(&error, "Error reading service provider database: "); - finish_parse_context(parse_context, error); - g_clear_error(&error); - return; - } - - if (len == 0) { - g_set_error(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "Operator ID '%s' not found in service provider database", - parse_context->mccmnc); - finish_parse_context(parse_context, error); - g_clear_error(&error); - return; - } - - if (!g_markup_parse_context_parse(parse_context->ctx, parse_context->buffer, len, &error)) { - g_prefix_error(&error, "Error parsing service provider database: "); - finish_parse_context(parse_context, error); - g_clear_error(&error); - return; - } - - if (parse_context->state == PARSER_DONE) { - finish_parse_context(parse_context, NULL); - return; - } - - read_next_chunk(stream, parse_context); -} - -static void -read_next_chunk(GInputStream *stream, ParseContext *parse_context) -{ - g_input_stream_read_async(stream, - parse_context->buffer, - sizeof(parse_context->buffer), - G_PRIORITY_DEFAULT, - parse_context->cancellable, - stream_read_cb, - parse_context); -} - -static void -file_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - GFile * file = G_FILE(source_object); - ParseContext * parse_context = user_data; - GFileInputStream *stream; - gs_free_error GError *error = NULL; - - stream = g_file_read_finish(file, res, &error); - if (!stream) { - g_prefix_error(&error, "Error opening service provider database: "); - finish_parse_context(parse_context, error); - return; - } - - read_next_chunk(G_INPUT_STREAM(stream), parse_context); - - g_object_unref(stream); -} - -/*****************************************************************************/ - -void -nm_service_providers_find_gsm_apn(const char * service_providers, - const char * mccmnc, - GCancellable * cancellable, - NMServiceProvidersGsmApnCallback callback, - gpointer user_data) -{ - GFile * file; - ParseContext *parse_context; - - parse_context = g_slice_new0(ParseContext); - parse_context->mccmnc = g_strdup(mccmnc); - parse_context->cancellable = cancellable; - parse_context->callback = callback; - parse_context->user_data = user_data; - parse_context->ctx = g_markup_parse_context_new(&parser, 0, parse_context, NULL); - - file = g_file_new_for_path(service_providers); - - g_file_read_async(file, G_PRIORITY_DEFAULT, cancellable, file_read_cb, parse_context); - - g_object_unref(file); -} diff --git a/src/devices/wwan/nm-service-providers.h b/src/devices/wwan/nm-service-providers.h deleted file mode 100644 index 093bcd5b..00000000 --- a/src/devices/wwan/nm-service-providers.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_SERVICE_PROVIDERS_H__ -#define __NETWORKMANAGER_SERVICE_PROVIDERS_H__ - -typedef void (*NMServiceProvidersGsmApnCallback)(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data); - -void nm_service_providers_find_gsm_apn(const char * service_providers, - const char * mccmnc, - GCancellable * cancellable, - NMServiceProvidersGsmApnCallback callback, - gpointer user_data); - -#endif /* __NETWORKMANAGER_SERVICE_PROVIDERS_H__ */ diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c deleted file mode 100644 index 1c3406da..00000000 --- a/src/devices/wwan/nm-wwan-factory.c +++ /dev/null @@ -1,146 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <gmodule.h> - -#include "devices/nm-device-factory.h" -#include "nm-setting-gsm.h" -#include "nm-setting-cdma.h" -#include "nm-modem-manager.h" -#include "nm-device-modem.h" -#include "platform/nm-platform.h" - -/*****************************************************************************/ - -#define NM_TYPE_WWAN_FACTORY (nm_wwan_factory_get_type()) -#define NM_WWAN_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) -#define NM_WWAN_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WWAN_FACTORY, NMWwanFactoryClass)) -#define NM_IS_WWAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WWAN_FACTORY)) -#define NM_IS_WWAN_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WWAN_FACTORY)) -#define NM_WWAN_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactoryClass)) - -typedef struct { - NMModemManager *mm; -} NMWwanFactoryPrivate; - -typedef struct { - NMDeviceFactory parent; - NMWwanFactoryPrivate _priv; -} NMWwanFactory; - -typedef struct { - NMDeviceFactoryClass parent; -} NMWwanFactoryClass; - -static GType nm_wwan_factory_get_type(void); - -G_DEFINE_TYPE(NMWwanFactory, nm_wwan_factory, NM_TYPE_DEVICE_FACTORY) - -#define NM_WWAN_FACTORY_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMWwanFactory, NM_IS_WWAN_FACTORY) - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES(NM_DEVICE_FACTORY_DECLARE_LINK_TYPES( - NM_LINK_TYPE_WWAN_NET) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_CDMA_SETTING_NAME)) - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - return (NMDeviceFactory *) g_object_new(NM_TYPE_WWAN_FACTORY, NULL); -} - -/*****************************************************************************/ - -static void -modem_added_cb(NMModemManager *manager, NMModem *modem, gpointer user_data) -{ - NMWwanFactory * self = NM_WWAN_FACTORY(user_data); - gs_unref_object NMDevice *device = NULL; - const char * driver; - - if (nm_modem_is_claimed(modem)) - return; - - driver = nm_modem_get_driver(modem); - - /* If it was a Bluetooth modem and no bluetooth device claimed it, ignore - * it. The rfcomm port (and thus the modem) gets created automatically - * by the Bluetooth code during the connection process. - */ - if (driver && strstr(driver, "bluetooth")) { - nm_log_dbg( - LOGD_MB, - "WWAN factory ignores bluetooth modem '%s' which should be handled by bluetooth plugin", - nm_modem_get_control_port(modem)); - return; - } - - /* Make the new modem device */ - device = nm_device_modem_new(modem); - g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); -} - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - g_return_val_if_fail(plink, NULL); - g_return_val_if_fail(plink->type == NM_LINK_TYPE_WWAN_NET, NULL); - *out_ignore = TRUE; - return NULL; -} - -static void -start(NMDeviceFactory *factory) -{ - NMWwanFactory * self = NM_WWAN_FACTORY(factory); - NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE(self); - - priv->mm = g_object_ref(nm_modem_manager_get()); - - g_signal_connect(priv->mm, NM_MODEM_MANAGER_MODEM_ADDED, G_CALLBACK(modem_added_cb), self); -} - -/*****************************************************************************/ - -static void -nm_wwan_factory_init(NMWwanFactory *self) -{} - -static void -dispose(GObject *object) -{ - NMWwanFactory * self = NM_WWAN_FACTORY(object); - NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE(self); - - if (priv->mm) - g_signal_handlers_disconnect_by_func(priv->mm, modem_added_cb, self); - g_clear_object(&priv->mm); - - /* Chain up to the parent class */ - G_OBJECT_CLASS(nm_wwan_factory_parent_class)->dispose(object); -} - -static void -nm_wwan_factory_class_init(NMWwanFactoryClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - object_class->dispose = dispose; - - factory_class->get_supported_types = get_supported_types; - factory_class->create_device = create_device; - factory_class->start = start; -} diff --git a/src/devices/wwan/tests/test-service-providers.c b/src/devices/wwan/tests/test-service-providers.c deleted file mode 100644 index ec19d588..00000000 --- a/src/devices/wwan/tests/test-service-providers.c +++ /dev/null @@ -1,130 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2019 Red Hat - */ - -#include "nm-default.h" - -#include "nm-service-providers.h" - -#include "nm-test-utils-core.h" - -static void -test_positive_cb(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data) -{ - GMainLoop *loop = user_data; - - g_main_loop_quit(loop); - g_assert_no_error(error); - g_assert_cmpstr(apn, ==, "gprs.example.com"); - g_assert_cmpstr(username, ==, "praise"); - g_assert_cmpstr(password, ==, "santa"); - g_assert_cmpstr(gateway, ==, "192.0.2.3"); - g_assert_cmpstr(auth_method, ==, "pap"); - - g_assert_nonnull(dns); - g_assert_cmpstr(dns->data, ==, "192.0.2.2"); - dns = dns->next; - g_assert_nonnull(dns); - g_assert_cmpstr(dns->data, ==, "192.0.2.1"); - g_assert_null(dns->next); -} - -static void -test_positive(void) -{ - GMainLoop *loop = g_main_loop_new(NULL, FALSE); - - nm_service_providers_find_gsm_apn(NM_BUILD_SRCDIR - "/src/devices/wwan/tests/test-service-providers.xml", - "13337", - NULL, - test_positive_cb, - loop); - g_main_loop_run(loop); - g_main_loop_unref(loop); -} - -/*****************************************************************************/ - -static void -test_negative_cb(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data) -{ - GMainLoop *loop = user_data; - - g_main_loop_quit(loop); - g_assert_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN); -} - -static void -test_negative(void) -{ - GMainLoop *loop = g_main_loop_new(NULL, FALSE); - - nm_service_providers_find_gsm_apn(NM_BUILD_SRCDIR - "/src/devices/wwan/tests/test-service-providers.xml", - "78130", - NULL, - test_negative_cb, - loop); - g_main_loop_run(loop); - g_main_loop_unref(loop); -} - -/*****************************************************************************/ - -static void -test_nonexistent_cb(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data) -{ - GMainLoop *loop = user_data; - - g_main_loop_quit(loop); - g_assert_error(error, G_IO_ERROR, G_IO_ERROR_AGAIN); -} - -static void -test_nonexistent(void) -{ - GMainLoop *loop = g_main_loop_new(NULL, FALSE); - - nm_service_providers_find_gsm_apn("nonexistent.xml", "13337", NULL, test_nonexistent_cb, loop); - g_main_loop_run(loop); - g_main_loop_unref(loop); -} - -/*****************************************************************************/ - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); - - g_test_add_func("/service-providers/positive", test_positive); - g_test_add_func("/service-providers/negative", test_negative); - g_test_add_func("/service-providers/nonexistent", test_nonexistent); - - return g_test_run(); -} diff --git a/src/devices/wwan/tests/test-service-providers.xml b/src/devices/wwan/tests/test-service-providers.xml deleted file mode 100644 index f0ca2deb..00000000 --- a/src/devices/wwan/tests/test-service-providers.xml +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding='utf-8'?> -<!DOCTYPE serviceproviders SYSTEM "serviceproviders.2.dtd"> - -<serviceproviders format="2.0"> - -<country code="feh"> - <provider> - <name>Sophia</name> - <gsm> - <network-id mcc="666" mnc="999"/> - <apn value="access.example.com"> - <plan type="postpaid"/> - <usage type="internet"/> - <name>APN</name> - <dns>192.0.2.1</dns> - <dns>192.0.2.2</dns> - </apn> - </gsm> - </provider> -</country> - -<country code="meh"> - <provider> - <name>Demiurge</name> - <gsm> - <network-id mcc="133" mnc="37"/> - <network-id mcc="133" mnc="666"/> - <apn value="mms"> - <usage type="mms"/> - <name>Unsolicited Nudes MMS</name> - <username>mms</username> - <password>mms</password> - <mmsc>http://mms.example.com/</mmsc> - <mmsproxy>192.0.2.1:8080</mmsproxy> - </apn> - <apn value="gprs.example.com"> - <plan type="postpaid"/> - <usage type="internet"/> - <name>GPRS</name> - <username>praise</username> - <password>santa</password> - <dns>192.0.2.1</dns> - <dns>192.0.2.2</dns> - <gateway>192.0.2.3</gateway> - <authentication method="pap"/> - </apn> - <apn value="second.example.com"> - <plan type="postpaid"/> - <usage type="internet"/> - <name>Second</name> - <username>worship</username> - <password>doom</password> - </apn> - </gsm> - </provider> - - <provider> - <name>Personal</name> - <gsm> - <network-id mcc="666" mnc="999"/> - <apn value="access.example.com"> - <plan type="postpaid"/> - <usage type="internet"/> - <name>APN</name> - <dns>192.0.2.1</dns> - <dns>192.0.2.2</dns> - </apn> - </gsm> - </provider> -</country> - -</serviceproviders> - |