diff options
| author | Michael Biebl <biebl@debian.org> | 2020-04-11 21:28:04 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2020-04-11 21:28:04 +0200 |
| commit | 1e5977b62f896e844b548c3007ace9e1dfa7f9ed (patch) | |
| tree | 7a7416ed410e72b6200f3d860fd315ec11cc106b /src | |
| parent | b012fa6e1d808e0736c009799c62d835cbfcc1dd (diff) | |
New upstream version 1.23.90 upstream/1.23.90
Diffstat (limited to 'src')
221 files changed, 12869 insertions, 9710 deletions
diff --git a/src/devices/adsl/meson.build b/src/devices/adsl/meson.build index a5d1c4b4..79834d7f 100644 --- a/src/devices/adsl/meson.build +++ b/src/devices/adsl/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + sources = files( 'nm-atm-manager.c', 'nm-device-adsl.c', diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c index 487011ff..46d74a07 100644 --- a/src/devices/adsl/nm-atm-manager.c +++ b/src/devices/adsl/nm-atm-manager.c @@ -248,7 +248,7 @@ dispose (GObject *object) for (iter = priv->devices; iter; iter = iter->next) g_object_weak_unref (G_OBJECT (iter->data), device_destroyed, self); - g_clear_pointer (&priv->devices, g_slist_free); + nm_clear_pointer (&priv->devices, g_slist_free); priv->udev_client = nm_udev_client_unref (priv->udev_client); diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index 7c2b3e20..8f7cba22 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -58,7 +58,7 @@ struct _NMDeviceAdslClass { 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) +#define NM_DEVICE_ADSL_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceAdsl, NM_IS_DEVICE_ADSL, NMDevice) /*****************************************************************************/ @@ -228,7 +228,8 @@ link_changed_cb (NMPlatform *platform, /* This only gets called for PPPoE connections and "nas" interfaces */ - if (priv->nas_ifindex > 0 && ifindex == priv->nas_ifindex) { + 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, @@ -273,11 +274,17 @@ nas_update_cb (gpointer user_data) NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); - g_assert (priv->nas_ifname); + nm_assert (priv->nas_ifname); priv->nas_update_count++; - if (priv->nas_update_count > 10) { + 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, @@ -286,31 +293,22 @@ nas_update_cb (gpointer user_data) return G_SOURCE_REMOVE; } - g_warn_if_fail (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) { - /* Keep waiting for it to appear */ - return G_SOURCE_CONTINUE; - } - 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_activate_schedule_stage3_ip_config_start (device); - } else { + 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 NMActStageReturn -br2684_create_iface (NMDeviceAdsl *self, - NMSettingAdsl *s_adsl, - NMDeviceStateReason *out_failure_reason) +static gboolean +br2684_create_iface (NMDeviceAdsl *self) { NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); struct atm_newif_br2684 ni; @@ -318,19 +316,14 @@ br2684_create_iface (NMDeviceAdsl *self, int err, errsv; guint num = 0; - g_return_val_if_fail (s_adsl != NULL, FALSE); - - if (priv->nas_update_id) { - g_warn_if_fail (priv->nas_update_id == 0); - nm_clear_g_source (&priv->nas_update_id); - } + 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); - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_BR2684_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; + return FALSE; } memset (&ni, 0, sizeof (ni)); @@ -343,36 +336,33 @@ br2684_create_iface (NMDeviceAdsl *self, * cannot return that name to us. Since we want to know the name right * away, just brute-force it. */ - while (num < 10000) { + while (TRUE) { memset (&ni.ifname, 0, sizeof (ni.ifname)); - g_snprintf (ni.ifname, sizeof (ni.ifname), "nas%d", num++); + g_snprintf (ni.ifname, sizeof (ni.ifname), "nas%u", num++); err = ioctl (fd, ATM_NEWBACKENDIF, &ni); - if (err == 0) { - g_free (priv->nas_ifname); - priv->nas_ifname = g_strdup (ni.ifname); - _LOGD (LOGD_ADSL, "waiting for br2684 iface '%s' to appear", priv->nas_ifname); + if (err != 0) { + errsv = errno; + if (errsv == EEXIST) + continue; - priv->nas_update_count = 0; - priv->nas_update_id = g_timeout_add (100, nas_update_cb, self); - return NM_ACT_STAGE_RETURN_POSTPONE; - } - errsv = errno; - if (errsv != EEXIST) { _LOGW (LOGD_ADSL, "failed to create br2684 interface (%d)", errsv); - break; + return FALSE; } - } - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_BR2684_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; + 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); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); NMSettingAdsl *s_adsl; const char *protocol; @@ -383,16 +373,27 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) protocol = nm_setting_adsl_get_protocol (s_adsl); _LOGD (LOGD_ADSL, "using ADSL protocol '%s'", protocol); - if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { - /* PPPoE needs RFC2684 bridging before we can do PPP over it */ - ret = br2684_create_iface (self, s_adsl, out_failure_reason); - } else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) { + if (nm_streq0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA)) { /* PPPoA doesn't need anything special */ - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } else - _LOGW (LOGD_ADSL, "unhandled ADSL protocol '%s'", protocol); + 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; + } - return ret; + _LOGW (LOGD_ADSL, "unhandled ADSL protocol '%s'", protocol); + return NM_ACT_STAGE_RETURN_SUCCESS; } static void @@ -460,8 +461,8 @@ act_stage3_ip4_config_start (NMDevice *device, g_return_val_if_fail (s_adsl, NM_ACT_STAGE_RETURN_FAILURE); /* PPPoE uses the NAS interface, not the ATM interface */ - if (g_strcmp0 (nm_setting_adsl_get_protocol (s_adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { - g_assert (priv->nas_ifname); + 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); @@ -540,8 +541,8 @@ adsl_cleanup (NMDeviceAdsl *self) * 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 = -1; - g_clear_pointer (&priv->nas_ifname, g_free); + priv->nas_ifindex = 0; + nm_clear_g_free (&priv->nas_ifname); } static void @@ -577,7 +578,7 @@ get_property (GObject *object, guint prop_id, { switch (prop_id) { case PROP_ATM_INDEX: - g_value_set_int (value, NM_DEVICE_ADSL_GET_PRIVATE ((NMDeviceAdsl *) object)->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); @@ -592,7 +593,7 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_ATM_INDEX: /* construct-only */ - NM_DEVICE_ADSL_GET_PRIVATE ((NMDeviceAdsl *) object)->atm_index = g_value_get_int (value); + 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); @@ -646,7 +647,7 @@ dispose (GObject *object) { adsl_cleanup (NM_DEVICE_ADSL (object)); - nm_clear_g_source (&NM_DEVICE_ADSL_GET_PRIVATE ((NMDeviceAdsl *) object)->carrier_poll_id); + nm_clear_g_source (&NM_DEVICE_ADSL_GET_PRIVATE (object)->carrier_poll_id); G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object); } diff --git a/src/devices/bluetooth/meson.build b/src/devices/bluetooth/meson.build index f0507c23..638a01a2 100644 --- a/src/devices/bluetooth/meson.build +++ b/src/devices/bluetooth/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + sources = files( 'nm-bluez-manager.c', 'nm-bt-error.c', diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index ef087d83..6ff96c32 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -221,7 +221,7 @@ convert_uuids_to_capabilities (const char *const*strv) continue; s_part1 = g_strndup (str, s - str); - switch (g_ascii_strtoull (s_part1, NULL, 16)) { + switch (_nm_utils_ascii_str_to_int64 (s_part1, 16, 0, G_MAXINT, -1)) { case 0x1103: capabilities |= NM_BT_CAPABILITY_DUN; break; @@ -1089,7 +1089,7 @@ _network_server_register_cb (GObject *source_object, ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, &error); if ( !ret - && nm_utils_error_is_cancelled (error, FALSE)) + && nm_utils_error_is_cancelled (error)) return; bzobj = user_data; @@ -2071,9 +2071,12 @@ _dbus_handle_interface_removed (NMBluezManager *self, } static void -_dbus_managed_objects_changed_cb (const char *object_path, - GVariant *added_interfaces_and_properties, - const char *const*removed_interfaces, +_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; @@ -2081,17 +2084,46 @@ _dbus_managed_objects_changed_cb (const char *object_path, 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 (!added_interfaces_and_properties) { - changed = _dbus_handle_interface_removed (self, object_path, &bzobj, removed_interfaces); + 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"); - } else - _dbus_handle_interface_added (self, object_path, added_interfaces_and_properties, FALSE); + return; + } } static void @@ -2140,7 +2172,7 @@ _dbus_get_managed_objects_cb (GVariant *result, GVariant *ifaces; if ( !result - && nm_utils_error_is_cancelled (error, FALSE)) + && nm_utils_error_is_cancelled (error)) return; self = user_data; @@ -2234,6 +2266,7 @@ name_owner_changed (NMBluezManager *self, 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); @@ -2442,7 +2475,7 @@ _connect_dun_step2_cb (NMBluez5DunContext *context, { BzDBusObj *bzobj; - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; bzobj = user_data; @@ -2484,7 +2517,7 @@ _connect_dun_step1_cb (GObject *source_object, ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, &error); if ( !ret - && nm_utils_error_is_cancelled (error, FALSE)) + && nm_utils_error_is_cancelled (error)) return; bzobj = user_data; @@ -2531,7 +2564,7 @@ _connect_nap_cb (GObject *source_object, ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, &error); if ( !ret - && nm_utils_error_is_cancelled (error, FALSE)) + && nm_utils_error_is_cancelled (error)) return; if (ret) diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c index af463d1a..c253d4e2 100644 --- a/src/devices/bluetooth/nm-bluez5-dun.c +++ b/src/devices/bluetooth/nm-bluez5-dun.c @@ -31,12 +31,12 @@ typedef struct { GError *rfcomm_sdp_search_error; + GSource *source; + gint64 connect_open_tty_started_at; gulong cancelled_id; - guint source_id; - guint8 sdp_session_try_count; } ConnectData; @@ -50,13 +50,13 @@ struct _NMBluez5DunContext { char *rfcomm_tty_path; + GSource *rfcomm_tty_poll_source; + int rfcomm_sock_fd; int rfcomm_tty_fd; int rfcomm_tty_no; int rfcomm_channel; - guint rfcomm_tty_poll_id; - bdaddr_t src; bdaddr_t dst; @@ -118,7 +118,7 @@ nm_bluez5_dun_context_get_rfcomm_dev (const NMBluez5DunContext *context) /*****************************************************************************/ static gboolean -_rfcomm_tty_poll_cb (GIOChannel *stream, +_rfcomm_tty_poll_cb (int fd, GIOCondition condition, gpointer user_data) { @@ -129,7 +129,7 @@ _rfcomm_tty_poll_cb (GIOChannel *stream, NM_FLAGS_ALL (condition, G_IO_HUP | G_IO_ERR) ? "," : "", NM_FLAGS_HAS (condition, G_IO_HUP) ? "HUP" : ""); - context->rfcomm_tty_poll_id = 0; + 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; @@ -145,10 +145,10 @@ _connect_open_tty_retry_cb (gpointer user_data) if (r >= 0) return G_SOURCE_REMOVE; - if (nm_utils_get_monotonic_timestamp_ns () > context->cdat->connect_open_tty_started_at + (30 * 100 * NM_UTILS_NS_PER_MSEC)) { + 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; - context->cdat->source_id = 0; + nm_clear_g_source_inst (&context->cdat->source); g_set_error (&error, NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, @@ -166,7 +166,6 @@ _connect_open_tty_retry_cb (gpointer user_data) static int _connect_open_tty (NMBluez5DunContext *context) { - nm_auto_unref_io_channel GIOChannel *io_channel = NULL; int fd; int errsv; @@ -174,26 +173,31 @@ _connect_open_tty (NMBluez5DunContext *context) if (fd < 0) { errsv = NM_ERRNO_NATIVE (errno); - if (context->cdat->source_id == 0) { + 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_ns (); - context->cdat->source_id = g_timeout_add (100, - _connect_open_tty_retry_cb, - context); + 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; - io_channel = g_io_channel_unix_new (context->rfcomm_tty_fd); - context->rfcomm_tty_poll_id = g_io_add_watch (io_channel, - G_IO_ERR | G_IO_HUP, - _rfcomm_tty_poll_cb, - context); + 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; @@ -263,7 +267,7 @@ _connect_create_rfcomm (NMBluez5DunContext *context) } static gboolean -_connect_socket_connect_cb (GIOChannel *stream, +_connect_socket_connect_cb (int fd, GIOCondition condition, gpointer user_data) { @@ -273,7 +277,7 @@ _connect_socket_connect_cb (GIOChannel *stream, socklen_t slen = sizeof(errsv); int r; - context->cdat->source_id = 0; + nm_clear_g_source_inst (&context->cdat->source); r = getsockopt (context->rfcomm_sock_fd, SOL_SOCKET, SO_ERROR, &errsv, &slen); @@ -346,7 +350,6 @@ _connect_socket_connect (NMBluez5DunContext *context) if (connect (context->rfcomm_sock_fd, (struct sockaddr *) &sa, sizeof (sa)) != 0) { - nm_auto_unref_io_channel GIOChannel *io_channel = NULL; errsv = errno; if (errsv != EINPROGRESS) { @@ -363,11 +366,13 @@ _connect_socket_connect (NMBluez5DunContext *context) context->dst_str, context->rfcomm_channel); - io_channel = g_io_channel_unix_new (context->rfcomm_sock_fd); - context->cdat->source_id = g_io_add_watch (io_channel, - G_IO_OUT, - _connect_socket_connect_cb, - context); + 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; } @@ -466,7 +471,7 @@ _connect_sdp_search_cb (uint8_t type, } static gboolean -_connect_sdp_search_io_cb (GIOChannel *io_channel, +_connect_sdp_search_io_cb (int fd, GIOCondition condition, gpointer user_data) { @@ -480,7 +485,7 @@ _connect_sdp_search_io_cb (GIOChannel *io_channel, error = g_error_new (NM_BT_ERROR, NM_BT_ERROR_DUN_CONNECT_FAILED, "Service Discovery interrupted"); - context->cdat->source_id = 0; + nm_clear_g_source_inst (&context->cdat->source); _context_invoke_callback_fail_and_free (context, error); return G_SOURCE_REMOVE; } @@ -490,7 +495,7 @@ _connect_sdp_search_io_cb (GIOChannel *io_channel, return G_SOURCE_CONTINUE; } - context->cdat->source_id = 0; + nm_clear_g_source_inst (&context->cdat->source); if ( context->rfcomm_channel < 0 && !context->cdat->rfcomm_sdp_search_error) { @@ -524,7 +529,7 @@ _connect_sdp_session_start_on_idle_cb (gpointer user_data) NMBluez5DunContext *context = user_data; gs_free_error GError *error = NULL; - context->cdat->source_id = 0; + nm_clear_g_source_inst (&context->cdat->source); _LOGD (context, "retry starting sdp-session..."); @@ -535,7 +540,7 @@ _connect_sdp_session_start_on_idle_cb (gpointer user_data) } static gboolean -_connect_sdp_io_cb (GIOChannel *io_channel, +_connect_sdp_io_cb (int fd, GIOCondition condition, gpointer user_data) { @@ -544,16 +549,13 @@ _connect_sdp_io_cb (GIOChannel *io_channel, sdp_list_t *attrs; uuid_t svclass; uint16_t attr; - int fd; int errsv; int fd_err = 0; int r; socklen_t len = sizeof (fd_err); gs_free_error GError *error = NULL; - context->cdat->source_id = 0; - - fd = g_io_channel_unix_get_fd (io_channel); + nm_clear_g_source_inst (&context->cdat->source); _LOGD (context, "sdp-session ready to connect with fd=%d", fd); @@ -572,10 +574,13 @@ _connect_sdp_io_cb (GIOChannel *io_channel, && --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 (&context->cdat->source_id); - context->cdat->source_id = g_timeout_add (1000, - _connect_sdp_session_start_on_idle_cb, - context); + 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; } @@ -615,10 +620,13 @@ _connect_sdp_io_cb (GIOChannel *io_channel, } /* Set callback responsible for update the internal SDP transaction */ - context->cdat->source_id = g_io_add_watch (io_channel, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - _connect_sdp_search_io_cb, - context); + 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) @@ -644,11 +652,9 @@ static gboolean _connect_sdp_session_start (NMBluez5DunContext *context, GError **error) { - nm_auto_unref_io_channel GIOChannel *io_channel = NULL; - nm_assert (context->cdat); - nm_clear_g_source (&context->cdat->source_id); + 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); @@ -661,11 +667,13 @@ _connect_sdp_session_start (NMBluez5DunContext *context, return FALSE; } - io_channel = g_io_channel_unix_new (sdp_get_socket (context->cdat->sdp_session)); - context->cdat->source_id = g_io_add_watch (io_channel, - G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - _connect_sdp_io_cb, - context); + 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; } @@ -772,7 +780,7 @@ _context_cleanup_connect_data (NMBluez5DunContext *context) nm_clear_g_signal_handler (cdat->cancellable, &cdat->cancelled_id); - nm_clear_g_source (&cdat->source_id); + nm_clear_g_source_inst (&cdat->source); nm_clear_pointer (&cdat->sdp_session, sdp_close); @@ -797,7 +805,7 @@ _context_invoke_callback (NMBluez5DunContext *context, if (!error) _LOGD (context, "connected via \"%s\"", context->rfcomm_tty_path); - else if (nm_utils_error_is_cancelled (error, FALSE)) + else if (nm_utils_error_is_cancelled (error)) _LOGD (context, "cancelled"); else _LOGD (context, "failed to connect: %s", error->message); @@ -836,7 +844,7 @@ _context_free (NMBluez5DunContext *context) _context_cleanup_connect_data (context); - nm_clear_g_source (&context->rfcomm_tty_poll_id); + nm_clear_g_source_inst (&context->rfcomm_tty_poll_source); if (context->rfcomm_sock_fd >= 0) { if (context->rfcomm_tty_no >= 0) { diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 497810c3..ab18897f 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -484,7 +484,7 @@ modem_auth_result (NMModem *modem, GError *error, gpointer user_data) } priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_INIT; - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -519,7 +519,7 @@ modem_prepare_result (NMModem *modem, } priv->stage1_modem_prepare_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); } static void @@ -719,7 +719,7 @@ mm_modem_added_cb (NMModemManager *manager, 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)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); } /*****************************************************************************/ @@ -830,7 +830,7 @@ connect_bz_cb (NMBluezManager *bz_mgr, NMDeviceBtPrivate *priv; char sbuf[100]; - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; self = user_data; @@ -903,7 +903,7 @@ connect_bz_cb (NMBluezManager *bz_mgr, } priv->stage1_bt_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); } static NMActStageReturn @@ -1153,7 +1153,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); switch (prop_id) { case PROP_BT_NAME: @@ -1172,7 +1172,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); switch (prop_id) { case PROP_BT_BZ_MGR: @@ -1296,7 +1296,7 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE ((NMDeviceBt *) object); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); g_free (priv->connect_rfcomm_iface); g_free (priv->dbus_path); diff --git a/src/devices/meson.build b/src/devices/meson.build index 2d874659..40a5c9dc 100644 --- a/src/devices/meson.build +++ b/src/devices/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + subdir('adsl') if enable_modem_manager diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c index 6e7a2a0f..735dd25b 100644 --- a/src/devices/nm-acd-manager.c +++ b/src/devices/nm-acd-manager.c @@ -38,8 +38,7 @@ struct _NMAcdManager { GHashTable *addresses; guint completed; NAcd *acd; - GIOChannel *channel; - guint event_id; + GSource *event_source; NMAcdCallbacks callbacks; gpointer user_data; @@ -157,7 +156,9 @@ nm_acd_manager_add_address (NMAcdManager *self, in_addr_t address) } static gboolean -acd_event (GIOChannel *source, GIOCondition condition, gpointer data) +acd_event (int fd, + GIOCondition condition, + gpointer data) { NMAcdManager *self = data; NAcdEvent *event; @@ -183,12 +184,12 @@ acd_event (GIOChannel *source, GIOCondition condition, gpointer data) 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_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)); + _nm_utils_inet4_ntop (info->address, address_str)); } } check_probing_done = TRUE; @@ -201,14 +202,14 @@ acd_event (GIOChannel *source, GIOCondition condition, gpointer data) 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), + _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), + _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)); @@ -248,7 +249,7 @@ acd_probe_add (NMAcdManager *self, 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_utils_inet4_ntop (info->address, sbuf), nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex), acd_error_to_string (r)); return FALSE; @@ -260,7 +261,7 @@ acd_probe_add (NMAcdManager *self, 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_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); @@ -334,11 +335,15 @@ nm_acd_manager_start_probe (NMAcdManager *self, guint timeout) if (success) self->state = STATE_PROBING; - nm_assert (!self->channel); - nm_assert (self->event_id == 0); + nm_assert (!self->event_source); n_acd_get_fd (self->acd, &fd); - self->channel = g_io_channel_unix_new (fd); - self->event_id = g_io_add_watch (self->channel, G_IO_IN, acd_event, self); + 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; } @@ -412,20 +417,24 @@ nm_acd_manager_announce_addresses (NMAcdManager *self) 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_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)); + _LOGD ("announcing address %s", _nm_utils_inet4_ntop (info->address, sbuf)); } } - if (!self->channel) { - nm_assert (self->event_id == 0); + if (!self->event_source) { n_acd_get_fd (self->acd, &fd); - self->channel = g_io_channel_unix_new (fd); - self->event_id = g_io_add_watch (self->channel, G_IO_IN, acd_event, self); + 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; @@ -479,8 +488,7 @@ nm_acd_manager_free (NMAcdManager *self) self->callbacks.user_data_destroy (self->user_data); nm_clear_pointer (&self->addresses, g_hash_table_destroy); - nm_clear_pointer (&self->channel, g_io_channel_unref); - nm_clear_g_source (&self->event_id); + 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-device-6lowpan.c b/src/devices/nm-device-6lowpan.c index 0289a360..66ed5458 100644 --- a/src/devices/nm-device-6lowpan.c +++ b/src/devices/nm-device-6lowpan.c @@ -34,7 +34,7 @@ struct _NMDevice6LowpanClass { 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) +#define NM_DEVICE_6LOWPAN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDevice6Lowpan, NM_IS_DEVICE_6LOWPAN, NMDevice) /*****************************************************************************/ diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 36d00328..c15605ce 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -70,16 +70,16 @@ complete_connection (NMDevice *device, /*****************************************************************************/ static gboolean -set_bond_attr (NMDevice *device, NMBondMode mode, const char *attr, const char *value) +_set_bond_attr (NMDevice *device, const char *attr, const char *value) { NMDeviceBond *self = NM_DEVICE_BOND (device); - gboolean ret; int ifindex = nm_device_get_ifindex (device); + gboolean ret; - if (!_nm_setting_bond_option_supported (attr, mode)) - return FALSE; - - ret = nm_platform_sysctl_master_set_option (nm_device_get_platform (device), ifindex, attr, value); + 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; @@ -119,8 +119,10 @@ update_connection (NMDevice *device, NMConnection *connection) /* Read bond options from sysfs and update the Bond setting to match */ options = nm_setting_bond_get_valid_options (s_bond); for (; *options; options++) { - gs_free char *value = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, *options); char *p; + gs_free char *value = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), + ifindex, + *options); if ( value && _nm_setting_bond_get_option_type (s_bond, *options) == NM_BOND_OPTION_TYPE_BOTH) { @@ -129,8 +131,12 @@ update_connection (NMDevice *device, NMConnection *connection) *p = '\0'; } - if (value && nm_streq (*options, NM_SETTING_BOND_OPTION_MODE)) - mode = _nm_setting_bond_mode_from_string (value); + if (mode == NM_BOND_MODE_UNKNOWN) { + if (value && nm_streq (*options, 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 (*options, mode)) continue; @@ -181,138 +187,86 @@ set_arp_targets (NMDevice *device, gs_free char *tmp = NULL; tmp = g_strdup_printf ("%s%s", prefix, value_v[i]); - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, tmp); + _set_bond_attr (device, NM_SETTING_BOND_OPTION_ARP_IP_TARGET, tmp); } } +/* + * Sets bond attribute stored in the option hashtable or + * the default value if no value was set. + */ static void -set_simple_option (NMDevice *device, - NMBondMode mode, - NMSettingBond *s_bond, - const char *opt) +set_bond_attr_or_default (NMDevice *device, + NMSettingBond *s_bond, + const char *opt) { - const char *value; + NMDeviceBond *self = NM_DEVICE_BOND (device); + const char *value = nm_setting_bond_get_option_or_default (s_bond, opt); - value = nm_setting_bond_get_option_by_name (s_bond, opt); - if (!value) - value = nm_setting_bond_get_option_default (s_bond, opt); - set_bond_attr (device, mode, opt, value); + if (value) { + _set_bond_attr (device, opt, value); + } else { + _LOGD (LOGD_BOND, "bond option %s rejected due to incompatibility", opt); + } } static gboolean apply_bonding_config (NMDeviceBond *self) { NMDevice *device = NM_DEVICE (self); - NMSettingBond *s_bond; int ifindex = nm_device_get_ifindex (device); - const char *mode_str, *value; - char *contents; - gboolean set_arp_interval = TRUE; + NMSettingBond *s_bond; NMBondMode mode; - - /* Option restrictions: - * - * arp_interval conflicts miimon > 0 - * arp_interval conflicts [ alb, tlb ] - * arp_validate does not work with [ BOND_MODE_8023AD, BOND_MODE_TLB, BOND_MODE_ALB ] - * downdelay needs miimon - * updelay needs miimon - * primary needs [ active-backup, tlb, alb ] - * - * clearing miimon requires that arp_interval be 0, but clearing - * arp_interval doesn't require miimon to be 0 - */ + const char *mode_str; + const char *value; + char *contents; 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_by_name (s_bond, NM_SETTING_BOND_OPTION_MODE); - if (!mode_str) - mode_str = "balance-rr"; - + 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); - if (mode == NM_BOND_MODE_UNKNOWN) { - _LOGW (LOGD_BOND, "unknown bond mode '%s'", mode_str); - return FALSE; - } + 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_attr (device, mode, NM_SETTING_BOND_OPTION_MODE, mode_str); - - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MIIMON); - if (value && atoi (value)) { - /* clear arp interval */ - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_ARP_INTERVAL, "0"); - set_arp_interval = FALSE; - - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_MIIMON, value); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_UPDELAY); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY); - } else if (!value) { - /* If not given, and arp_interval is not given or disabled, default to 100 */ - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - if (_nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, 0) == 0) - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_MIIMON, "100"); - } - - if (set_arp_interval) { - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); - /* Just let miimon get cleared automatically; even setting miimon to - * 0 (disabled) clears arp_interval. - */ - } - - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE); - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_ARP_VALIDATE, value ?: "0"); - - /* Primary */ - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_PRIMARY); - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_PRIMARY, value ?: ""); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_MIIMON); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_UPDELAY); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_DOWNDELAY); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ARP_INTERVAL); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ARP_VALIDATE); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY); /* ARP targets: clear and initialize the list */ - contents = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, + contents = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), + ifindex, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); set_arp_targets (device, mode, contents, " \n", "-"); - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); + value = nm_setting_bond_get_option_or_default (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); set_arp_targets (device, mode, value, ",", "+"); g_free (contents); - /* AD actor system: don't set if empty */ - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM); - if (value) - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM, value); - - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_AD_SELECT); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_LACP_RATE); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER); - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY); - - /* num_grat_arp and num_unsol_na are actually the same attribute - * on kernel side and their value in the bond setting is guaranteed - * to be equal. Write only one of the two. - */ - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP); - if (value) - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP, value); - else - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA); - + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYSTEM); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_ACTOR_SYS_PRIO); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_SELECT); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_AD_USER_PORT_KEY); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ALL_SLAVES_ACTIVE); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ARP_ALL_TARGETS); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_FAIL_OVER_MAC); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_LACP_RATE); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_LP_INTERVAL); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_MIN_LINKS); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY_RESELECT); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_RESEND_IGMP); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_USE_CARRIER); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP); return TRUE; } @@ -369,8 +323,9 @@ enslave_slave (NMDevice *device, const char *active; if (s_bond) { - active = nm_setting_bond_get_option_by_name (s_bond, "active_slave"); - if (active && nm_streq0 (active, nm_device_get_iface (slave))) { + active = nm_setting_bond_get_option_or_default (s_bond, + NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); + if (nm_streq0 (active, nm_device_get_iface (slave))) { nm_platform_sysctl_master_set_option (nm_device_get_platform (device), nm_device_get_ifindex (device), "active_slave", @@ -407,7 +362,7 @@ release_slave (NMDevice *device, 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)); + _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 @@ -568,19 +523,14 @@ reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_n s_bond = nm_connection_get_setting_bond (con_new); g_return_if_fail (s_bond); - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MODE); - if (!value) - value = "balance-rr"; - + 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); /* Primary */ - value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_PRIMARY); - set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_PRIMARY, value ?: ""); - + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_PRIMARY); /* Active slave */ - set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); + set_bond_attr_or_default (device, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE); } /*****************************************************************************/ diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index 72a8ce2b..c6c54344 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -158,11 +158,85 @@ complete_connection (NMDevice *device, return TRUE; } +static void +from_sysfs_group_address (const char *value, GValue *out) +{ + if (!nm_utils_hwaddr_matches (value, -1, "01:80:C2:00:00:00", -1)) + g_value_set_string (out, value); +} + +static const char * +to_sysfs_group_address (GValue *value) +{ + return g_value_get_string (value) ?: "01:80:C2:00:00:00"; +} + +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 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; + } +} + /*****************************************************************************/ typedef struct { const char *name; const char *sysname; + const char *(*to_sysfs) (GValue *value); + void (*from_sysfs) (const char *value, GValue *out); uint nm_min; uint nm_max; uint nm_default; @@ -172,41 +246,76 @@ typedef struct { } Option; static const Option master_options[] = { - { NM_SETTING_BRIDGE_STP, "stp_state", /* this must stay as the first item */ - 0, 1, 1, - FALSE, FALSE, FALSE }, - { NM_SETTING_BRIDGE_PRIORITY, "priority", - 0, G_MAXUINT16, 0x8000, - TRUE, FALSE, TRUE }, - { NM_SETTING_BRIDGE_FORWARD_DELAY, "forward_delay", - 0, NM_BR_MAX_FORWARD_DELAY, 15, - TRUE, TRUE, TRUE}, - { NM_SETTING_BRIDGE_HELLO_TIME, "hello_time", - 0, NM_BR_MAX_HELLO_TIME, 2, - TRUE, TRUE, TRUE }, - { NM_SETTING_BRIDGE_MAX_AGE, "max_age", - 0, NM_BR_MAX_MAX_AGE, 20, - TRUE, TRUE, TRUE }, - { NM_SETTING_BRIDGE_AGEING_TIME, "ageing_time", - NM_BR_MIN_AGEING_TIME, NM_BR_MAX_AGEING_TIME, 300, - TRUE, TRUE, FALSE }, - { NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, "group_fwd_mask", - 0, 0xFFFF, 0, - TRUE, FALSE, FALSE }, - { NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "multicast_snooping", - 0, 1, 1, - FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_STP, "stp_state", /* this must stay as the first item */ + NULL, NULL, + 0, 1, 1, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_PRIORITY, "priority", + NULL, NULL, + 0, G_MAXUINT16, 0x8000, + TRUE, FALSE, TRUE }, + { NM_SETTING_BRIDGE_FORWARD_DELAY, "forward_delay", + NULL, NULL, + 0, NM_BR_MAX_FORWARD_DELAY, 15, + TRUE, TRUE, TRUE}, + { NM_SETTING_BRIDGE_HELLO_TIME, "hello_time", + NULL, NULL, + 0, NM_BR_MAX_HELLO_TIME, 2, + TRUE, TRUE, TRUE }, + { NM_SETTING_BRIDGE_MAX_AGE, "max_age", + NULL, NULL, + 0, NM_BR_MAX_MAX_AGE, 20, + TRUE, TRUE, TRUE }, + { NM_SETTING_BRIDGE_AGEING_TIME, "ageing_time", + NULL, NULL, + NM_BR_MIN_AGEING_TIME, NM_BR_MAX_AGEING_TIME, 300, + TRUE, TRUE, FALSE }, + { NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, "group_fwd_mask", + NULL, NULL, + 0, 0xFFFF, 0, + TRUE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_MULTICAST_QUERIER, "multicast_querier", + NULL, NULL, + 0, 1, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, "multicast_query_use_ifaddr", + NULL, NULL, + 0, 1, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "multicast_snooping", + NULL, NULL, + 0, 1, 1, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_MULTICAST_ROUTER, "multicast_router", + to_sysfs_multicast_router, from_sysfs_multicast_router, + 0, 0, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_GROUP_ADDRESS, "group_addr", + to_sysfs_group_address, from_sysfs_group_address, + 0, 0, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_VLAN_PROTOCOL, "vlan_protocol", + to_sysfs_vlan_protocol, from_sysfs_vlan_protocol, + 0, 0, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, "vlan_stats_enabled", + NULL, NULL, + 0, 1, 0, + FALSE, FALSE, FALSE }, { NULL, NULL } }; static const Option slave_options[] = { { NM_SETTING_BRIDGE_PORT_PRIORITY, "priority", + NULL, NULL, 0, NM_BR_PORT_MAX_PRIORITY, NM_BR_PORT_DEF_PRIORITY, TRUE, FALSE }, { NM_SETTING_BRIDGE_PORT_PATH_COST, "path_cost", + NULL, NULL, 0, NM_BR_PORT_MAX_PATH_COST, 100, TRUE, FALSE }, { NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", + NULL, NULL, 0, 1, 0, FALSE, FALSE }, { NULL, NULL } @@ -216,50 +325,82 @@ 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; - GValue val = G_VALUE_INIT; - guint32 uval = 0; - char value[100]; + const char *value; - g_assert (setting); + 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); - g_assert (pspec); + nm_assert (pspec); - /* Get the property's value */ g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec)); g_object_get_property ((GObject *) setting, option->name, &val); - if (G_VALUE_HOLDS_BOOLEAN (&val)) - uval = g_value_get_boolean (&val) ? 1 : 0; - else if (G_VALUE_HOLDS_UINT (&val)) { - uval = 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) { - g_value_unset (&val); - g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec)); - g_param_value_set_default (pspec, &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_UINT: { + char value_buf[100]; + guint uval; + uval = g_value_get_uint (&val); - } - /* 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; - } else + /* 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) { + g_value_unset (&val); + g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec)); + g_param_value_set_default (pspec, &val); + uval = g_value_get_uint (&val); + } + + /* 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; + + nm_sprintf_buf (value_buf, "%u", uval); + value = value_buf; + } + break; + case G_TYPE_STRING: + value = g_value_get_string (&val); + break; + default: nm_assert_not_reached (); - g_value_unset (&val); + value = NULL; + break; + } - nm_sprintf_buf (value, "%u", uval); - 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); +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 ** @@ -335,29 +476,68 @@ update_connection (NMDevice *device, NMConnection *connection) option++; for (; option->name; option++) { - gs_free char *str = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, option->sysname); - uint value; + 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) { - /* 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_bridge, option->name, value, NULL); - } else + 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_UINT: { + guint 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_int64 (str, 10, + option->nm_min, + option->nm_max, + option->nm_default); + } + g_value_set_uint (&value, 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); } } @@ -518,7 +698,7 @@ _bt_register_bridge_cb (GError *error, { NMDeviceBridge *self; - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; self = user_data; @@ -532,7 +712,7 @@ _bt_register_bridge_cb (GError *error, return; } - nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self)); + nm_device_activate_schedule_stage2_device_config (NM_DEVICE (self), FALSE); } void @@ -561,40 +741,41 @@ 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) { - gs_free_error GError *error = NULL; + 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 (!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; - - 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; - } + if (self->bt_cancellable) + return NM_ACT_STAGE_RETURN_POSTPONE; - self->bt_registered = TRUE; + 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; } - return NM_ACT_STAGE_RETURN_SUCCESS; + self->bt_registered = TRUE; + return NM_ACT_STAGE_RETURN_POSTPONE; } static void @@ -736,10 +917,11 @@ create_and_realize (NMDevice *device, if ( !hwaddr && nm_device_hw_addr_get_cloned (device, connection, FALSE, &hwaddr_cloned, NULL, NULL)) { - /* The cloned MAC address might by dynamic, for example with stable-id="${RANDOM}". - * It's a bit odd that we first create the device with one dynamic address, - * and later on may reset it to another. That is, because we don't cache - * the dynamic address in @device, like we do during nm_device_hw_addr_set_cloned(). */ + /* 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; } diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 86e50c52..7556bb27 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -43,19 +43,9 @@ _LOG_DECLARE_SELF(NMDeviceEthernet); #define PPPOE_RECONNECT_DELAY 7 #define PPPOE_ENCAP_OVERHEAD 8 /* 2 bytes for PPP, 6 for PPPoE */ -/*****************************************************************************/ - -typedef struct Supplicant { - NMSupplicantManager *mgr; - NMSupplicantInterface *iface; - - /* signal handler ids */ - gulong iface_state_id; - gulong auth_state_id; +#define SUPPLICANT_LNK_TIMEOUT_SEC 15 - /* Timeouts and idles */ - guint con_timeout_id; -} Supplicant; +/*****************************************************************************/ typedef enum { DCB_WAIT_UNKNOWN = 0, @@ -72,12 +62,6 @@ typedef enum { } DcbWait; typedef struct _NMDeviceEthernetPrivate { - guint32 speed; - gulong carrier_id; - - Supplicant supplicant; - guint supplicant_timeout_id; - /* s390 */ char * subchan1; char * subchan2; @@ -87,6 +71,24 @@ typedef struct _NMDeviceEthernetPrivate { 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 */ @@ -110,7 +112,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceEthernet, 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) +#define NM_DEVICE_ETHERNET_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMDeviceEthernet, NM_IS_DEVICE_ETHERNET, NMDevice) /*****************************************************************************/ @@ -400,7 +402,9 @@ supplicant_interface_release (NMDeviceEthernet *self) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - nm_clear_g_source (&priv->supplicant_timeout_id); + 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); @@ -501,7 +505,7 @@ wired_secrets_cb (NMActRequest *req, } supplicant_interface_release (self); - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -538,7 +542,7 @@ wired_secrets_get_secrets (NMDeviceEthernet *self, } static gboolean -link_timeout_cb (gpointer user_data) +supplicant_lnk_timeout_cb (gpointer user_data) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); @@ -547,13 +551,13 @@ link_timeout_cb (gpointer user_data) NMConnection *applied_connection; const char *setting_name; - priv->supplicant_timeout_id = 0; + 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 FALSE; + return G_SOURCE_REMOVE; } /* Disconnect event during initial authentication and credentials @@ -578,13 +582,13 @@ link_timeout_cb (gpointer user_data) 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 FALSE; + 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 FALSE; + return G_SOURCE_REMOVE; } static NMSupplicantConfig * @@ -605,7 +609,7 @@ build_supplicant_config (NMDeviceEthernet *self, 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 (FALSE, FALSE, FALSE, FALSE); + 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)) { @@ -617,18 +621,86 @@ build_supplicant_config (NMDeviceEthernet *self, } 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 = NM_DEVICE_ETHERNET (user_data); + NMDeviceEthernet *self; + NMDeviceEthernetPrivate *priv; - if (error && !nm_utils_error_is_cancelled (error, TRUE)) { + 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 @@ -640,72 +712,29 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); - NMSupplicantConfig *config; - NMDeviceState devstate; - GError *error = NULL; NMSupplicantInterfaceState new_state = new_state_i; NMSupplicantInterfaceState old_state = old_state_i; - if (new_state == old_state) - return; - _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)); - devstate = nm_device_get_state (device); - - switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - config = build_supplicant_config (self, &error); - if (config) { - nm_supplicant_interface_assoc (priv->supplicant.iface, config, - supplicant_iface_assoc_cb, self); - g_object_unref (config); - } else { - _LOGE (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) couldn't build security configuration: %s", - error->message); - g_clear_error (&error); - - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: - nm_clear_g_source (&priv->supplicant_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 (devstate == 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 (device); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: - if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) { - /* Start the link timeout so we allow some time for reauthentication */ - if (!priv->supplicant_timeout_id) - priv->supplicant_timeout_id = g_timeout_add_seconds (15, link_timeout_cb, device); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + 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 ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) - wired_auth_cond_fail (self, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - break; - default: - break; + 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 NMActStageReturn +static gboolean handle_auth_or_fail (NMDeviceEthernet *self, NMActRequest *req, gboolean new_secrets) @@ -714,7 +743,7 @@ handle_auth_or_fail (NMDeviceEthernet *self, NMConnection *applied_connection; if (!nm_device_auth_retries_try_next (NM_DEVICE (self))) - return NM_ACT_STAGE_RETURN_FAILURE; + return FALSE; nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); @@ -724,7 +753,7 @@ handle_auth_or_fail (NMDeviceEthernet *self, 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 NM_ACT_STAGE_RETURN_FAILURE; + return FALSE; } _LOGI (LOGD_DEVICE | LOGD_ETHER, "Activation: (ethernet) asking for new secrets"); @@ -739,7 +768,7 @@ handle_auth_or_fail (NMDeviceEthernet *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 NM_ACT_STAGE_RETURN_POSTPONE; + return TRUE; } static gboolean @@ -771,43 +800,70 @@ supplicant_connection_timeout_cb (gpointer user_data) if (nm_settings_connection_get_timestamp (connection, ×tamp)) new_secrets = !timestamp; - if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_FAILURE) + 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; - return FALSE; + 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 gboolean -supplicant_interface_init (NMDeviceEthernet *self) +static void +supplicant_interface_create_cb (NMSupplicantManager *supplicant_manager, + NMSupplMgrCreateIfaceHandle *handle, + NMSupplicantInterface *iface, + GError *error, + gpointer user_data) { - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + NMDeviceEthernet *self; + NMDeviceEthernetPrivate *priv; guint timeout; - supplicant_interface_release (self); + if (nm_utils_error_is_cancelled (error)) + return; - priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr, - nm_device_get_iface (NM_DEVICE (self)), - NM_SUPPLICANT_DRIVER_WIRED); + self = user_data; + priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + + nm_assert (priv->supplicant.create_handle == handle); + priv->supplicant.create_handle = NULL; - if (!priv->supplicant.iface) { + if (error) { _LOGE (LOGD_DEVICE | LOGD_ETHER, - "Couldn't initialize supplicant interface"); - return FALSE; + "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; } - /* Listen for its state signals */ + 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); - /* Set up a timeout on the connection attempt */ timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self)); priv->supplicant.con_timeout_id = g_timeout_add_seconds (timeout, supplicant_connection_timeout_cb, self); - return TRUE; + if (nm_supplicant_interface_state_is_operational (nm_supplicant_interface_get_state (iface))) + supplicant_iface_start (self); } static NMPlatformLinkDuplexType @@ -898,7 +954,7 @@ pppoe_reconnect_delay (gpointer user_data) 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)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); return G_SOURCE_REMOVE; } @@ -920,7 +976,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) * 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_s () - priv->last_pppoe_time; + 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)) { @@ -947,7 +1003,6 @@ supplicant_check_secrets_needed (NMDeviceEthernet *self, NMDeviceStateReason *ou NMConnection *connection; NMSetting8021x *security; const char *setting_name; - NMActStageReturn ret = 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); @@ -956,7 +1011,7 @@ supplicant_check_secrets_needed (NMDeviceEthernet *self, NMDeviceStateReason *ou if (!security) { _LOGE (LOGD_DEVICE, "Invalid or missing 802.1X security"); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return ret; + return NM_ACT_STAGE_RETURN_FAILURE; } if (!priv->supplicant.mgr) @@ -971,21 +1026,25 @@ supplicant_check_secrets_needed (NMDeviceEthernet *self, NMDeviceStateReason *ou "Activation: (ethernet) connection '%s' has security, but secrets are required.", nm_connection_get_id (connection)); - ret = handle_auth_or_fail (self, req, FALSE); - if (ret != NM_ACT_STAGE_RETURN_POSTPONE) + if (!handle_auth_or_fail (self, req, FALSE)) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - } else { - _LOGI (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) connection '%s' requires no security. No secrets needed.", - nm_connection_get_id (connection)); - - if (supplicant_interface_init (self)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return NM_ACT_STAGE_RETURN_FAILURE; + } + return NM_ACT_STAGE_RETURN_POSTPONE; } - return ret; + _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 @@ -997,33 +1056,17 @@ carrier_changed (NMSupplicantInterface *iface, NMDeviceStateReason reason; NMActStageReturn ret; - if (nm_device_has_carrier (NM_DEVICE (self))) { - _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); - } - } -} - -static NMActStageReturn -nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + if (!nm_device_has_carrier (NM_DEVICE (self))) + return; - 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; + _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); } - - return supplicant_check_secrets_needed (self, out_failure_reason); } /*****************************************************************************/ @@ -1329,7 +1372,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMSettingConnection *s_con; const char *connection_type; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; + gboolean do_postpone = FALSE; NMSettingDcb *s_dcb; s_con = nm_device_get_applied_setting (device, NM_TYPE_SETTING_CONNECTION); @@ -1343,14 +1386,23 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) * process opens the port up for normal traffic. */ connection_type = nm_setting_connection_get_connection_type (s_con); - if (!strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)) { + 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 */ - return nm_8021x_stage2_config (self, out_failure_reason); + 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); } } @@ -1372,7 +1424,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } priv->dcb_handle_carrier_changes = TRUE; - ret = NM_ACT_STAGE_RETURN_POSTPONE; + do_postpone = TRUE; } /* PPPoE setup */ @@ -1382,11 +1434,13 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) s_ppp = nm_device_get_applied_setting (device, NM_TYPE_SETTING_PPP); if (s_ppp) { - guint32 mtu = 0, mru = 0, mxu; + guint32 mtu; + guint32 mru; + guint32 mxu; mtu = nm_setting_ppp_get_mtu (s_ppp); mru = nm_setting_ppp_get_mru (s_ppp); - mxu = mru > mtu ? mru : mtu; + 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); @@ -1397,7 +1451,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } } - return ret; + return do_postpone + ? NM_ACT_STAGE_RETURN_POSTPONE + : NM_ACT_STAGE_RETURN_SUCCESS; } static NMActStageReturn @@ -1428,7 +1484,7 @@ get_configured_mtu (NMDevice *device, gboolean *out_force) { /* MTU only set for plain ethernet */ - if (NM_DEVICE_ETHERNET_GET_PRIVATE ((NMDeviceEthernet *) device)->ppp_manager) + if (NM_DEVICE_ETHERNET_GET_PRIVATE (device)->ppp_manager) return 0; return nm_device_get_configured_mtu_for_wired (device, out_source, out_force); @@ -1468,7 +1524,7 @@ deactivate (NMDevice *device) /* 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_s (); + priv->last_pppoe_time = nm_utils_get_monotonic_timestamp_sec (); } static gboolean @@ -1589,13 +1645,13 @@ get_s390_subchannels (NMDevice *device) { nm_assert (NM_IS_DEVICE_ETHERNET (device)); - return NM_DEVICE_ETHERNET_GET_PRIVATE ((NMDeviceEthernet *) device)->subchannels; + return NM_DEVICE_ETHERNET_GET_PRIVATE (device)->subchannels; } static void update_connection (NMDevice *device, NMConnection *connection) { - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE ((NMDeviceEthernet *) device); + 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; diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index 1c1d5eaa..a7db2669 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -173,8 +173,8 @@ static GHashTable *factories_by_setting = NULL; static void __attribute__((destructor)) _cleanup (void) { - g_clear_pointer (&factories_by_link, g_hash_table_unref); - g_clear_pointer (&factories_by_setting, g_hash_table_unref); + nm_clear_pointer (&factories_by_link, g_hash_table_unref); + nm_clear_pointer (&factories_by_setting, g_hash_table_unref); } NMDeviceFactory * @@ -385,6 +385,7 @@ nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc call _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); diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 5f9e13c3..9883dc4e 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -32,7 +32,7 @@ struct _NMDeviceGenericClass { 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) +#define NM_DEVICE_GENERIC_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceGeneric, NM_IS_DEVICE_GENERIC, NMDevice) /*****************************************************************************/ @@ -50,8 +50,8 @@ get_generic_capabilities (NMDevice *device) static const char * get_type_description (NMDevice *device) { - if (NM_DEVICE_GENERIC_GET_PRIVATE ((NMDeviceGeneric *) device)->type_description) - return NM_DEVICE_GENERIC_GET_PRIVATE ((NMDeviceGeneric *) device)->type_description; + 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); } @@ -64,7 +64,7 @@ realize_start_notify (NMDevice *device, const NMPlatformLink *plink) NM_DEVICE_CLASS (nm_device_generic_parent_class)->realize_start_notify (device, plink); - g_clear_pointer (&priv->type_description, g_free); + 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)); @@ -181,7 +181,7 @@ dispose (GObject *object) NMDeviceGeneric *self = NM_DEVICE_GENERIC (object); NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (self); - g_clear_pointer (&priv->type_description, g_free); + nm_clear_g_free (&priv->type_description); G_OBJECT_CLASS (nm_device_generic_parent_class)->dispose (object); } diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 9f79d9bb..0ef74d25 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -43,7 +43,7 @@ struct _NMDeviceInfinibandClass { 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) +#define NM_DEVICE_INFINIBAND_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceInfiniband, NM_IS_DEVICE_INFINIBAND, NMDevice) /*****************************************************************************/ @@ -52,7 +52,7 @@ get_generic_capabilities (NMDevice *device) { guint32 caps = NM_DEVICE_CAP_CARRIER_DETECT; - if (NM_DEVICE_INFINIBAND_GET_PRIVATE ((NMDeviceInfiniband *) device)->is_partition) + if (NM_DEVICE_INFINIBAND_GET_PRIVATE (device)->is_partition) caps |= NM_DEVICE_CAP_IS_SOFTWARE; return caps; @@ -223,7 +223,7 @@ create_and_realize (NMDevice *device, const NMPlatformLink **out_plink, GError **error) { - NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE ((NMDeviceInfiniband *) device); + NMDeviceInfinibandPrivate *priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device); NMSettingInfiniband *s_infiniband; int r; @@ -281,7 +281,7 @@ unrealize (NMDevice *device, GError **error) g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (device), FALSE); - priv = NM_DEVICE_INFINIBAND_GET_PRIVATE ((NMDeviceInfiniband *) device); + priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (device); if (priv->p_key < 0) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, @@ -309,7 +309,7 @@ get_property (GObject *object, guint prop_id, { switch (prop_id) { case PROP_IS_PARTITION: - g_value_set_boolean (value, NM_DEVICE_INFINIBAND_GET_PRIVATE ((NMDeviceInfiniband *) object)->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); @@ -323,7 +323,7 @@ set_property (GObject *object, guint prop_id, { switch (prop_id) { case PROP_IS_PARTITION: - NM_DEVICE_INFINIBAND_GET_PRIVATE ((NMDeviceInfiniband *) object)->is_partition = g_value_get_boolean (value); + 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); diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c index 0becb5e5..0a33c82e 100644 --- a/src/devices/nm-device-ip-tunnel.c +++ b/src/devices/nm-device-ip-tunnel.c @@ -67,7 +67,7 @@ struct _NMDeviceIPTunnelClass { 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) +#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceIPTunnel, NM_IS_DEVICE_IP_TUNNEL, NMDevice) /*****************************************************************************/ @@ -96,35 +96,63 @@ ip6tnl_flags_plat_to_setting (guint32 flags) /*****************************************************************************/ static gboolean -address_equal_pp (int family, const char *a, const char *b) +address_equal_pp (int addr_family, const char *a, const char *b) { - char buffer1[sizeof (struct in6_addr)] = { }; - char buffer2[sizeof (struct in6_addr)] = { }; + const NMIPAddr *addr_a = &nm_ip_addr_zero; + const NMIPAddr *addr_b = &nm_ip_addr_zero; + NMIPAddr addr_a_val; + NMIPAddr addr_b_val; - g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + nm_assert_addr_family (addr_family); - if (a) - inet_pton (family, a, buffer1); - if (b) - inet_pton (family, b, buffer2); + 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 !memcmp (buffer1, buffer2, - family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr)); + return nm_ip_addr_equal (addr_family, addr_a, addr_b); } static gboolean -address_equal_pn (int family, const char *a, const void *b) +address_set (int addr_family, + char **p_addr, + const NMIPAddr *addr_new) { - char buffer1[sizeof (struct in6_addr)] = { }; + 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; + } - g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + if (*p_addr) { + NMIPAddr addr_val; - if (a) - inet_pton (family, a, buffer1); + if (!nm_utils_parse_inaddr_bin (addr_family, + *p_addr, + NULL, + &addr_val)) + nm_assert_not_reached (); - return !memcmp (buffer1, b, - family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr)); + 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 @@ -133,10 +161,8 @@ 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; - in_addr_t local4 = 0; - in_addr_t remote4 = 0; - struct in6_addr local6 = IN6ADDR_ANY_INIT; - struct in6_addr remote6 = IN6ADDR_ANY_INIT; + NMIPAddr local = NM_IP_ADDR_INIT; + NMIPAddr remote = NM_IP_ADDR_INIT; guint8 ttl = 0; guint8 tos = 0; guint8 encap_limit = 0; @@ -149,19 +175,19 @@ update_properties_from_ifindex (NMDevice *device, int ifindex) clear: nm_device_parent_set_ifindex (device, 0); if (priv->local) { - g_clear_pointer (&priv->local, g_free); + nm_clear_g_free (&priv->local); _notify (self, PROP_LOCAL); } if (priv->remote) { - g_clear_pointer (&priv->remote, g_free); + nm_clear_g_free (&priv->remote); _notify (self, PROP_REMOTE); } if (priv->input_key) { - g_clear_pointer (&priv->input_key, g_free); + nm_clear_g_free (&priv->input_key); _notify (self, PROP_INPUT_KEY); } if (priv->output_key) { - g_clear_pointer (&priv->output_key, g_free); + nm_clear_g_free (&priv->output_key); _notify (self, PROP_OUTPUT_KEY); } @@ -181,8 +207,8 @@ clear: } parent_ifindex = lnk->parent_ifindex; - local4 = lnk->local; - remote4 = lnk->remote; + local.addr4 = lnk->local; + remote.addr4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; @@ -197,7 +223,7 @@ clear: g_free (key); } else { if (priv->input_key) { - g_clear_pointer (&priv->input_key, g_free); + nm_clear_g_free (&priv->input_key); _notify (self, PROP_INPUT_KEY); } } @@ -212,7 +238,7 @@ clear: g_free (key); } else { if (priv->output_key) { - g_clear_pointer (&priv->output_key, g_free); + nm_clear_g_free (&priv->output_key); _notify (self, PROP_OUTPUT_KEY); } } @@ -226,8 +252,8 @@ clear: } parent_ifindex = lnk->parent_ifindex; - local4 = lnk->local; - remote4 = lnk->remote; + local.addr4 = lnk->local; + remote.addr4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; @@ -241,8 +267,8 @@ clear: } parent_ifindex = lnk->parent_ifindex; - local4 = lnk->local; - remote4 = lnk->remote; + local.addr4 = lnk->local; + remote.addr4 = lnk->remote; ttl = lnk->ttl; tos = lnk->tos; pmtud = lnk->path_mtu_discovery; @@ -267,8 +293,8 @@ clear: } parent_ifindex = lnk->parent_ifindex; - local6 = lnk->local; - remote6 = lnk->remote; + local.addr6 = lnk->local; + remote.addr6 = lnk->remote; ttl = lnk->ttl; tos = lnk->tclass; encap_limit = lnk->encap_limit; @@ -288,7 +314,7 @@ clear: g_free (key); } else { if (priv->input_key) { - g_clear_pointer (&priv->input_key, g_free); + nm_clear_g_free (&priv->input_key); _notify (self, PROP_INPUT_KEY); } } @@ -303,7 +329,7 @@ clear: g_free (key); } else { if (priv->output_key) { - g_clear_pointer (&priv->output_key, g_free); + nm_clear_g_free (&priv->output_key); _notify (self, PROP_OUTPUT_KEY); } } @@ -313,35 +339,10 @@ clear: nm_device_parent_set_ifindex (device, parent_ifindex); - if (priv->addr_family == AF_INET) { - if (!address_equal_pn (AF_INET, priv->local, &local4)) { - g_clear_pointer (&priv->local, g_free); - if (local4) - priv->local = nm_utils_inet4_ntop_dup (local4); - _notify (self, PROP_LOCAL); - } - - if (!address_equal_pn (AF_INET, priv->remote, &remote4)) { - g_clear_pointer (&priv->remote, g_free); - if (remote4) - priv->remote = nm_utils_inet4_ntop_dup (remote4); - _notify (self, PROP_REMOTE); - } - } else { - if (!address_equal_pn (AF_INET6, priv->local, &local6)) { - g_clear_pointer (&priv->local, g_free); - if (memcmp (&local6, &in6addr_any, sizeof (in6addr_any))) - priv->local = nm_utils_inet6_ntop_dup (&local6); - _notify (self, PROP_LOCAL); - } - - if (!address_equal_pn (AF_INET6, priv->remote, &remote6)) { - g_clear_pointer (&priv->remote, g_free); - if (memcmp (&remote6, &in6addr_any, sizeof (in6addr_any))) - priv->remote = nm_utils_inet6_ntop_dup (&remote6); - _notify (self, PROP_REMOTE); - } - } + 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: @@ -657,11 +658,44 @@ create_and_realize (NMDevice *device, 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); - g_assert (s_ip_tunnel); + nm_assert (NM_IS_SETTING_IP_TUNNEL (s_ip_tunnel)); mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel); + + if ( 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); + } + + if (NM_IN_SET (mode, NM_IP_TUNNEL_MODE_GRE)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "Invalid hardware address '%s' for tunnel type", + hwaddr); + return FALSE; + } + + mac_address_valid = TRUE; + } + switch (mode) { case NM_IP_TUNNEL_MODE_GRETAP: lnk_gre.is_tap = TRUE; @@ -702,7 +736,12 @@ create_and_realize (NMDevice *device, lnk_gre.output_flags = NM_GRE_KEY; } - r = nm_platform_link_gre_add (nm_device_get_platform (device), iface, &lnk_gre, out_plink); + 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", @@ -896,7 +935,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE ((NMDeviceIPTunnel *) object); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); switch (prop_id) { case PROP_MODE: @@ -942,7 +981,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE ((NMDeviceIPTunnel *) object); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); switch (prop_id) { case PROP_MODE: @@ -963,7 +1002,7 @@ nm_device_ip_tunnel_init (NMDeviceIPTunnel *self) static void constructed (GObject *object) { - NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE ((NMDeviceIPTunnel *) object); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); if (NM_IN_SET (priv->mode, NM_IP_TUNNEL_MODE_IPIP6, @@ -983,10 +1022,10 @@ dispose (GObject *object) NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (object); NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); - g_clear_pointer (&priv->local, g_free); - g_clear_pointer (&priv->remote, g_free); - g_clear_pointer (&priv->input_key, g_free); - g_clear_pointer (&priv->output_key, g_free); + 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); } diff --git a/src/devices/nm-device-macsec.c b/src/devices/nm-device-macsec.c index c9592a49..f1878078 100644 --- a/src/devices/nm-device-macsec.c +++ b/src/devices/nm-device-macsec.c @@ -23,16 +23,9 @@ _LOG_DECLARE_SELF(NMDeviceMacsec); /*****************************************************************************/ -typedef struct Supplicant { - NMSupplicantManager *mgr; - NMSupplicantInterface *iface; +#define SUPPLICANT_LNK_TIMEOUT_SEC 15 - /* signal handler ids */ - gulong iface_state_id; - - /* Timeouts and idles */ - guint con_timeout_id; -} Supplicant; +/*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceMacsec, PROP_SCI, @@ -53,8 +46,20 @@ typedef struct { NMPlatformLnkMacsec props; gulong parent_state_id; gulong parent_mtu_id; - Supplicant supplicant; - guint supplicant_timeout_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; @@ -69,7 +74,7 @@ struct _NMDeviceMacsecClass { 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) +#define NM_DEVICE_MACSEC_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceMacsec, NM_IS_DEVICE_MACSEC, NMDevice) /******************************************************************/ @@ -77,7 +82,8 @@ static void macsec_secrets_cancel (NMDeviceMacsec *self); /******************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (validation_mode_to_string, guint8, +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"), @@ -226,7 +232,7 @@ build_supplicant_config (NMDeviceMacsec *self, GError **error) 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 (FALSE, FALSE, FALSE, FALSE); + config = nm_supplicant_config_new (NM_SUPPL_CAP_MASK_NONE); s_macsec = nm_device_get_applied_setting (NM_DEVICE (self), NM_TYPE_SETTING_MACSEC); @@ -253,7 +259,9 @@ supplicant_interface_release (NMDeviceMacsec *self) { NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); - nm_clear_g_source (&priv->supplicant_timeout_id); + 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); @@ -264,21 +272,6 @@ supplicant_interface_release (NMDeviceMacsec *self) } static void -supplicant_iface_assoc_cb (NMSupplicantInterface *iface, - GError *error, - gpointer user_data) -{ - NMDeviceMacsec *self = NM_DEVICE_MACSEC (user_data); - - if (error && !nm_utils_error_is_cancelled (error, TRUE)) { - supplicant_interface_release (self); - nm_device_queue_state (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - } -} - -static void macsec_secrets_cb (NMActRequest *req, NMActRequestGetSecretsCallId *call_id, NMSettingsConnection *connection, @@ -313,7 +306,7 @@ macsec_secrets_cb (NMActRequest *req, return; } - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -350,7 +343,7 @@ macsec_secrets_get_secrets (NMDeviceMacsec *self, } static gboolean -link_timeout_cb (gpointer user_data) +supplicant_lnk_timeout_cb (gpointer user_data) { NMDeviceMacsec *self = NM_DEVICE_MACSEC (user_data); NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); @@ -359,7 +352,7 @@ link_timeout_cb (gpointer user_data) NMConnection *applied_connection; const char *setting_name; - priv->supplicant_timeout_id = 0; + priv->supplicant.lnk_timeout_id = 0; req = nm_device_get_act_request (dev); @@ -367,7 +360,7 @@ link_timeout_cb (gpointer user_data) nm_device_state_changed (dev, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_TIMEOUT); - return FALSE; + return G_SOURCE_REMOVE; } /* Disconnect event during initial authentication and credentials @@ -391,13 +384,98 @@ link_timeout_cb (gpointer user_data) 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 FALSE; + 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 FALSE; + 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 @@ -409,76 +487,31 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, { NMDeviceMacsec *self = NM_DEVICE_MACSEC (user_data); NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); - NMSupplicantConfig *config; - NMDeviceState devstate; - GError *error = NULL; NMSupplicantInterfaceState new_state = new_state_i; NMSupplicantInterfaceState old_state = old_state_i; - if (new_state == old_state) - return; - _LOGI (LOGD_DEVICE, "supplicant interface state: %s -> %s", nm_supplicant_interface_state_to_string (old_state), nm_supplicant_interface_state_to_string (new_state)); - devstate = nm_device_get_state (device); - - switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - config = build_supplicant_config (self, &error); - if (config) { - nm_supplicant_interface_assoc (priv->supplicant.iface, config, - supplicant_iface_assoc_cb, self); - g_object_unref (config); - } else { - _LOGE (LOGD_DEVICE, - "Activation: couldn't build security configuration: %s", - error->message); - g_clear_error (&error); - - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: - nm_clear_g_source (&priv->supplicant_timeout_id); - nm_clear_g_source (&priv->supplicant.con_timeout_id); - nm_device_bring_up (device, TRUE, NULL); - - /* If this is the initial association during device activation, - * schedule the next activation stage. - */ - if (devstate == NM_DEVICE_STATE_CONFIG) { - _LOGI (LOGD_DEVICE, - "Activation: Stage 2 of 5 (Device Configure) successful."); - nm_device_activate_schedule_stage3_ip_config_start (device); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: - if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) { - /* Start the link timeout so we allow some time for reauthentication */ - if (!priv->supplicant_timeout_id) - priv->supplicant_timeout_id = g_timeout_add_seconds (15, link_timeout_cb, device); - } - break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + 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 ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - } - break; - default: - ; + 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 NMActStageReturn +static gboolean handle_auth_or_fail (NMDeviceMacsec *self, NMActRequest *req, gboolean new_secrets) @@ -487,7 +520,7 @@ handle_auth_or_fail (NMDeviceMacsec *self, NMConnection *applied_connection; if (!nm_device_auth_retries_try_next (NM_DEVICE (self))) - return NM_ACT_STAGE_RETURN_FAILURE; + return FALSE; nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); @@ -497,13 +530,13 @@ handle_auth_or_fail (NMDeviceMacsec *self, 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 NM_ACT_STAGE_RETURN_FAILURE; + 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 NM_ACT_STAGE_RETURN_POSTPONE; + return TRUE; } static gboolean @@ -526,11 +559,10 @@ supplicant_connection_timeout_cb (gpointer user_data) "Activation: (macsec) association took too long."); supplicant_interface_release (self); - req = nm_device_get_act_request (device); - g_assert (req); + req = nm_device_get_act_request (device); connection = nm_act_request_get_settings_connection (req); - g_assert (connection); + 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, @@ -539,48 +571,73 @@ supplicant_connection_timeout_cb (gpointer user_data) if (nm_settings_connection_get_timestamp (connection, ×tamp)) new_secrets = !timestamp; - if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_POSTPONE) - _LOGW (LOGD_DEVICE, "Activation: (macsec) asking for new secrets"); - else + 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"); - return FALSE; + 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 gboolean -supplicant_interface_init (NMDeviceMacsec *self) +static void +supplicant_interface_create_cb (NMSupplicantManager *supplicant_manager, + NMSupplMgrCreateIfaceHandle *handle, + NMSupplicantInterface *iface, + GError *error, + gpointer user_data) { - NMDeviceMacsecPrivate *priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); - NMDevice *parent; + NMDeviceMacsec *self; + NMDeviceMacsecPrivate *priv; guint timeout; - parent = nm_device_parent_get_device (NM_DEVICE (self)); - g_return_val_if_fail (parent, FALSE); + if (nm_utils_error_is_cancelled (error)) + return; - supplicant_interface_release (self); + self = user_data; + priv = NM_DEVICE_MACSEC_GET_PRIVATE (self); - priv->supplicant.iface = nm_supplicant_manager_create_interface (priv->supplicant.mgr, - nm_device_get_iface (parent), - NM_SUPPLICANT_DRIVER_MACSEC); + nm_assert (priv->supplicant.create_handle == handle); - if (!priv->supplicant.iface) { + priv->supplicant.create_handle = NULL; + + if (error) { _LOGE (LOGD_DEVICE, - "Couldn't initialize supplicant interface"); - return FALSE; + "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; } - /* Listen for its state signals */ + 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); - /* Set up a timeout on the connection attempt */ timeout = nm_device_get_supplicant_timeout (NM_DEVICE (self)); priv->supplicant.con_timeout_id = g_timeout_add_seconds (timeout, supplicant_connection_timeout_cb, self); - return TRUE; + + if (nm_supplicant_interface_state_is_operational (nm_supplicant_interface_get_state (iface))) + supplicant_iface_start (self); } static NMActStageReturn @@ -589,8 +646,9 @@ 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; - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + NMDevice *parent; const char *setting_name; + int ifindex; connection = nm_device_get_applied_connection (NM_DEVICE (self)); @@ -608,21 +666,31 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) "Activation: connection '%s' has security, but secrets are required.", nm_connection_get_id (connection)); - ret = handle_auth_or_fail (self, req, FALSE); - if (ret != NM_ACT_STAGE_RETURN_POSTPONE) + if (!handle_auth_or_fail (self, req, FALSE)) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - } else { - _LOGI (LOGD_DEVICE | LOGD_ETHER, - "Activation: connection '%s' requires no security. No secrets needed.", - nm_connection_get_id (connection)); + return NM_ACT_STAGE_RETURN_FAILURE; + } - if (supplicant_interface_init (self)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + return NM_ACT_STAGE_RETURN_POSTPONE; } - return ret; + _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 diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 3633f02d..2f8c4c32 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -49,7 +49,7 @@ struct _NMDeviceMacvlanClass { 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) +#define NM_DEVICE_MACVLAN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceMacvlan, NM_IS_DEVICE_MACVLAN, NMDevice) /*****************************************************************************/ @@ -292,7 +292,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE ((NMDeviceMacvlan *) device); + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device); NMSettingMacvlan *s_macvlan; const char *parent = NULL; @@ -390,7 +390,7 @@ complete_connection (NMDevice *device, static void update_connection (NMDevice *device, NMConnection *connection) { - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE ((NMDeviceMacvlan *) device); + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device); NMSettingMacvlan *s_macvlan = nm_connection_get_setting_macvlan (connection); int new_mode; @@ -422,7 +422,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE ((NMDeviceMacvlan *) object); + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (object); switch (prop_id) { case PROP_MODE: @@ -444,7 +444,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE ((NMDeviceMacvlan *) object); + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (object); switch (prop_id) { case PROP_TAP: diff --git a/src/devices/nm-device-ppp.c b/src/devices/nm-device-ppp.c index 32403ff6..52784143 100644 --- a/src/devices/nm-device-ppp.c +++ b/src/devices/nm-device-ppp.c @@ -39,7 +39,7 @@ struct _NMDevicePppClass { 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) +#define NM_DEVICE_PPP_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDevicePpp, NM_IS_DEVICE_PPP, NMDevice) static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) @@ -137,11 +137,9 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) 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); @@ -157,9 +155,12 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) } if ( !priv->ppp_manager - || !nm_ppp_manager_start (priv->ppp_manager, req, + || !nm_ppp_manager_start (priv->ppp_manager, + req, nm_setting_pppoe_get_username (s_pppoe), - 30, 0, &error)) { + 30, + 0, + &error)) { _LOGW (LOGD_DEVICE | LOGD_PPP, "PPPoE failed to start: %s", error->message); g_error_free (error); @@ -169,16 +170,18 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) return NM_ACT_STAGE_RETURN_FAILURE; } - g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, + 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_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_signal_connect (priv->ppp_manager, + NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, G_CALLBACK (ppp_ip4_config), self); - return NM_ACT_STAGE_RETURN_POSTPONE; } diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index e87733ef..8d539026 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -71,8 +71,10 @@ 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); -void nm_device_activate_schedule_stage2_device_config (NMDevice *device); +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, @@ -180,15 +182,14 @@ void nm_device_commit_mtu (NMDevice *self); ((NM_NARG (__VA_ARGS__) == 0) \ ? NULL \ : ({ \ - static const struct { \ - const NMLinkType types[NM_NARG (__VA_ARGS__)]; \ - const NMLinkType sentinel; \ - } _link_types = { \ - .types = { __VA_ARGS__ }, \ - .sentinel = NM_LINK_TYPE_NONE, \ + static const NMLinkType _types[NM_NARG (__VA_ARGS__) + 1] = { \ + __VA_ARGS__ \ + _NM_MACRO_COMMA_IF_ARGS (__VA_ARGS__) \ + NM_LINK_TYPE_NONE, \ }; \ \ - _link_types.types; \ + nm_assert (_types[NM_NARG (__VA_ARGS__)] == NM_LINK_TYPE_NONE); \ + _types; \ })\ ) diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 77b46a59..8d4680e2 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -48,7 +48,7 @@ struct _NMDeviceTunClass { 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) +#define NM_DEVICE_TUN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceTun, NM_IS_DEVICE_TUN, NMDevice) /*****************************************************************************/ diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index b6efeb81..183e9eff 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -182,7 +182,7 @@ update_properties (NMDevice *device) g_return_if_fail (NM_IS_DEVICE_VLAN (device)); - priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) device); + priv = NM_DEVICE_VLAN_GET_PRIVATE (device); ifindex = nm_device_get_ifindex (device); @@ -221,7 +221,7 @@ create_and_realize (NMDevice *device, const NMPlatformLink **out_plink, GError **error) { - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) device); + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); const char *iface = nm_device_get_iface (device); NMSettingVlan *s_vlan; int parent_ifindex; @@ -318,7 +318,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE ((NMDeviceVlan *) device); + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); NMSettingVlan *s_vlan; const char *parent; diff --git a/src/devices/nm-device-vrf.c b/src/devices/nm-device-vrf.c new file mode 100644 index 00000000..05ee7a8c --- /dev/null +++ b/src/devices/nm-device-vrf.c @@ -0,0 +1,371 @@ +// 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 new file mode 100644 index 00000000..89ab0f13 --- /dev/null +++ b/src/devices/nm-device-vrf.h @@ -0,0 +1,22 @@ +// 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 index 29be6854..b49e7c3e 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -57,7 +57,7 @@ struct _NMDeviceVxlanClass { 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) +#define NM_DEVICE_VXLAN_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceVxlan, NM_IS_DEVICE_VXLAN, NMDevice) /*****************************************************************************/ @@ -232,7 +232,7 @@ address_matches (const char *str, in_addr_t addr4, struct in6_addr *addr6) static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection, GError **error) { - NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE ((NMDeviceVxlan *) device); + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device); NMSettingVxlan *s_vxlan; const char *parent; @@ -369,7 +369,7 @@ complete_connection (NMDevice *device, static void update_connection (NMDevice *device, NMConnection *connection) { - NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE ((NMDeviceVxlan *) device); + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device); NMSettingVxlan *s_vxlan = nm_connection_get_setting_vxlan (connection); char sbuf[NM_UTILS_INET_ADDRSTRLEN]; @@ -390,11 +390,11 @@ update_connection (NMDevice *device, NMConnection *connection) 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), + _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), + _nm_utils_inet6_ntop (&priv->props.group6, sbuf), NULL); } } @@ -402,11 +402,11 @@ update_connection (NMDevice *device, NMConnection *connection) 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), + _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), + _nm_utils_inet6_ntop (&priv->props.local6, sbuf), NULL); } } @@ -473,7 +473,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE ((NMDeviceVxlan *) object); + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (object); switch (prop_id) { case PROP_ID: diff --git a/src/devices/nm-device-wireguard.c b/src/devices/nm-device-wireguard.c index c916fa46..bb7a5950 100644 --- a/src/devices/nm-device-wireguard.c +++ b/src/devices/nm-device-wireguard.c @@ -51,7 +51,7 @@ G_STATIC_ASSERT (NM_WIREGUARD_SYMMETRIC_KEY_LEN == NMP_WIREGUARD_SYMMETRIC_KEY_L /*****************************************************************************/ -#define LINK_CONFIG_RATE_LIMIT_NSEC (50 * NM_UTILS_NS_PER_MSEC) +#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) @@ -80,7 +80,7 @@ typedef struct { NMSockAddrUnion sockaddr; - /* the timestamp (in nm_utils_get_monotonic_timestamp_ns() scale) when we want + /* 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. @@ -168,7 +168,8 @@ static gboolean link_config_delayed_ratelimit_cb (gpointer user_data); /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_link_config_mode_to_string, LinkConfigMode, +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"), @@ -555,7 +556,7 @@ _peers_resolve_retry_timeout (gpointer user_data) _LOGT (LOGD_DEVICE, "wireguard-peers: rechecking peer endpoints..."); - now = nm_utils_get_monotonic_timestamp_ns (); + 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) @@ -606,11 +607,11 @@ _peers_resolve_retry_reschedule (NMDeviceWireGuard *self, return; } - now = nm_utils_get_monotonic_timestamp_ns (); + 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_NS_PER_MSEC, + interval_ms = NM_CLAMP ((new_next_try_at_nsec - now) / NM_UTILS_NSEC_PER_MSEC, (gint64) 500, (gint64) (24*60*60*1000)); @@ -636,8 +637,8 @@ _peers_resolve_retry_reschedule_for_peer (NMDeviceWireGuard *self, return; } - peer_data->ep_resolv.next_try_at_nsec = nm_utils_get_monotonic_timestamp_ns () - + (retry_in_msec * NM_UTILS_NS_PER_MSEC); + 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); } @@ -684,7 +685,7 @@ _peers_resolve_cb (GObject *source_object, list = g_resolver_lookup_by_name_finish (G_RESOLVER (source_object), res, &resolv_error); - if (nm_utils_error_is_cancelled (resolv_error, FALSE)) + if (nm_utils_error_is_cancelled (resolv_error)) return; peer_data = user_data; @@ -1265,7 +1266,7 @@ _secrets_cb (NMActRequest *req, return; } - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -1370,7 +1371,7 @@ link_config (NMDeviceWireGuard *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_ns (); + 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)); @@ -1475,12 +1476,12 @@ link_config_delayed (NMDeviceWireGuard *self, priv->link_config_delayed_id = 0; if (priv->link_config_last_at != 0) { - now = nm_utils_get_monotonic_timestamp_ns (); + 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_NS_PER_MSEC, + 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); @@ -1521,28 +1522,26 @@ act_stage2_config (NMDevice *device, } 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); + "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. */ - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NONE); return NM_ACT_STAGE_RETURN_SUCCESS; } - if (ret != NM_ACT_STAGE_RETURN_FAILURE) { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NONE); - return ret; + 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; } - 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 * diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 72ec29a1..c3483e4d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -43,8 +43,7 @@ #include "nm-ip6-config.h" #include "nm-pacrunner-manager.h" #include "dnsmasq/nm-dnsmasq-manager.h" -#include "nm-dhcp4-config.h" -#include "nm-dhcp6-config.h" +#include "nm-dhcp-config.h" #include "nm-rfkill-manager.h" #include "nm-firewall-manager.h" #include "settings/nm-settings-connection.h" @@ -159,6 +158,15 @@ typedef struct { 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; @@ -233,9 +241,9 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDevice, PROP_LLDP_NEIGHBORS, PROP_REAL, PROP_SLAVES, - PROP_REFRESH_RATE_MS, - PROP_TX_BYTES, - PROP_RX_BYTES, + PROP_STATISTICS_REFRESH_RATE_MS, + PROP_STATISTICS_TX_BYTES, + PROP_STATISTICS_RX_BYTES, PROP_IP4_CONNECTIVITY, PROP_IP6_CONNECTIVITY, PROP_INTERFACE_FLAGS, @@ -475,17 +483,29 @@ typedef struct _NMDevicePrivate { /* DHCPv4 tracking */ struct { - NMDhcpClient * client; - NMDhcp4Config * config; char * pac_url; char * root_path; - gulong state_sigid; - guint grace_id; - bool was_active:1; - bool grace_pending:1; } 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; @@ -545,22 +565,6 @@ typedef struct _NMDevicePrivate { EthtoolState *ethtool_state; - struct { - NMDhcpClient * client; - NMDhcp6Config * config; - /* IP6 config from DHCP */ - AppliedConfig ip6_config; - /* Event ID of the current IP6 config from DHCP */ - char * event_id; - gulong state_sigid; - gulong prefix_sigid; - NMNDiscDHCPLevel mode; - guint needed_prefixes; - guint grace_id; - bool was_active:1; - bool grace_pending:1; - } dhcp6; - gboolean needs_ip6_subnet; /* master interface for bridge/bond/team slave */ @@ -687,8 +691,6 @@ static void (*const activate_stage4_ip_config_timeout_x[2]) (NMDevice *self) = { static void sriov_op_cb (GError *error, gpointer user_data); -static void activate_stage2_device_config (NMDevice *self); - static void activate_stage5_ip_config_result_4 (NMDevice *self); static void activate_stage5_ip_config_result_6 (NMDevice *self); @@ -699,7 +701,8 @@ static void (*const activate_stage5_ip_config_result_x[2]) (NMDevice *self) = { /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (queued_state_to_string, NMDeviceState, +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"), @@ -796,7 +799,8 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_device_state_reason_to_str, NMDeviceStateReason, #define reason_to_string_a(reason) NM_UTILS_LOOKUP_STR_A (nm_device_state_reason_to_str, reason) -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (mtu_source_to_str, NMDeviceMtuSource, +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"), @@ -886,6 +890,22 @@ is_loopback (NMDevice *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) { @@ -1041,7 +1061,8 @@ applied_config_reset_nameservers (AppliedConfig *config) /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_sys_iface_state_to_str, NMDeviceSysIfaceState, +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"), @@ -1183,7 +1204,14 @@ init_ip_config_dns_priority (NMDevice *self, NMIPConfig *config) G_MININT, G_MAXINT, 0); - nm_ip_config_set_dns_priority (config, priority ?: NM_DNS_PRIORITY_DEFAULT_NORMAL); + + 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); } /*****************************************************************************/ @@ -1372,7 +1400,8 @@ _get_stable_id (NMDevice *self, /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_ip_state_to_string, NMDeviceIPState, +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"), @@ -1837,11 +1866,11 @@ _stats_update_counters (NMDevice *self, if (priv->stats.tx_bytes != tx_bytes) { priv->stats.tx_bytes = tx_bytes; - _notify (self, PROP_TX_BYTES); + _notify (self, PROP_STATISTICS_TX_BYTES); } if (priv->stats.rx_bytes != rx_bytes) { priv->stats.rx_bytes = rx_bytes; - _notify (self, PROP_RX_BYTES); + _notify (self, PROP_STATISTICS_RX_BYTES); } } @@ -1898,7 +1927,7 @@ _stats_set_refresh_rate (NMDevice *self, guint refresh_rate_ms) old_rate = priv->stats.refresh_rate_ms; priv->stats.refresh_rate_ms = refresh_rate_ms; - _notify (self, PROP_REFRESH_RATE_MS); + _notify (self, PROP_STATISTICS_REFRESH_RATE_MS); _LOGD (LOGD_DEVICE, "stats: set refresh to %u ms", priv->stats.refresh_rate_ms); @@ -2124,6 +2153,8 @@ nm_device_get_route_metric_default (NMDeviceType device_type) 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: @@ -2289,6 +2320,8 @@ _get_route_table (NMDevice *self, NMSettingIPConfig *s_ip; guint32 route_table = 0; gboolean is_user_config = TRUE; + NMSettingConnection *s_con; + NMSettingVrf *s_vrf; nm_assert_addr_family (addr_family); @@ -2325,6 +2358,28 @@ _get_route_table (NMDevice *self, } } + 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); @@ -2656,17 +2711,17 @@ concheck_periodic_schedule_do (NMDevice *self, int addr_family, gint64 now_ns) * 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_NS_PER_SECOND); + 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_NS_PER_MSEC), + (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_NS_PER_MSEC, + 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; @@ -2708,7 +2763,7 @@ concheck_periodic_schedule_set (NMDevice *self, int addr_family, ConcheckSchedul 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_ns_cached (&now_ns); + 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; @@ -2728,8 +2783,8 @@ concheck_periodic_schedule_set (NMDevice *self, int addr_family, ConcheckSchedul return; } - cur_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (priv->concheck_x[IS_IPv4].p_max_interval * NM_UTILS_NS_PER_SECOND); - nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); + 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) { @@ -2752,7 +2807,7 @@ concheck_periodic_schedule_set (NMDevice *self, int addr_family, ConcheckSchedul 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_ns_cached (&now_ns); + 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; @@ -2783,11 +2838,11 @@ concheck_periodic_schedule_set (NMDevice *self, int addr_family, ConcheckSchedul * pretty close to now_ns. * * We want to reschedule the timeout at exp_expiry (aka now) + cur_interval. */ - nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); - exp_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (old_interval * NM_UTILS_NS_PER_SECOND); - new_expiry = exp_expiry + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NS_PER_SECOND); + 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_NS_PER_SECOND); + 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) { @@ -2821,9 +2876,9 @@ concheck_periodic_schedule_set (NMDevice *self, int addr_family, ConcheckSchedul * 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_NS_PER_SECOND); - tdiff = NM_MAX (new_expiry - nm_utils_get_monotonic_timestamp_ns_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_NS_PER_SECOND); + 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); } @@ -3481,7 +3536,7 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) g_hash_table_remove_all (priv->ip6_saved_properties); - if (priv->dhcp4.client) { + if (priv->dhcp_data_4.client) { if (!nm_device_dhcp4_renew (self, FALSE)) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, @@ -3489,7 +3544,7 @@ nm_device_update_dynamic_ip_setup (NMDevice *self) return; } } - if (priv->dhcp6.client) { + if (priv->dhcp_data_6.client) { if (!nm_device_dhcp6_renew (self, FALSE)) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, @@ -3661,7 +3716,7 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) } else { gint64 now_ms, until_ms; - now_ms = nm_utils_get_monotonic_timestamp_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)", @@ -3757,7 +3812,7 @@ ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) if (nm_ndisc_get_node_type (ndisc) != NM_NDISC_NODE_TYPE_ROUTER) return; - now = nm_utils_get_monotonic_timestamp_s (); + 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), @@ -4800,19 +4855,19 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) _set_mtu (self, 0); if (priv->driver_version) { - g_clear_pointer (&priv->driver_version, g_free); + nm_clear_g_free (&priv->driver_version); _notify (self, PROP_DRIVER_VERSION); } if (priv->firmware_version) { - g_clear_pointer (&priv->firmware_version, g_free); + nm_clear_g_free (&priv->firmware_version); _notify (self, PROP_FIRMWARE_VERSION); } if (priv->udi) { - g_clear_pointer (&priv->udi, g_free); + nm_clear_g_free (&priv->udi); _notify (self, PROP_UDI); } if (priv->physical_port_id) { - g_clear_pointer (&priv->physical_port_id, g_free); + nm_clear_g_free (&priv->physical_port_id); _notify (self, PROP_PHYSICAL_PORT_ID); } @@ -4825,7 +4880,7 @@ nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) priv->hw_addr_type = HW_ADDR_TYPE_UNSET; if (nm_clear_g_free (&priv->hw_addr_perm)) _notify (self, PROP_PERM_HW_ADDRESS); - g_clear_pointer (&priv->hw_addr_initial, g_free); + nm_clear_g_free (&priv->hw_addr_initial); priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) @@ -5374,10 +5429,10 @@ nm_device_removed (NMDevice *self, gboolean 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->dhcp4.client) - nm_dhcp_client_stop (priv->dhcp4.client, FALSE); - if (priv->dhcp6.client) - nm_dhcp_client_stop (priv->dhcp6.client, FALSE); + 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); } } @@ -5456,7 +5511,8 @@ nm_device_set_enabled (NMDevice *self, gboolean enabled) NM_DEVICE_GET_CLASS (self)->set_enabled (self, enabled); } -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_autoconnect_blocked_flags_to_string, NMDeviceAutoconnectBlockedFlags, +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"), @@ -6380,7 +6436,7 @@ master_ready_cb (NMActiveConnection *active, nm_assert (nm_active_connection_get_master_ready (active)); if (priv->state == NM_DEVICE_STATE_PREPARE) - nm_device_activate_schedule_stage1_device_prepare (self); + nm_device_activate_schedule_stage1_device_prepare (self, FALSE); } static void @@ -6503,7 +6559,7 @@ sriov_params_cb (GError *error, gpointer data) nm_utils_user_data_unpack (data, &self, &plat_vfs); - if (nm_utils_error_is_cancelled (error, TRUE)) + if (nm_utils_error_is_cancelled_or_disposing (error)) return; priv = NM_DEVICE_GET_PRIVATE (self); @@ -6528,7 +6584,7 @@ sriov_params_cb (GError *error, gpointer data) priv->stage1_sriov_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare (self); + nm_device_activate_schedule_stage1_device_prepare (self, FALSE); } /* @@ -6668,26 +6724,22 @@ activate_stage1_device_prepare (NMDevice *self) if (master) master_ready (self, active); - activation_source_invoke_sync (self, activate_stage2_device_config, AF_INET); + nm_device_activate_schedule_stage2_device_config (self, TRUE); } -/* - * nm_device_activate_schedule_stage1_device_prepare - * - * Prepare a device for activation - * - */ void -nm_device_activate_schedule_stage1_device_prepare (NMDevice *self) +nm_device_activate_schedule_stage1_device_prepare (NMDevice *self, + gboolean do_sync) { - NMDevicePrivate *priv; - g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (NM_DEVICE_GET_PRIVATE (self)->act_request.obj); - priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->act_request.obj); + if (!do_sync) { + activation_source_schedule (self, activate_stage1_device_prepare, AF_INET); + return; + } - activation_source_schedule (self, activate_stage1_device_prepare, AF_INET); + activation_source_invoke_sync (self, activate_stage1_device_prepare, AF_INET); } static NMActStageReturn @@ -7009,10 +7061,11 @@ activate_stage2_device_config (NMDevice *self) if (!nm_device_sys_iface_state_is_external_or_assume (self)) { if (!nm_device_bring_up (self, FALSE, &no_firmware)) { - if (no_firmware) - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_FIRMWARE_MISSING); - else - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + nm_device_state_changed (self, + NM_DEVICE_STATE_FAILED, + no_firmware + ? NM_DEVICE_STATE_REASON_FIRMWARE_MISSING + : NM_DEVICE_STATE_REASON_CONFIG_FAILED); return; } } @@ -7050,18 +7103,18 @@ activate_stage2_device_config (NMDevice *self) nm_device_activate_schedule_stage3_ip_config_start (self); } -/* - * nm_device_activate_schedule_stage2_device_config - * - * Schedule setup of the hardware device - * - */ void -nm_device_activate_schedule_stage2_device_config (NMDevice *self) +nm_device_activate_schedule_stage2_device_config (NMDevice *self, + gboolean do_sync) { g_return_if_fail (NM_IS_DEVICE (self)); - activation_source_schedule (self, activate_stage2_device_config, AF_INET); + 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 @@ -7170,7 +7223,7 @@ acd_manager_probe_terminated (NMAcdManager *acd_manager, gpointer user_data) _NMLOG (result ? LOGL_DEBUG : LOGL_WARN, LOGD_DEVICE, "IPv4 DAD result: address %s is %s", - nm_utils_inet4_ntop (address->address, sbuf), + _nm_utils_inet4_ntop (address->address, sbuf), result ? "unique" : "duplicate"); } } @@ -7548,25 +7601,25 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - priv->dhcp4.was_active = FALSE; - nm_clear_g_source (&priv->dhcp4.grace_id); - priv->dhcp4.grace_pending = FALSE; - g_clear_pointer (&priv->dhcp4.pac_url, g_free); - g_clear_pointer (&priv->dhcp4.root_path, g_free); + 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); + nm_clear_g_free (&priv->dhcp4.root_path); - if (priv->dhcp4.client) { + if (priv->dhcp_data_4.client) { /* Stop any ongoing DHCP transaction on this device */ - nm_clear_g_signal_handler (priv->dhcp4.client, &priv->dhcp4.state_sigid); + 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->dhcp4.client, release); + nm_dhcp_client_stop (priv->dhcp_data_4.client, release); - g_clear_object (&priv->dhcp4.client); + g_clear_object (&priv->dhcp_data_4.client); } - if (priv->dhcp4.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp4.config); + if (priv->dhcp_data_4.config) { + nm_dbus_object_clear_and_unexport (&priv->dhcp_data_4.config); _notify (self, PROP_DHCP4_CONFIG); } } @@ -7811,7 +7864,7 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config, gboolean bound) * 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->dhcp4.client, &error)) { + if (bound && !nm_dhcp_client_accept (priv->dhcp_data_4.client, &error)) { _LOGW (LOGD_DHCP4, "error accepting lease: %s", error->message); return FALSE; } @@ -7825,22 +7878,78 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config, gboolean bound) } static gboolean -dhcp4_grace_period_expired (gpointer user_data) +dhcp_grace_period_expired (NMDevice *self, int addr_family) { - NMDevice *self = user_data; 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; - priv->dhcp4.grace_id = 0; - priv->dhcp4.grace_pending = FALSE; - _LOGI (LOGD_DHCP4, "DHCPv4: grace period expired"); + _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, AF_INET, + 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 = get_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) { @@ -7848,7 +7957,7 @@ dhcp4_fail (NMDevice *self, NMDhcpState dhcp_state) _LOGD (LOGD_DHCP4, "DHCPv4 failed (ip_state %s, was_active %d)", _ip_state_to_string (priv->ip_state_4), - priv->dhcp4.was_active); + priv->dhcp_data_4.was_active); /* The client is always left running after a failure. */ @@ -7871,43 +7980,21 @@ dhcp4_fail (NMDevice *self, NMDhcpState dhcp_state) * not active before. */ if ( dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp4.was_active && priv->ip_state_4 == NM_DEVICE_IP_STATE_CONF)) { + || (!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; } - /* In any other case (expired lease, assumed connection, etc.), - * wait for some time before failing the IP method. - */ - if (!priv->dhcp4.grace_pending) { - guint32 timeout; - - /* Start a grace period equal to the DHCP timeout multiplied - * by a constant factor. */ - timeout = get_dhcp_timeout (self, AF_INET); - if (timeout == NM_DHCP_TIMEOUT_INFINITY) { - _LOGI (LOGD_DHCP4, "DHCPv4: trying to acquire a new lease"); - } else { - timeout = dhcp_grace_period_from_timeout (timeout); - _LOGI (LOGD_DHCP4, - "DHCPv4: trying to acquire a new lease within %u seconds", - timeout); - nm_assert (!priv->dhcp4.grace_id); - priv->dhcp4.grace_id = g_timeout_add_seconds (timeout, - dhcp4_grace_period_expired, - self); - } - - priv->dhcp4.grace_pending = TRUE; + if (dhcp_grace_period_start (self, AF_INET)) goto clear_config; - } + return; clear_config: /* The previous configuration is no longer valid */ - if (priv->dhcp4.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp4.config); - priv->dhcp4.config = nm_dhcp4_config_new (); + 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); } } @@ -7921,7 +8008,7 @@ dhcp4_dad_cb (NMDevice *self, NMIP4Config **configs, gboolean success) nm_device_activate_schedule_ip_config_result (self, AF_INET, NM_IP_CONFIG_CAST (configs[1])); } else { - nm_dhcp_client_decline (priv->dhcp4.client, "Address conflict detected", NULL); + 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); } @@ -7954,8 +8041,8 @@ dhcp4_state_changed (NMDhcpClient *client, break; } - nm_clear_g_source (&priv->dhcp4.grace_id); - priv->dhcp4.grace_pending = FALSE; + 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 @@ -7970,7 +8057,7 @@ dhcp4_state_changed (NMDhcpClient *client, g_free (priv->dhcp4.root_path); priv->dhcp4.root_path = g_strdup (g_hash_table_lookup (options, "root_path")); - nm_dhcp4_config_set_options (priv->dhcp4.config, options); + 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) { @@ -8349,8 +8436,8 @@ dhcp4_start (NMDevice *self) s_ip4 = nm_connection_get_setting_ip4_config (connection); /* Clear old exported DHCP options */ - nm_dbus_object_clear_and_unexport (&priv->dhcp4.config); - priv->dhcp4.config = nm_dhcp4_config_new (); + 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) { @@ -8360,38 +8447,38 @@ dhcp4_start (NMDevice *self) client_id = dhcp4_get_client_id (self, connection, hwaddr); - g_warn_if_fail (priv->dhcp4.client == NULL); - priv->dhcp4.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)), - get_dhcp_hostname_flags (self, AF_INET), - client_id, - get_dhcp_timeout (self, AF_INET), - priv->dhcp_anycast_address, - NULL, - &error); - if (!priv->dhcp4.client) { + 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)), + get_dhcp_hostname_flags (self, AF_INET), + client_id, + get_dhcp_timeout (self, AF_INET), + priv->dhcp_anycast_address, + NULL, + &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->dhcp4.state_sigid = g_signal_connect (priv->dhcp4.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK (dhcp4_state_changed), - self); + 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->dhcp4.was_active = TRUE; + 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; @@ -8402,7 +8489,7 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - g_return_val_if_fail (priv->dhcp4.client != NULL, FALSE); + g_return_val_if_fail (priv->dhcp_data_4.client != NULL, FALSE); _LOGI (LOGD_DHCP4, "DHCPv4 lease renewal requested"); @@ -8422,7 +8509,7 @@ shared_ip_release (gpointer data) { g_hash_table_remove (shared_ips, data); if (!g_hash_table_size (shared_ips)) - g_clear_pointer (&shared_ips, g_hash_table_unref); + nm_clear_pointer (&shared_ips, g_hash_table_unref); } static NMIP4Config * @@ -8577,26 +8664,26 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - priv->dhcp6.was_active = FALSE; + priv->dhcp_data_6.was_active = FALSE; priv->dhcp6.mode = NM_NDISC_DHCP_LEVEL_NONE; applied_config_clear (&priv->dhcp6.ip6_config); - g_clear_pointer (&priv->dhcp6.event_id, g_free); - nm_clear_g_source (&priv->dhcp6.grace_id); - priv->dhcp6.grace_pending = FALSE; + 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->dhcp6.client) { - nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.state_sigid); - nm_clear_g_signal_handler (priv->dhcp6.client, &priv->dhcp6.prefix_sigid); + 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->dhcp6.client, release); + nm_dhcp_client_stop (priv->dhcp_data_6.client, release); - g_clear_object (&priv->dhcp6.client); + g_clear_object (&priv->dhcp_data_6.client); } - if (priv->dhcp6.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp6.config); + if (priv->dhcp_data_6.config) { + nm_dbus_object_clear_and_unexport (&priv->dhcp_data_6.config); _notify (self, PROP_DHCP6_CONFIG); } } @@ -8612,7 +8699,7 @@ dhcp6_lease_change (NMDevice *self) return FALSE; } - g_assert (priv->dhcp6.client); /* sanity check */ + g_assert (priv->dhcp_data_6.client); /* sanity check */ settings_connection = nm_device_get_settings_connection (self); g_assert (settings_connection); @@ -8631,23 +8718,6 @@ dhcp6_lease_change (NMDevice *self) return TRUE; } -static gboolean -dhcp6_grace_period_expired (gpointer user_data) -{ - NMDevice *self = user_data; - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - priv->dhcp6.grace_id = 0; - priv->dhcp6.grace_pending = FALSE; - _LOGI (LOGD_DHCP6, "DHCPv6: grace period expired"); - - nm_device_ip_method_failed (self, AF_INET6, - NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - /* If the device didn't fail, the DHCP client will continue */ - - return G_SOURCE_REMOVE; -} - static void dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) { @@ -8656,7 +8726,7 @@ dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) _LOGD (LOGD_DHCP6, "DHCPv6 failed (ip_state %s, was_active %d)", _ip_state_to_string (priv->ip_state_6), - priv->dhcp6.was_active); + priv->dhcp_data_6.was_active); /* The client is always left running after a failure. */ @@ -8682,36 +8752,13 @@ dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) * not active before. */ if ( dhcp_state == NM_DHCP_STATE_TERMINATED - || (!priv->dhcp6.was_active && priv->ip_state_6 == NM_DEVICE_IP_STATE_CONF)) { + || (!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; } - /* In any other case (expired lease, assumed connection, etc.), - * wait for some time before failing the IP method. - */ - if (!priv->dhcp6.grace_pending) { - guint32 timeout; - - /* Start a grace period equal to the DHCP timeout multiplied - * by a constant factor. */ - timeout = get_dhcp_timeout (self, AF_INET6); - if (timeout == NM_DHCP_TIMEOUT_INFINITY) - _LOGI (LOGD_DHCP6, "DHCPv6: trying to acquire a new lease"); - else { - timeout = dhcp_grace_period_from_timeout (timeout); - _LOGI (LOGD_DHCP6, - "DHCPv6: trying to acquire a new lease within %u seconds", - timeout); - nm_assert (!priv->dhcp6.grace_id); - priv->dhcp6.grace_id = g_timeout_add_seconds (timeout, - dhcp6_grace_period_expired, - self); - } - - priv->dhcp6.grace_pending = TRUE; + 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); @@ -8722,9 +8769,9 @@ dhcp6_fail (NMDevice *self, NMDhcpState dhcp_state) clear_config: /* The previous configuration is no longer valid */ - if (priv->dhcp6.config) { - nm_dbus_object_clear_and_unexport (&priv->dhcp6.config); - priv->dhcp6.config = nm_dhcp6_config_new (); + 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); } } @@ -8748,8 +8795,8 @@ dhcp6_state_changed (NMDhcpClient *client, switch (state) { case NM_DHCP_STATE_BOUND: case NM_DHCP_STATE_EXTENDED: - nm_clear_g_source (&priv->dhcp6.grace_id); - priv->dhcp6.grace_pending = FALSE; + 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. @@ -8764,11 +8811,11 @@ dhcp6_state_changed (NMDhcpClient *client, 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 { - g_clear_pointer (&priv->dhcp6.event_id, g_free); + 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_dhcp6_config_set_options (priv->dhcp6.config, options); + nm_dhcp_config_set_options (priv->dhcp_data_6.config, options); _notify (self, PROP_DHCP6_CONFIG); } else applied_config_clear (&priv->dhcp6.ip6_config); @@ -8999,7 +9046,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole duid_out = generate_duid_ll (arp_type, hwaddr_bin, hwaddr_len); else { duid_out = generate_duid_llt (arp_type, hwaddr_bin, hwaddr_len, - nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NS_PER_SECOND); + nm_utils_host_id_get_timestamp_ns () / NM_UTILS_NSEC_PER_SEC); } goto out_good; @@ -9094,7 +9141,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboole * 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_NS_PER_SECOND; + 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. */ @@ -9191,48 +9238,48 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) iaid = dhcp_get_iaid (self, AF_INET6, connection, &iaid_explicit); duid = dhcp6_get_duid (self, connection, hwaddr, &enforce_duid); - priv->dhcp6.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), - hwaddr, - bcast_hwaddr, - &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), - get_dhcp_hostname_flags (self, AF_INET6), - duid, - enforce_duid, - iaid, - iaid_explicit, - get_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->dhcp6.client) { + 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), + hwaddr, + bcast_hwaddr, + &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), + get_dhcp_hostname_flags (self, AF_INET6), + duid, + enforce_duid, + iaid, + iaid_explicit, + get_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->dhcp6.was_active = TRUE; + priv->dhcp_data_6.was_active = TRUE; return FALSE; } - priv->dhcp6.state_sigid = g_signal_connect (priv->dhcp6.client, - NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, - G_CALLBACK (dhcp6_state_changed), - self); - priv->dhcp6.prefix_sigid = g_signal_connect (priv->dhcp6.client, + 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->dhcp6.was_active = TRUE; + priv->dhcp_data_6.was_active = TRUE; return TRUE; } @@ -9243,12 +9290,12 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; - nm_dbus_object_clear_and_unexport (&priv->dhcp6.config); - priv->dhcp6.config = nm_dhcp6_config_new (); + 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); - g_clear_pointer (&priv->dhcp6.event_id, g_free); + nm_clear_g_free (&priv->dhcp6.event_id); connection = nm_device_get_applied_connection (self); g_return_val_if_fail (connection, FALSE); @@ -9273,7 +9320,7 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - g_return_val_if_fail (priv->dhcp6.client != NULL, FALSE); + g_return_val_if_fail (priv->dhcp_data_6.client != NULL, FALSE); _LOGI (LOGD_DHCP6, "DHCPv6 lease renewal requested"); @@ -9297,7 +9344,7 @@ nm_device_request_ip6_prefixes (NMDevice *self, int needed_prefixes) priv->dhcp6.needed_prefixes = needed_prefixes; - if (priv->dhcp6.client) { + 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 { @@ -9330,7 +9377,7 @@ nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet) 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), + _nm_utils_inet6_ntop (&address.address, sbuf), subnet->preferred); /* This also updates the ndisc if there are actual changes. */ @@ -9510,7 +9557,7 @@ check_and_add_ipv6ll_addr (NMDevice *self) } _LOGD (LOGD_IP6, "linklocal6: generated %s IPv6LL address %s", - addr_type, nm_utils_inet6_ntop (&lladdr, sbuf)); + 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); @@ -9692,6 +9739,17 @@ _set_mtu (NMDevice *self, guint32 mtu) } } +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) { @@ -9851,10 +9909,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) } if (mtu_desired && mtu_desired != mtu_plat) { - int r; - - r = nm_platform_link_set_mtu (nm_device_get_platform (self), ifindex, mtu_desired); - if (r == -NME_PL_CANT_SET_MTU) { + 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", @@ -9864,7 +9919,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) ? "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_ms () + CARRIER_WAIT_TIME_AFTER_MTU_MS; + 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 ()) { @@ -9880,7 +9935,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config) : ""); success = FALSE; } - priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_ms () + CARRIER_WAIT_TIME_AFTER_MTU_MS; + priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_msec () + CARRIER_WAIT_TIME_AFTER_MTU_MS; } } @@ -10152,7 +10207,7 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) nm_assert (!applied_config_get_current (&priv->ac_ip6_config)); applied_config_clear (&priv->ac_ip6_config); - g_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); + 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)); @@ -10203,7 +10258,7 @@ addrconf6_cleanup (NMDevice *self) nm_clear_g_signal_handler (priv->ndisc, &priv->ndisc_timeout_id); applied_config_clear (&priv->ac_ip6_config); - g_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); + nm_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); nm_clear_g_source (&priv->rt6_temporary_not_available_id); g_clear_object (&priv->ndisc); } @@ -10752,7 +10807,7 @@ fw_change_zone_cb (NMFirewallManager *firewall_manager, priv->fw_call = NULL; - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; switch (priv->fw_state) { @@ -10996,10 +11051,10 @@ start_sharing (NMDevice *self, NMIP4Config *config, GError **error) g_return_val_if_fail (req, FALSE); netmask = _nm_utils_ip4_prefix_to_netmask (ip4_addr->plen); - nm_utils_inet4_ntop (netmask, str_mask); + _nm_utils_inet4_ntop (netmask, str_mask); network = ip4_addr->address & netmask; - nm_utils_inet4_ntop (network, str_addr); + _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); @@ -11153,10 +11208,10 @@ activate_stage5_ip_config_result_4 (NMDevice *self) } } - if (priv->dhcp4.client) { + if (priv->dhcp_data_4.client) { gs_free_error GError *error = NULL; - if (!nm_dhcp_client_accept (priv->dhcp4.client, &error)) { + 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); @@ -11168,7 +11223,7 @@ activate_stage5_ip_config_result_4 (NMDevice *self) /* If IPv4 wasn't the first to complete, and DHCP was used, then ensure * dispatcher scripts get the DHCP lease information. */ - if ( priv->dhcp4.client + 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, @@ -11710,8 +11765,8 @@ nm_device_reactivate_ip4_config (NMDevice *self, nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->dev2_ip_config_4.orig, nm_device_get_route_metric (self, AF_INET)); } - if (priv->dhcp4.client) { - nm_dhcp_client_set_route_metric (priv->dhcp4.client, + 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)); } } @@ -11784,8 +11839,8 @@ nm_device_reactivate_ip6_config (NMDevice *self, nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->dev2_ip_config_6.orig, nm_device_get_route_metric (self, AF_INET6)); } - if (priv->dhcp6.client) { - nm_dhcp_client_set_route_metric (priv->dhcp6.client, + 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)); } } @@ -12318,7 +12373,7 @@ _rt6_temporary_not_available_set (NMDevice *self, if ( !temporary_not_available || !temporary_not_available->len) { /* nothing outstanding. Clear tracking the routes. */ - g_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); + nm_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); nm_clear_g_source (&priv->rt6_temporary_not_available_id); return success; } @@ -12334,7 +12389,7 @@ _rt6_temporary_not_available_set (NMDevice *self, nm_g_slice_free_fcn (IP6RoutesTemporaryNotAvailableData)); } - now_ms = nm_utils_get_monotonic_timestamp_ms (); + now_ms = nm_utils_get_monotonic_timestamp_msec (); oldest_ms = now_ms; for (i = 0; i < temporary_not_available->len; i++) { @@ -12547,7 +12602,7 @@ _device_activate (NMDevice *self, NMActRequest *req) act_request_set (self, req); - nm_device_activate_schedule_stage1_device_prepare (self); + nm_device_activate_schedule_stage1_device_prepare (self, FALSE); } static void @@ -12771,12 +12826,16 @@ nm_device_set_proxy_config (NMDevice *self, const char *pac_url) } /* IP Configuration stuff */ -NMDhcp4Config * -nm_device_get_dhcp4_config (NMDevice *self) +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); - return NM_DEVICE_GET_PRIVATE (self)->dhcp4.config; + nm_assert_addr_family (addr_family); + + return NM_DEVICE_GET_PRIVATE (self)->dhcp_data_x[IS_IPv4].config; } NMIP4Config * @@ -13030,14 +13089,6 @@ nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *co _LOGW (LOGD_IP6, "failed to set VPN routes for device"); } -NMDhcp6Config * -nm_device_get_dhcp6_config (NMDevice *self) -{ - g_return_val_if_fail (NM_IS_DEVICE (self), NULL); - - return NM_DEVICE_GET_PRIVATE (self)->dhcp6.config; -} - NMIP6Config * nm_device_get_ip6_config (NMDevice *self) { @@ -13114,8 +13165,8 @@ ip_check_gw_ping_cleanup (NMDevice *self) priv->gw_ping.pid = 0; } - g_clear_pointer (&priv->gw_ping.binary, g_free); - g_clear_pointer (&priv->gw_ping.address, g_free); + nm_clear_g_free (&priv->gw_ping.binary); + nm_clear_g_free (&priv->gw_ping.address); } static gboolean @@ -13280,14 +13331,14 @@ nm_device_start_ip_check (NMDevice *self) 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); + _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); + _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; } @@ -13371,14 +13422,14 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) device_is_up = nm_device_is_up (self); if (block && !device_is_up) { - gint64 wait_until = nm_utils_get_monotonic_timestamp_us () + 10000 /* microseconds */; + 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_us () < wait_until); + } while (!device_is_up && nm_utils_get_monotonic_timestamp_usec () < wait_until); } if (!device_is_up) { @@ -13413,7 +13464,7 @@ nm_device_bring_up (NMDevice *self, gboolean block, gboolean *no_firmware) if (!priv->carrier) nm_device_add_pending_action (self, NM_PENDING_ACTION_CARRIER_WAIT, FALSE); - now_ms = nm_utils_get_monotonic_timestamp_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_wait_id = g_timeout_add (until_ms - now_ms, carrier_wait_timeout, self); } @@ -13456,14 +13507,14 @@ nm_device_take_down (NMDevice *self, gboolean block) device_is_up = nm_device_is_up (self); if (block && device_is_up) { - gint64 wait_until = nm_utils_get_monotonic_timestamp_us () + 10000 /* microseconds */; + 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_us () < wait_until); + } while (device_is_up && nm_utils_get_monotonic_timestamp_usec () < wait_until); } if (device_is_up) { @@ -15123,7 +15174,7 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->ipv6ll_has = FALSE; memset (&priv->ipv6ll_addr, 0, sizeof (priv->ipv6ll_addr)); - g_clear_pointer (&priv->rt6_temporary_not_available, g_hash_table_unref); + 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); @@ -15255,7 +15306,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean (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_ms () + CARRIER_WAIT_TIME_AFTER_MTU_MS; + 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]; @@ -15366,11 +15417,11 @@ nm_device_spawn_iface_helper (NMDevice *self) if (nm_setting_ip_config_get_may_fail (s_ip4) == FALSE) g_ptr_array_add (argv, g_strdup ("--dhcp4-required")); - if (priv->dhcp4.client) { + if (priv->dhcp_data_4.client) { const char *hostname; GBytes *client_id; - client_id = nm_dhcp_client_get_client_id (priv->dhcp4.client); + 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, @@ -15381,9 +15432,9 @@ nm_device_spawn_iface_helper (NMDevice *self) NULL)); } - hostname = nm_dhcp_client_get_hostname (priv->dhcp4.client); + hostname = nm_dhcp_client_get_hostname (priv->dhcp_data_4.client); if (hostname) { - if (nm_dhcp_client_get_use_fqdn (priv->dhcp4.client)) + 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")); @@ -15505,7 +15556,7 @@ sriov_deactivate_cb (GError *error, gpointer user_data) NMDevice *self; gpointer reason; - if (nm_utils_error_is_cancelled (error, TRUE)) + if (nm_utils_error_is_cancelled_or_disposing (error)) return; nm_utils_user_data_unpack (user_data, &self, &reason); @@ -15556,6 +15607,31 @@ deactivate_dispatcher_complete (NMDispatcherCallId *call_id, gpointer user_data) 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, @@ -15573,7 +15649,7 @@ _set_state_full (NMDevice *self, { NMDevicePrivate *priv; NMDeviceState old_state; - NMActRequest *req; + gs_unref_object NMActRequest *req = NULL; gboolean no_firmware = FALSE; NMSettingsConnection *sett_conn; NMSettingSriov *s_sriov; @@ -15915,8 +15991,9 @@ _set_state_full (NMDevice *self, /* 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); + 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) @@ -15924,10 +16001,6 @@ _set_state_full (NMDevice *self, concheck_update_interval (self, AF_INET, concheck_now); concheck_update_interval (self, AF_INET6, concheck_now); - /* Dispose of the cached activation request */ - if (req) - g_object_unref (req); - priv->in_state_changed = FALSE; nm_device_remove_pending_action (self, NM_PENDING_ACTION_IN_STATE_CHANGE, @@ -16376,8 +16449,10 @@ _hw_addr_set (NMDevice *self, } if ( priv->hw_addr_len - && priv->hw_addr_len != addr_len) - g_return_val_if_reached (FALSE); + && 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); @@ -16432,7 +16507,7 @@ again: * * wait/poll up to 100 msec until it changes. */ - poll_end = nm_utils_get_monotonic_timestamp_us () + (100 * 1000); + 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; @@ -16443,7 +16518,7 @@ again: break; handle_wait: - now = nm_utils_get_monotonic_timestamp_us (); + now = nm_utils_get_monotonic_timestamp_usec (); if (now < poll_end) { g_usleep (NM_MIN (poll_end - now, 500)); continue; @@ -16920,6 +16995,297 @@ _activation_func_to_string (ActivationHandleFunc func) /*****************************************************************************/ 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_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_uint (value, priv->ip4_address); + 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; @@ -16994,7 +17360,7 @@ constructor (GType type, gsize l; if (!_nm_utils_hwaddr_aton (priv->hw_addr_perm, buf, sizeof (buf), &l)) { - g_clear_pointer (&priv->hw_addr_perm, g_free); + nm_clear_g_free (&priv->hw_addr_perm); g_return_val_if_reached (object); } @@ -17160,7 +17526,7 @@ finalize (GObject *object) g_free (priv->hw_addr_initial); g_slist_free (priv->pending_actions); g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref); - g_clear_pointer (&priv->physical_port_id, g_free); + nm_clear_g_free (&priv->physical_port_id); g_free (priv->udi); g_free (priv->iface); g_free (priv->ip_iface); @@ -17188,306 +17554,7 @@ finalize (GObject *object) g_object_unref (priv->netns); } -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_DRIVER_VERSION: - /* construct-only */ - priv->driver_version = g_value_dup_string (value); - break; - case PROP_FIRMWARE_VERSION: - /* construct-only */ - priv->firmware_version = g_value_dup_string (value); - break; - case PROP_IP4_ADDRESS: - priv->ip4_address = g_value_get_uint (value); - break; - case PROP_MANAGED: - 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: - 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_FIRMWARE_MISSING: - /* construct-only */ - priv->firmware_missing = g_value_get_boolean (value); - 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_WIFI_P2P); - 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_REFRESH_RATE_MS: - _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 -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_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_uint (value, priv->ip4_address); - 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->dhcp4.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->dhcp6.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_REFRESH_RATE_MS: - g_value_set_uint (value, priv->stats.refresh_rate_ms); - break; - case PROP_TX_BYTES: - g_value_set_uint64 (value, priv->stats.tx_bytes); - break; - case PROP_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 const GDBusSignalInfo signal_info_state_changed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( "StateChanged", @@ -17572,6 +17639,7 @@ static const NMDBusInterfaceInfoExtended interface_info_device = { 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), ), ), }; @@ -17631,6 +17699,7 @@ nm_device_class_init (NMDeviceClass *klass) 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, "", "", @@ -17655,12 +17724,12 @@ nm_device_class_init (NMDeviceClass *klass) obj_properties[PROP_DRIVER_VERSION] = g_param_spec_string (NM_DEVICE_DRIVER_VERSION, "", "", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_FIRMWARE_VERSION] = g_param_spec_string (NM_DEVICE_FIRMWARE_VERSION, "", "", NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_CAPABILITIES] = g_param_spec_uint (NM_DEVICE_CAPABILITIES, "", "", @@ -17680,27 +17749,27 @@ nm_device_class_init (NMDeviceClass *klass) obj_properties[PROP_IP4_ADDRESS] = g_param_spec_uint (NM_DEVICE_IP4_ADDRESS, "", "", 0, G_MAXUINT32, 0, /* FIXME */ - G_PARAM_READWRITE | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_IP4_CONFIG] = g_param_spec_string (NM_DEVICE_IP4_CONFIG, "", "", NULL, - G_PARAM_READWRITE | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_DHCP4_CONFIG] = g_param_spec_string (NM_DEVICE_DHCP4_CONFIG, "", "", NULL, - G_PARAM_READWRITE | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_IP6_CONFIG] = g_param_spec_string (NM_DEVICE_IP6_CONFIG, "", "", NULL, - G_PARAM_READWRITE | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_DHCP6_CONFIG] = g_param_spec_string (NM_DEVICE_DHCP6_CONFIG, "", "", NULL, - G_PARAM_READWRITE | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_STATE] = g_param_spec_uint (NM_DEVICE_STATE, "", "", @@ -17731,17 +17800,17 @@ nm_device_class_init (NMDeviceClass *klass) obj_properties[PROP_MANAGED] = g_param_spec_boolean (NM_DEVICE_MANAGED, "", "", FALSE, - G_PARAM_READWRITE | + 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 | + 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_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_NM_PLUGIN_MISSING] = g_param_spec_boolean (NM_DEVICE_NM_PLUGIN_MISSING, "", "", @@ -17822,17 +17891,17 @@ nm_device_class_init (NMDeviceClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_REFRESH_RATE_MS] = + obj_properties[PROP_STATISTICS_REFRESH_RATE_MS] = g_param_spec_uint (NM_DEVICE_STATISTICS_REFRESH_RATE_MS, "", "", 0, UINT32_MAX, 0, - G_PARAM_READWRITE | + G_PARAM_READWRITE | /* via D-Bus */ G_PARAM_STATIC_STRINGS); - obj_properties[PROP_TX_BYTES] = + 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_RX_BYTES] = + obj_properties[PROP_STATISTICS_RX_BYTES] = g_param_spec_uint64 (NM_DEVICE_STATISTICS_RX_BYTES, "", "", 0, UINT64_MAX, 0, G_PARAM_READABLE | diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 8c6c856e..c18301b2 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -444,6 +444,8 @@ typedef struct _NMDeviceClass { gboolean (* can_update_from_platform_link) (NMDevice *self, const NMPlatformLink *plink); + gboolean (* set_platform_mtu) (NMDevice *self, guint32 mtu); + /* Controls, whether to call act_stage2_config() callback also for assuming * a device or for external activations. In this case, act_stage2_config() must * take care not to touch the device's configuration. */ @@ -504,8 +506,7 @@ const char * nm_device_get_initial_hw_address (NMDevice *dev); NMProxyConfig * nm_device_get_proxy_config (NMDevice *dev); -NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev); -NMDhcp6Config * nm_device_get_dhcp6_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, @@ -883,4 +884,6 @@ struct _NMBtVTableNetworkServer { 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 index 4c9e7705..b9caed50 100644 --- a/src/devices/nm-lldp-listener.c +++ b/src/devices/nm-lldp-listener.c @@ -17,7 +17,7 @@ #include "systemd/nm-sd.h" #define MAX_NEIGHBORS 4096 -#define MIN_UPDATE_INTERVAL_NS (2 * NM_UTILS_NS_PER_SECOND) +#define MIN_UPDATE_INTERVAL_NS (2 * NM_UTILS_NSEC_PER_SEC) #define LLDP_MAC_NEAREST_BRIDGE ((const struct ether_addr *) ((uint8_t[ETH_ALEN]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e })) #define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE ((const struct ether_addr *) ((uint8_t[ETH_ALEN]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 })) @@ -154,7 +154,8 @@ ether_addr_equal (const struct ether_addr *a1, const struct ether_addr *a2) /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_lldp_attr_id_to_name, LldpAttrId, +static +NM_UTILS_LOOKUP_STR_DEFINE (_lldp_attr_id_to_name, LldpAttrId, NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_PORT_DESCRIPTION, NM_LLDP_ATTR_PORT_DESCRIPTION), NM_UTILS_LOOKUP_STR_ITEM (LLDP_ATTR_ID_SYSTEM_NAME, NM_LLDP_ATTR_SYSTEM_NAME), @@ -174,7 +175,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_lldp_attr_id_to_name, LldpAttrId, NM_UTILS_LOOKUP_ITEM_IGNORE (_LLDP_ATTR_ID_COUNT), ); -_NM_UTILS_LOOKUP_DEFINE (static, _lldp_attr_id_to_type, LldpAttrId, LldpAttrType, +static +NM_UTILS_LOOKUP_DEFINE (_lldp_attr_id_to_type, LldpAttrId, LldpAttrType, NM_UTILS_LOOKUP_DEFAULT_WARN (LLDP_ATTR_TYPE_NONE), NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_PORT_DESCRIPTION, LLDP_ATTR_TYPE_STRING), NM_UTILS_LOOKUP_ITEM (LLDP_ATTR_ID_SYSTEM_NAME, LLDP_ATTR_TYPE_STRING), @@ -347,7 +349,7 @@ lldp_neighbor_free (LldpNeighbor *neighbor) ; } } - g_clear_pointer (&neighbor->variant, g_variant_unref); + nm_clear_pointer (&neighbor->variant, g_variant_unref); g_slice_free (LldpNeighbor, neighbor); } } @@ -828,7 +830,7 @@ data_changed_timeout (gpointer user_data) priv = NM_LLDP_LISTENER_GET_PRIVATE (self); priv->ratelimit_id = 0; - priv->ratelimit_next = nm_utils_get_monotonic_timestamp_ns() + MIN_UPDATE_INTERVAL_NS; + priv->ratelimit_next = nm_utils_get_monotonic_timestamp_nsec() + MIN_UPDATE_INTERVAL_NS; data_changed_notify (self, priv); return G_SOURCE_REMOVE; } @@ -839,13 +841,13 @@ data_changed_schedule (NMLldpListener *self) NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self); gint64 now; - now = nm_utils_get_monotonic_timestamp_ns (); + now = nm_utils_get_monotonic_timestamp_nsec (); if (now >= priv->ratelimit_next) { nm_clear_g_source (&priv->ratelimit_id); priv->ratelimit_next = now + MIN_UPDATE_INTERVAL_NS; data_changed_notify (self, priv); } else if (!priv->ratelimit_id) - priv->ratelimit_id = g_timeout_add (NM_UTILS_NS_TO_MSEC_CEIL (priv->ratelimit_next - now), data_changed_timeout, self); + priv->ratelimit_id = g_timeout_add (NM_UTILS_NSEC_TO_MSEC_CEIL (priv->ratelimit_next - now), data_changed_timeout, self); } static void diff --git a/src/devices/ovs/meson.build b/src/devices/ovs/meson.build index 27e1b4d0..8457e68a 100644 --- a/src/devices/ovs/meson.build +++ b/src/devices/ovs/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + sources = files( 'nm-device-ovs-bridge.c', 'nm-device-ovs-interface.c', diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index 2868dee0..951b5788 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -121,6 +121,43 @@ _is_internal_interface (NMDevice *device) 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, @@ -351,4 +388,6 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) 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-ovsdb.c b/src/devices/ovs/nm-ovsdb.c index ec4f5c74..b6550b25 100644 --- a/src/devices/ovs/nm-ovsdb.c +++ b/src/devices/ovs/nm-ovsdb.c @@ -64,6 +64,7 @@ typedef struct { GHashTable *ports; /* port uuid => OpenvswitchPort */ GHashTable *bridges; /* bridge uuid => OpenvswitchBridge */ char *db_uuid; + guint num_failures; } NMOvsdbPrivate; struct _NMOvsdb { @@ -87,7 +88,7 @@ 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 is_disposing); +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); @@ -103,6 +104,7 @@ typedef enum { OVSDB_MONITOR, OVSDB_ADD_INTERFACE, OVSDB_DEL_INTERFACE, + OVSDB_SET_INTERFACE_MTU, } OvsdbCommand; typedef struct { @@ -112,7 +114,10 @@ typedef struct { OvsdbMethodCallback callback; gpointer user_data; union { - char *ifname; + struct { + char *ifname; + guint32 mtu; + }; struct { NMConnection *bridge; NMConnection *port; @@ -123,6 +128,8 @@ typedef struct { }; } OvsdbMethodCall; +#define OVSDB_MAX_FAILURES 3 + static void _call_trace (const char *comment, OvsdbMethodCall *call, json_t *msg) { @@ -154,6 +161,13 @@ _call_trace (const char *comment, OvsdbMethodCall *call, json_t *msg) 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; } if (msg) @@ -172,7 +186,8 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command, const char *ifname, NMConnection *bridge, NMConnection *port, NMConnection *interface, NMDevice *bridge_device, NMDevice *interface_device, - OvsdbMethodCallback callback, gpointer user_data) + guint32 mtu, OvsdbMethodCallback callback, gpointer user_data, + gboolean add_first) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); OvsdbMethodCall *call; @@ -180,8 +195,13 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command, /* Ensure we're not unsynchronized before we queue the method call. */ ovsdb_try_connect (self); - g_array_set_size (priv->calls, priv->calls->len + 1); - call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1); + 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; @@ -200,6 +220,10 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command, case OVSDB_DEL_INTERFACE: call->ifname = g_strdup (ifname); break; + case OVSDB_SET_INTERFACE_MTU: + call->ifname = g_strdup (ifname); + call->mtu = mtu; + break; } _call_trace ("enqueue", call, NULL); @@ -338,11 +362,20 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_ gs_free char *cloned_mac = NULL; gs_free_error GError *error = NULL; 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); + } + if (!nm_device_hw_addr_get_cloned (interface_device, interface, FALSE, @@ -384,6 +417,9 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *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", @@ -820,6 +856,22 @@ ovsdb_next_command (NMOvsdb *self) "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); @@ -1153,7 +1205,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg) "result", &result, "error", &error) == -1) { _LOGW ("couldn't grok the message: %s", json_error.text); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); return; } @@ -1164,7 +1216,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg) /* It's a method call! */ if (!params) { _LOGW ("a method call with no params: '%s'", method); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); return; } @@ -1184,13 +1236,13 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg) /* 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); + 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); + ovsdb_disconnect (self, FALSE, FALSE); return; } /* Cool, we found a corresponding call. Finish it. */ @@ -1208,6 +1260,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg) 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. */ @@ -1266,9 +1319,11 @@ ovsdb_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) 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, FALSE); + ovsdb_disconnect (self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE); return; } @@ -1314,9 +1369,11 @@ ovsdb_write_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) 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, FALSE); + ovsdb_disconnect (self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE); return; } @@ -1359,7 +1416,7 @@ ovsdb_write (NMOvsdb *self) * puts us back in sync. */ static void -ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing) +ovsdb_disconnect (NMOvsdb *self, gboolean retry, gboolean is_disposing) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); OvsdbMethodCall *call; @@ -1367,18 +1424,26 @@ ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing) gpointer user_data; gs_free_error GError *error = NULL; + nm_assert (!retry || !is_disposing); + if (!priv->client) return; - _LOGD ("disconnecting from ovsdb"); - nm_utils_error_set_cancelled (&error, is_disposing, "NMOvsdb"); + _LOGD ("disconnecting from ovsdb, retry %d", retry); - 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); + 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; @@ -1386,17 +1451,20 @@ ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing) g_string_truncate (priv->output, 0); g_clear_object (&priv->client); g_clear_object (&priv->conn); - g_clear_pointer (&priv->db_uuid, g_free); + 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 (error, TRUE)) { + if (!nm_utils_error_is_cancelled_or_disposing (error)) { _LOGI ("%s", error->message); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); } return; } @@ -1420,7 +1488,7 @@ _client_connect_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) _LOGI ("%s", error->message); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); g_clear_error (&error); return; } @@ -1461,7 +1529,8 @@ ovsdb_try_connect (NMOvsdb *self) /* 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, _monitor_bridges_cb, NULL); + NULL, NULL, NULL, NULL, NULL, 0, + _monitor_bridges_cb, NULL, TRUE); } /*****************************************************************************/ @@ -1499,11 +1568,8 @@ out: g_slice_free (OvsdbCall, 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) +static OvsdbCall * +ovsdb_call_new (NMOvsdbCallback callback, gpointer user_data) { OvsdbCall *call; @@ -1511,24 +1577,43 @@ nm_ovsdb_add_interface (NMOvsdb *self, 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, - _transact_cb, call); + 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) { - OvsdbCall *call; - - call = g_slice_new (OvsdbCall); - call->callback = callback; - call->user_data = user_data; - ovsdb_call_method (self, OVSDB_DEL_INTERFACE, ifname, - NULL, NULL, NULL, NULL, NULL, _transact_cb, call); + 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); } /*****************************************************************************/ @@ -1549,7 +1634,8 @@ _clear_call (gpointer data) g_clear_object (&call->interface_device); break; case OVSDB_DEL_INTERFACE: - g_clear_pointer (&call->ifname, g_free); + case OVSDB_SET_INTERFACE_MTU: + nm_clear_g_free (&call->ifname); break; } } @@ -1609,7 +1695,7 @@ dispose (GObject *object) NMOvsdb *self = NM_OVSDB (object); NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); - ovsdb_disconnect (self, TRUE); + ovsdb_disconnect (self, FALSE, TRUE); if (priv->input) { g_string_free (priv->input, TRUE); @@ -1624,9 +1710,9 @@ dispose (GObject *object) priv->calls = NULL; } - g_clear_pointer (&priv->bridges, g_hash_table_destroy); - g_clear_pointer (&priv->ports, g_hash_table_destroy); - g_clear_pointer (&priv->interfaces, g_hash_table_destroy); + 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); } diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h index 59f46206..72a2dc73 100644 --- a/src/devices/ovs/nm-ovsdb.h +++ b/src/devices/ovs/nm-ovsdb.h @@ -34,4 +34,7 @@ void nm_ovsdb_add_interface (NMOvsdb *self, 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 index 0e63183b..c2b77cb9 100644 --- a/src/devices/team/meson.build +++ b/src/devices/team/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + sources = files( 'nm-device-team.c', 'nm-team-factory.c', diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index a0749c21..06f8840d 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -416,7 +416,7 @@ teamd_dbus_appeared (GDBusConnection *connection, } priv->stage1_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -932,7 +932,7 @@ dispose (GObject *object) } teamd_cleanup (self, TRUE); - g_clear_pointer (&priv->config, g_free); + nm_clear_g_free (&priv->config); G_OBJECT_CLASS (nm_device_team_parent_class)->dispose (object); } diff --git a/src/devices/tests/meson.build b/src/devices/tests/meson.build index bb53d1ee..1ddd4f85 100644 --- a/src/devices/tests/meson.build +++ b/src/devices/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_units = [ 'test-acd', 'test-lldp', diff --git a/src/devices/tests/test-acd.c b/src/devices/tests/test-acd.c index da5e4f2d..32d6f669 100644 --- a/src/devices/tests/test-acd.c +++ b/src/devices/tests/test-acd.c @@ -157,7 +157,7 @@ again: } g_error ("expected check for address #%d (%s) to %s, but it didn't", - i, nm_utils_inet4_ntop (info->addresses[i], sbuf), + i, _nm_utils_inet4_ntop (info->addresses[i], sbuf), info->expected_result[i] ? "detect no duplicated" : "detect a duplicate"); } } diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index bd71c9e3..8fc4ad67 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -501,7 +501,7 @@ test_recv (TestRecvFixture *fixture, gconstpointer user_data) data->check (loop, listener); nm_clear_g_source (&sd_id); - g_clear_pointer (&loop, g_main_loop_unref); + nm_clear_pointer (&loop, g_main_loop_unref); } static void diff --git a/src/devices/wifi/meson.build b/src/devices/wifi/meson.build index 6566f201..00404c71 100644 --- a/src/devices/wifi/meson.build +++ b/src/devices/wifi/meson.build @@ -1,28 +1,38 @@ -common_sources = files( - 'nm-wifi-ap.c', - 'nm-wifi-p2p-peer.c', - 'nm-wifi-utils.c', -) - -sources = common_sources + files( - 'nm-device-olpc-mesh.c', - 'nm-device-wifi-p2p.c', - 'nm-device-wifi.c', - 'nm-wifi-common.c', - 'nm-wifi-factory.c', -) +# SPDX-License-Identifier: LGPL-2.1+ +iwd_sources = files() if enable_iwd - sources += files( + 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: sources, - dependencies: daemon_nm_default_dep, + 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, @@ -43,8 +53,8 @@ if enable_tests exe = executable( test_unit, - ['tests/' + test_unit + '.c'] + common_sources, - dependencies: libnetwork_manager_test_dep, + 'tests/' + test_unit + '.c', + dependencies: [ libnetwork_manager_test_dep, libnm_wifi_base_dep ], c_args: test_c_flags, ) diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 6b587e3f..3c1d5b22 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -7,24 +7,26 @@ #include "nm-device-iwd.h" -#include "nm-libnm-core-intern/nm-common-macros.h" -#include "devices/nm-device.h" #include "devices/nm-device-private.h" -#include "nm-utils.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.h" #include "nm-setting-wireless-security.h" -#include "nm-setting-8021x.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 "nm-wifi-utils.h" -#include "nm-wifi-common.h" -#include "nm-core-internal.h" -#include "nm-config.h" -#include "nm-iwd-manager.h" -#include "nm-dbus-manager.h" -#include "nm-std-aux/nm-dbus-compat.h" +#include "supplicant/nm-supplicant-types.h" #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceIwd); @@ -41,14 +43,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceIwd, PROP_LAST_SCAN, ); -enum { - SCANNING_PROHIBITED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - typedef struct { GDBusObject * dbus_obj; GDBusProxy * dbus_device_proxy; @@ -77,37 +71,35 @@ struct _NMDeviceIwd { struct _NMDeviceIwdClass { NMDeviceClass parent; - - /* Signals */ - gboolean (*scanning_prohibited) (NMDeviceIwd *device, gboolean periodic); }; /*****************************************************************************/ 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) +#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, - gint32 now_s) + 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), now_s)); + nm_wifi_ap_to_string (ap, buf, sizeof (buf), 0)); } /* Callers ensure we're not removing current_ap */ @@ -124,12 +116,12 @@ ap_add_remove (NMDeviceIwd *self, 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", 0); + _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", 0); + _ap_dump (self, LOGL_DEBUG, ap, "removed"); } _notify (self, PROP_ACCESS_POINTS); @@ -191,45 +183,43 @@ remove_all_aps (NMDeviceIwd *self) nm_device_recheck_available_connections (NM_DEVICE (self)); } -static GVariant * -vardict_from_network_type (const char *type) +static NM80211ApSecurityFlags +ap_security_flags_from_network_type (const char *type) { - GVariantBuilder builder; - const char *key_mgmt = ""; - const char *pairwise = "ccmp"; + NM80211ApSecurityFlags flags; - if (!strcmp (type, "psk")) - key_mgmt = "wpa-psk"; - else if (!strcmp (type, "8021x")) - key_mgmt = "wpa-eap"; + 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 NULL; + return NM_802_11_AP_SEC_NONE; - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&builder, "{sv}", "KeyMgmt", - g_variant_new_strv (&key_mgmt, 1)); - g_variant_builder_add (&builder, "{sv}", "Pairwise", - g_variant_new_strv (&pairwise, 1)); - g_variant_builder_add (&builder, "{sv}", "Group", - g_variant_new_string ("ccmp")); - return g_variant_new ("a{sv}", &builder); + 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, *type_value = NULL; - const char *name, *type; - GVariantBuilder builder; - gs_unref_variant GVariant *props = NULL; - GVariant *rsn; + 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); @@ -253,6 +243,11 @@ insert_ap_from_network (NMDeviceIwd *self, 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 @@ -268,32 +263,26 @@ insert_ap_from_network (NMDeviceIwd *self, bssid[4] = ap_id >> 8; bssid[5] = ap_id; - /* WEP not supported */ - if (nm_streq (type, "wep")) - return; - - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&builder, "{sv}", "BSSID", - g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid, 6, 1)); - g_variant_builder_add (&builder, "{sv}", "Mode", - g_variant_new_string ("infrastructure")); - - rsn = vardict_from_network_type (type); - if (rsn) - g_variant_builder_add (&builder, "{sv}", "RSN", rsn); + ssid = g_bytes_new (name, NM_MIN (32u, strlen (name))); - props = g_variant_new ("a{sv}", &builder); + 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 (path, props); + ap = nm_wifi_ap_new_from_properties (&bss_info); - nm_wifi_ap_set_ssid_arr (ap, - (const guint8 *) name, - NM_MIN (32, strlen (name))); + nm_assert (bss_path == nm_wifi_ap_get_supplicant_path (ap)); - nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (signal / 100)); - nm_wifi_ap_set_freq (ap, 2417); - nm_wifi_ap_set_max_bitrate (ap, 65000); - g_hash_table_insert (aps, (gpointer) nm_wifi_ap_get_supplicant_path (ap), ap); + g_hash_table_insert (aps, bss_path, ap); } static void @@ -313,6 +302,7 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) 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) { @@ -336,16 +326,17 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) return; } - new_aps = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, g_object_unref); + 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, signal, ap_id++); + 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, signal, ap_id++); + insert_ap_from_network (self, new_aps, path, last_seen_msec, signal, ap_id++); } g_variant_iter_free (networks); @@ -356,7 +347,7 @@ get_ordered_networks_cb (GObject *source, GAsyncResult *res, gpointer user_data) 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", 0); + _ap_dump (self, LOGL_TRACE, ap, "updated"); changed = TRUE; } g_hash_table_remove (new_aps, @@ -566,20 +557,17 @@ is_connection_known_network (NMConnection *connection) static gboolean is_ap_known_network (NMWifiAP *ap) { - GDBusProxy *network_proxy; + 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_wifi_ap_get_supplicant_path (ap), + 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"); - g_object_unref (network_proxy); - - return known_network - && g_variant_is_of_type (known_network, G_VARIANT_TYPE_OBJECT_PATH); + return nm_g_variant_is_of_type (known_network, G_VARIANT_TYPE_OBJECT_PATH); } static gboolean @@ -975,15 +963,6 @@ _nm_device_iwd_get_aps (NMDeviceIwd *self) return &NM_DEVICE_IWD_GET_PRIVATE (self)->aps_lst_head; } -static gboolean -check_scanning_prohibited (NMDeviceIwd *self, gboolean periodic) -{ - gboolean prohibited = FALSE; - - g_signal_emit (self, signals[SCANNING_PROHIBITED], 0, periodic, &prohibited); - return prohibited; -} - static void scan_cb (GObject *source, GAsyncResult *res, gpointer user_data) { @@ -993,12 +972,12 @@ scan_cb (GObject *source, GAsyncResult *res, gpointer user_data) 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, FALSE)) + 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_ms (); + priv->last_scan = nm_utils_get_monotonic_timestamp_msec (); _notify (self, PROP_LAST_SCAN); /* On success, priv->scanning becomes true right before or right @@ -1093,7 +1072,7 @@ _nm_device_iwd_request_scan (NMDeviceIwd *self, } static gboolean -scanning_prohibited (NMDeviceIwd *self, gboolean periodic) +check_scanning_prohibited (NMDeviceIwd *self, gboolean periodic) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); @@ -1148,7 +1127,7 @@ try_reply_agent_request (NMDeviceIwd *self, *replied = FALSE; - if (!strcmp (method_name, "RequestPassphrase")) { + if (nm_streq (method_name, "RequestPassphrase")) { const char *psk; if (!s_wireless_sec) @@ -1168,7 +1147,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; *setting_key = NM_SETTING_WIRELESS_SECURITY_PSK; return TRUE; - } else if (!strcmp (method_name, "RequestPrivateKeyPassphrase")) { + } else if (nm_streq (method_name, "RequestPrivateKeyPassphrase")) { const char *password; if (!s_8021x) @@ -1188,7 +1167,7 @@ try_reply_agent_request (NMDeviceIwd *self, *setting_name = NM_SETTING_802_1X_SETTING_NAME; *setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD; return TRUE; - } else if (!strcmp (method_name, "RequestUserNameAndPassword")) { + } else if (nm_streq (method_name, "RequestUserNameAndPassword")) { const char *identity, *password; if (!s_8021x) @@ -1212,7 +1191,7 @@ try_reply_agent_request (NMDeviceIwd *self, else *setting_key = NM_SETTING_802_1X_PASSWORD; return TRUE; - } else if (!strcmp (method_name, "RequestUserPassword")) { + } else if (nm_streq (method_name, "RequestUserPassword")) { const char *password; if (!s_8021x) @@ -1270,7 +1249,7 @@ wifi_secrets_cb (NMActRequest *req, priv->wifi_secrets_id = NULL; - if (nm_utils_error_is_cancelled (error, FALSE)) { + 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"); @@ -1366,7 +1345,7 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) "Activation: (wifi) Network.Connect failed: %s", error->message); - if (nm_utils_error_is_cancelled (error, FALSE)) + 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)) @@ -1438,7 +1417,7 @@ act_failed_cb (GObject *source, GAsyncResult *res, gpointer user_data) 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, FALSE)) + if (!variant && nm_utils_error_is_cancelled (error)) return; /* Change state to FAILED unless already done by state_changed @@ -1467,7 +1446,7 @@ act_start_cb (GObject *source, GAsyncResult *res, gpointer user_data) "Activation: (wifi) Network.Connect failed: %s", error->message); - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; if (!NM_IN_SET (nm_device_get_state (device), NM_DEVICE_STATE_CONFIG)) @@ -1587,7 +1566,7 @@ act_set_mode_cb (GObject *source, GAsyncResult *res, gpointer user_data) "Activation: (wifi) Setting Device.Mode failed: %s", error->message); - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; if ( !NM_IN_SET (nm_device_get_state (device), NM_DEVICE_STATE_CONFIG) @@ -1647,7 +1626,7 @@ act_psk_cb (NMActRequest *req, NMDeviceIwdPrivate *priv; NMDevice *device; - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; priv = NM_DEVICE_IWD_GET_PRIVATE (self); @@ -1772,29 +1751,25 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceIwd *self = NM_DEVICE_IWD (device); NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMActRequest *req; NMConnection *connection; NMSettingWireless *s_wireless; const char *mode; 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_assert (connection); - 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)) { - GDBusProxy *network_proxy; + 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; + goto out_fail; } /* 802.1x networks that are not IWD Known Networks will definitely @@ -1808,18 +1783,18 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) nm_connection_get_id (connection)); NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - goto out; + goto out_fail; } network_proxy = nm_iwd_manager_get_dbus_interface (nm_iwd_manager_get (), - nm_wifi_ap_get_supplicant_path (ap), + nm_ref_string_get_str (nm_wifi_ap_get_supplicant_path (ap)), NM_IWD_NETWORK_INTERFACE); if (!network_proxy) { _LOGE (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) could not get Network interface proxy for %s", - nm_wifi_ap_get_supplicant_path (ap)); + 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; + goto out_fail; } if (!priv->cancellable) @@ -1832,12 +1807,15 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NULL, G_DBUS_CALL_FLAGS_NONE, G_MAXINT, priv->cancellable, network_connect_cb, self); - g_object_unref (network_proxy); - } else if (NM_IN_STRSET (mode, NM_SETTING_WIRELESS_MODE_AP, NM_SETTING_WIRELESS_MODE_ADHOC)) { + 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)) { + 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); @@ -1852,16 +1830,18 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); } else act_set_mode (self); - } - /* We'll get stage3 started when the supplicant connects */ - ret = NM_ACT_STAGE_RETURN_POSTPONE; + return NM_ACT_STAGE_RETURN_POSTPONE; + } -out: - if (ret == NM_ACT_STAGE_RETURN_FAILURE) - cleanup_association_attempt (self, FALSE); + _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); - return ret; +out_fail: + cleanup_association_attempt (self, FALSE); + return NM_ACT_STAGE_RETURN_FAILURE; } static guint32 @@ -1987,7 +1967,7 @@ device_state_changed (NMDevice *device, static gboolean get_enabled (NMDevice *device) { - return NM_DEVICE_IWD_GET_PRIVATE ((NMDeviceIwd *) device)->enabled; + return NM_DEVICE_IWD_GET_PRIVATE (device)->enabled; } static void @@ -2099,7 +2079,7 @@ get_property (GObject *object, guint prop_id, case PROP_LAST_SCAN: g_value_set_int64 (value, priv->last_scan > 0 - ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan, NM_UTILS_NS_PER_MSEC) + ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan, NM_UTILS_NSEC_PER_MSEC) : (gint64) -1); break; default: @@ -2582,8 +2562,6 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) device_class->state_changed = device_state_changed; - klass->scanning_prohibited = scanning_prohibited; - obj_properties[PROP_MODE] = g_param_spec_uint (NM_DEVICE_IWD_MODE, "", "", NM_802_11_MODE_UNKNOWN, @@ -2628,12 +2606,4 @@ nm_device_iwd_class_init (NMDeviceIwdClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[SCANNING_PROHIBITED] = - g_signal_new (NM_DEVICE_IWD_SCANNING_PROHIBITED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceIwdClass, scanning_prohibited), - NULL, NULL, NULL, - G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN); } diff --git a/src/devices/wifi/nm-device-iwd.h b/src/devices/wifi/nm-device-iwd.h index 586e02f4..1f15d3f4 100644 --- a/src/devices/wifi/nm-device-iwd.h +++ b/src/devices/wifi/nm-device-iwd.h @@ -25,8 +25,6 @@ #define NM_DEVICE_IWD_SCANNING NM_DEVICE_WIFI_SCANNING #define NM_DEVICE_IWD_LAST_SCAN NM_DEVICE_WIFI_LAST_SCAN -#define NM_DEVICE_IWD_SCANNING_PROHIBITED NM_DEVICE_WIFI_SCANNING_PROHIBITED - typedef struct _NMDeviceIwd NMDeviceIwd; typedef struct _NMDeviceIwdClass NMDeviceIwdClass; diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index 516dc78b..770b53f6 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -57,7 +57,7 @@ struct _NMDeviceOlpcMeshClass { 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) +#define NM_DEVICE_OLPC_MESH_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDeviceOlpcMesh, NM_IS_DEVICE_OLPC_MESH, NMDevice) /*****************************************************************************/ @@ -130,7 +130,6 @@ 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); - gboolean scanning; /* disconnect companion device, if it is connected */ if (nm_device_get_act_request (NM_DEVICE (priv->companion))) { @@ -145,8 +144,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) } /* wait with continuing configuration until the companion device is done scanning */ - g_object_get (priv->companion, NM_DEVICE_WIFI_SCANNING, &scanning, NULL); - if (scanning) { + if (nm_device_wifi_get_scanning (NM_DEVICE_WIFI (priv->companion))) { priv->stage1_waiting = TRUE; return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -189,10 +187,10 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) 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), @@ -237,6 +235,9 @@ 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); } @@ -248,15 +249,16 @@ companion_notify_cb (NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_d { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); - gboolean scanning; + + nm_assert (NM_IS_DEVICE_WIFI (companion)); + nm_assert (priv->companion == (gpointer) companion); if (!priv->stage1_waiting) return; - g_object_get (companion, NM_DEVICE_WIFI_SCANNING, &scanning, NULL); - if (!scanning) { + if (!nm_device_wifi_get_scanning (NM_DEVICE_WIFI (companion))) { priv->stage1_waiting = FALSE; - nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); } } @@ -290,16 +292,6 @@ companion_state_changed_cb (NMDeviceWifi *companion, } static gboolean -companion_scan_prohibited_cb (NMDeviceWifi *companion, gboolean periodic, 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 scan while configuring the mesh interface */ - return (state >= NM_DEVICE_STATE_PREPARE) && (state <= NM_DEVICE_STATE_IP_CONFIG); -} - -static gboolean companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); @@ -324,7 +316,7 @@ check_companion (NMDeviceOlpcMesh *self, NMDevice *other) if (!nm_utils_hwaddr_matches (my_addr, -1, their_addr, -1)) return FALSE; - g_assert (priv->companion == NULL); + nm_assert (priv->companion == NULL); priv->companion = g_object_ref (other); _LOGI (LOGD_OLPC, "found companion Wi-Fi device %s", @@ -336,9 +328,6 @@ check_companion (NMDeviceOlpcMesh *self, NMDevice *other) 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_WIFI_SCANNING_PROHIBITED, - G_CALLBACK (companion_scan_prohibited_cb), self); - g_signal_connect (G_OBJECT (other), NM_DEVICE_AUTOCONNECT_ALLOWED, G_CALLBACK (companion_autoconnect_allowed_cb), self); @@ -400,8 +389,24 @@ state_changed (NMDevice *device, 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 (NM_DEVICE_OLPC_MESH (device)); + 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 diff --git a/src/devices/wifi/nm-device-wifi-p2p.c b/src/devices/wifi/nm-device-wifi-p2p.c index 34ff70fa..497bc436 100644 --- a/src/devices/wifi/nm-device-wifi-p2p.c +++ b/src/devices/wifi/nm-device-wifi-p2p.c @@ -12,19 +12,20 @@ #include "supplicant/nm-supplicant-manager.h" #include "supplicant/nm-supplicant-interface.h" -#include "nm-manager.h" -#include "nm-utils.h" -#include "nm-wifi-p2p-peer.h" #include "NetworkManagerUtils.h" #include "devices/nm-device-private.h" -#include "settings/nm-settings.h" -#include "nm-setting-wifi-p2p.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 "platform/nm-platform.h" #include "nm-manager.h" -#include "nm-core-internal.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); @@ -104,7 +105,7 @@ peer_list_dump (gpointer user_data) if (_LOGD_ENABLED (LOGD_WIFI_SCAN)) { NMWifiP2PPeer *peer; - gint32 now_s = nm_utils_get_monotonic_timestamp_s (); + 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) @@ -227,11 +228,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return FALSE; supplicant_state = nm_supplicant_interface_get_state (priv->mgmt_iface); - if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY - || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) - return FALSE; - - return TRUE; + return nm_supplicant_interface_state_is_operational (supplicant_state); } static gboolean @@ -432,7 +429,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) 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 */ @@ -452,7 +448,8 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) /* TODO: Fix "pbc" being hardcoded here! */ nm_supplicant_interface_p2p_connect (priv->mgmt_iface, nm_wifi_p2p_peer_get_supplicant_path (peer), - "pbc", NULL); + "pbc", + NULL); /* Set up a timeout on the connect attempt */ if (priv->sup_timeout_id == 0) { @@ -526,7 +523,7 @@ peer_add_remove (NMDeviceWifiP2P *self, 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); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } } @@ -649,52 +646,49 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMSupplicantInterfaceState new_state = new_state_i; NMSupplicantInterfaceState old_state = old_state_i; - if (new_state == old_state) - return; - _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)); - switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - _LOGD (LOGD_WIFI, "supplicant ready"); + 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_READY) - _set_is_waiting_for_supplicant (self, FALSE); - break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: - supplicant_interfaces_release (self, TRUE); + 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); - break; - default: - break; + _set_is_waiting_for_supplicant (self, FALSE); } } static void -supplicant_iface_peer_updated_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, +supplicant_iface_peer_changed_cb (NMSupplicantInterface *iface, + NMSupplicantPeerInfo *peer_info, + gboolean is_present, NMDeviceWifiP2P *self) { - NMDeviceWifiP2PPrivate *priv; + NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); NMWifiP2PPeer *found_peer; - g_return_if_fail (self != NULL); - g_return_if_fail (object_path != NULL); + found_peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, peer_info->peer_path->str); - priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); + if (!is_present) { + if (!found_peer) + return; + + peer_add_remove (self, FALSE, found_peer, TRUE); + goto out; + } - found_peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path); if (found_peer) { - if (!nm_wifi_p2p_peer_update_from_properties (found_peer, object_path, properties)) + if (!nm_wifi_p2p_peer_update_from_properties (found_peer, peer_info)) return; update_disconnect_on_connection_peer_missing (self); @@ -702,35 +696,11 @@ supplicant_iface_peer_updated_cb (NMSupplicantInterface *iface, } else { gs_unref_object NMWifiP2PPeer *peer = NULL; - peer = nm_wifi_p2p_peer_new_from_properties (object_path, properties); - if (!peer) { - _LOGD (LOGD_WIFI, "invalid P2P peer properties received for %s", object_path); - return; - } - + peer = nm_wifi_p2p_peer_new_from_properties (peer_info); peer_add_remove (self, TRUE, peer, TRUE); } - schedule_peer_list_dump (self); -} - -static void -supplicant_iface_peer_removed_cb (NMSupplicantInterface *iface, - const char *object_path, - NMDeviceWifiP2P *self) -{ - NMDeviceWifiP2PPrivate *priv; - NMWifiP2PPeer *peer; - - g_return_if_fail (self != NULL); - g_return_if_fail (object_path != NULL); - - priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); - peer = nm_wifi_p2p_peers_find_by_supplicant_path (&priv->peers_lst_head, object_path); - if (!peer) - return; - - peer_add_remove (self, FALSE, peer, TRUE); +out: schedule_peer_list_dump (self); } @@ -742,7 +712,7 @@ check_group_iface_ready (NMDeviceWifiP2P *self) if (!priv->group_iface) return; - if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + 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)) @@ -755,6 +725,24 @@ check_group_iface_ready (NMDeviceWifiP2P *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, @@ -762,44 +750,26 @@ supplicant_group_iface_state_cb (NMSupplicantInterface *iface, gpointer user_data) { NMDeviceWifiP2P *self = NM_DEVICE_WIFI_P2P (user_data); - NMDeviceWifiP2PPrivate *priv = NM_DEVICE_WIFI_P2P_GET_PRIVATE (self); - NMDevice *device = NM_DEVICE (self); NMSupplicantInterfaceState new_state = new_state_i; NMSupplicantInterfaceState old_state = old_state_i; - if (new_state == old_state) - return; - _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)); - switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - _LOGD (LOGD_WIFI, "P2P Group supplicant ready"); - - if (!nm_device_set_ip_iface (device, nm_supplicant_interface_get_ifname (priv->group_iface))) { - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - break; - } - - if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) - _set_is_waiting_for_supplicant (self, FALSE); - - check_group_iface_ready (self); - break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: + if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { supplicant_group_interface_release (self); - nm_device_state_changed (device, + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - break; - default: - break; + return; + } + + if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { + supplicant_group_iface_is_ready (self); + return; } } @@ -833,8 +803,9 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface, NMDeviceWifiP2P *self) { NMDeviceWifiP2PPrivate *priv; + NMSupplicantInterfaceState state; - g_return_if_fail (self != NULL); + 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."); @@ -844,6 +815,7 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface, 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 @@ -862,10 +834,13 @@ supplicant_iface_group_started_cb (NMSupplicantInterface *iface, G_CALLBACK (supplicant_group_iface_group_finished_cb), self); - if (nm_supplicant_interface_get_state (priv->group_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + state = nm_supplicant_interface_get_state (priv->group_iface); + if (state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) { _set_is_waiting_for_supplicant (self, TRUE); + return; + } - check_group_iface_ready (self); + supplicant_group_iface_is_ready (self); } static void @@ -935,9 +910,8 @@ device_state_changed (NMDevice *device, break; case NM_DEVICE_STATE_UNAVAILABLE: if ( !priv->mgmt_iface - || nm_supplicant_interface_get_state (priv->mgmt_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) + || !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? */ @@ -1084,20 +1058,20 @@ nm_device_wifi_p2p_set_mgmt_iface (NMDeviceWifiP2P *self, goto done; _LOGD (LOGD_DEVICE | LOGD_WIFI, "P2P: WPA supplicant management interface changed to %s.", - nm_supplicant_interface_get_object_path (iface)); + 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_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_UPDATED, - G_CALLBACK (supplicant_iface_peer_updated_cb), - self); - g_signal_connect (priv->mgmt_iface, NM_SUPPLICANT_INTERFACE_PEER_REMOVED, - G_CALLBACK (supplicant_iface_peer_removed_cb), + 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_signal_connect (priv->mgmt_iface, + NM_SUPPLICANT_INTERFACE_GROUP_STARTED, G_CALLBACK (supplicant_iface_group_started_cb), self); done: @@ -1106,8 +1080,7 @@ done: NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); _set_is_waiting_for_supplicant (self, !priv->mgmt_iface - || ( nm_supplicant_interface_get_state (priv->mgmt_iface) - < NM_SUPPLICANT_INTERFACE_STATE_READY)); + || !nm_supplicant_interface_state_is_operational (nm_supplicant_interface_get_state (priv->mgmt_iface))); } void diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 98f9df25..266a8425 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -11,6 +11,8 @@ #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" @@ -42,10 +44,9 @@ #include "devices/nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceWifi); -/* All of these are in seconds */ -#define SCAN_INTERVAL_MIN 3 -#define SCAN_INTERVAL_STEP 20 -#define SCAN_INTERVAL_MAX 120 +#define SCAN_INTERVAL_SEC_MIN 3 +#define SCAN_INTERVAL_SEC_STEP 20 +#define SCAN_INTERVAL_SEC_MAX 120 #define SCAN_RAND_MAC_ADDRESS_EXPIRE_MIN 5 @@ -62,7 +63,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceWifi, ); enum { - SCANNING_PROHIBITED, P2P_DEVICE_CREATED, LAST_SIGNAL @@ -71,9 +71,10 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { - gint8 invalid_strength_counter; - CList aps_lst_head; + GHashTable *aps_idx_by_supplicant_path; + + CList scanning_prohibited_lst_head; NMWifiAP * current_ap; guint32 rate; @@ -83,13 +84,15 @@ typedef struct { bool is_scanning:1; bool hidden_probe_scan_warn:1; - gint64 last_scan; /* milliseconds */ + gint64 last_scan_msec; + gint32 scheduled_scan_time; /* seconds */ - guint8 scan_interval; /* seconds */ + guint8 scan_interval_sec; guint pending_scan_id; guint ap_dump_id; NMSupplicantManager *sup_mgr; + NMSupplMgrCreateIfaceHandle *sup_create_handle; NMSupplicantInterface *sup_iface; guint sup_timeout_id; /* supplicant association timeout */ @@ -97,7 +100,7 @@ typedef struct { NMActRequestGetSecretsCallId *wifi_secrets_id; - guint periodic_source_id; + guint periodic_update_id; guint link_timeout_id; guint32 failed_iface_count; guint reacquire_iface_id; @@ -122,53 +125,46 @@ struct _NMDeviceWifi struct _NMDeviceWifiClass { NMDeviceClass parent; - - /* Signals */ - gboolean (*scanning_prohibited) (NMDeviceWifi *device, gboolean periodic); }; /*****************************************************************************/ 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) +#define NM_DEVICE_WIFI_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDeviceWifi, NM_IS_DEVICE_WIFI, NMDevice) /*****************************************************************************/ static gboolean check_scanning_prohibited (NMDeviceWifi *self, gboolean periodic); +static void supplicant_iface_state_down (NMDeviceWifi *self); + static void schedule_scan (NMDeviceWifi *self, gboolean backoff); 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_updated_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, - NMDeviceWifi *self); - -static void supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, - const char *object_path, +static void supplicant_iface_bss_changed_cb (NMSupplicantInterface *iface, + NMSupplicantBssInfo *bss_info, + gboolean is_present, NMDeviceWifi *self); -static void supplicant_iface_scan_done_cb (NMSupplicantInterface * iface, - gboolean success, - NMDeviceWifi * self); - static void supplicant_iface_wps_credentials_cb (NMSupplicantInterface *iface, GVariant *credentials, NMDeviceWifi *self); -static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface, - GParamSpec * pspec, - NMDeviceWifi * self); - static void supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self); @@ -177,6 +173,10 @@ static void supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self); +static void _requested_scan_set (NMDeviceWifi *self, gboolean value); + +static void periodic_update (NMDeviceWifi *self); + static void request_wireless_scan (NMDeviceWifi *self, gboolean periodic, gboolean force_if_scanning, @@ -193,19 +193,66 @@ static void recheck_p2p_availability (NMDeviceWifi *self); /*****************************************************************************/ +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); + return; + } + + if (elem) + return; + + c_list_link_tail (&priv->scanning_prohibited_lst_head, + &nm_c_list_elem_new_stale (tag)->lst); +} + +/*****************************************************************************/ + static void _ap_dump (NMDeviceWifi *self, NMLogLevel log_level, const NMWifiAP *ap, const char *prefix, - gint32 now_s) + 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_s)); + 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)->is_scanning; } static void @@ -213,6 +260,7 @@ _notify_scanning (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); gboolean scanning; + gboolean last_scan_changed = FALSE; scanning = priv->sup_iface && nm_supplicant_interface_get_scanning (priv->sup_iface); @@ -220,9 +268,42 @@ _notify_scanning (NMDeviceWifi *self) if (scanning == priv->is_scanning) return; - _LOGD (LOGD_WIFI, "wifi-scan: scanning-state: %s", scanning ? "scanning" : "idle"); priv->is_scanning = scanning; - _notify (self, PROP_SCANNING); + + if ( !scanning + || priv->last_scan_msec == 0) { + last_scan_changed = TRUE; + priv->last_scan_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)" : ""); + + schedule_scan (self, TRUE); + + nm_gobject_notify_together (self, + PROP_SCANNING, + last_scan_changed + ? PROP_LAST_SCAN + : PROP_0); + + if (!priv->is_scanning) { + _requested_scan_set (self, FALSE); + if (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED) { + /* Run a quick update of current AP when coming out of a scan */ + periodic_update (self); + } + } +} + +static void +supplicant_iface_notify_scanning_cb (NMSupplicantInterface *iface, + GParamSpec *pspec, + NMDeviceWifi *self) +{ + _notify_scanning (self); } static gboolean @@ -237,40 +318,40 @@ unmanaged_on_quit (NMDevice *self) return TRUE; } -static gboolean -supplicant_interface_acquire (NMDeviceWifi *self) +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); - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (!priv->sup_iface, TRUE); + if (nm_utils_error_is_cancelled (error)) + return; - priv->sup_iface = nm_supplicant_manager_create_interface (priv->sup_mgr, - nm_device_get_iface (NM_DEVICE (self)), - NM_SUPPLICANT_DRIVER_WIRELESS); - if (!priv->sup_iface) { - _LOGE (LOGD_WIFI, "Couldn't initialize supplicant interface"); - return FALSE; + 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; } - if (nm_supplicant_interface_get_state (priv->sup_iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) - nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, FALSE); + 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_UPDATED, - G_CALLBACK (supplicant_iface_bss_updated_cb), - self); - g_signal_connect (priv->sup_iface, - NM_SUPPLICANT_INTERFACE_BSS_REMOVED, - G_CALLBACK (supplicant_iface_bss_removed_cb), - self); - g_signal_connect (priv->sup_iface, - NM_SUPPLICANT_INTERFACE_SCAN_DONE, - G_CALLBACK (supplicant_iface_scan_done_cb), + NM_SUPPLICANT_INTERFACE_BSS_CHANGED, + G_CALLBACK (supplicant_iface_bss_changed_cb), self); g_signal_connect (priv->sup_iface, NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS, @@ -291,7 +372,30 @@ supplicant_interface_acquire (NMDeviceWifi *self) _notify_scanning (self); - return TRUE; + 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 @@ -310,27 +414,26 @@ _requested_scan_set (NMDeviceWifi *self, gboolean value) nm_device_add_pending_action ((NMDevice *) self, NM_PENDING_ACTION_WIFI_SCAN, TRUE); else { nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); - nm_device_remove_pending_action ((NMDevice *) self, NM_PENDING_ACTION_WIFI_SCAN, TRUE); + nm_device_remove_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WIFI_SCAN, TRUE); } } static void supplicant_interface_release (NMDeviceWifi *self) { - NMDeviceWifiPrivate *priv; - - g_return_if_fail (self != NULL); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - 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); _requested_scan_set (self, FALSE); nm_clear_g_source (&priv->pending_scan_id); /* Reset the scan interval to be pretty frequent when disconnected */ - priv->scan_interval = SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP; + priv->scan_interval_sec = SCAN_INTERVAL_SEC_MIN + SCAN_INTERVAL_SEC_STEP; _LOGD (LOGD_WIFI, "wifi-scan: reset interval to %u seconds", - (unsigned) priv->scan_interval); + (unsigned) priv->scan_interval_sec); nm_clear_g_source (&priv->ap_dump_id); @@ -410,44 +513,48 @@ set_current_ap (NMDeviceWifi *self, NMWifiAP *new_ap, gboolean recheck_available static void periodic_update (NMDeviceWifi *self) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); + NMDeviceWifiPrivate *priv; + int ifindex; guint32 new_rate; - int percent; - NMDeviceState state; - NMSupplicantInterfaceState supplicant_state; - /* BSSID and signal strength have meaningful values only if the device - * is activated and not scanning. - */ - state = nm_device_get_state (NM_DEVICE (self)); - if (state != NM_DEVICE_STATE_ACTIVATED) + 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; + } - /* 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. - */ - supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface); - if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING - || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED - || nm_supplicant_interface_get_scanning (priv->sup_iface)) + 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; + } - /* In AP mode we currently have nothing to do. */ - if (priv->mode == NM_802_11_MODE_AP) + 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) { - /* Smooth out the strength to work around crappy drivers */ + int percent; + percent = nm_platform_wifi_get_quality (nm_device_get_platform (NM_DEVICE (self)), ifindex); - if (percent >= 0 || ++priv->invalid_strength_counter > 3) { + 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 } - priv->invalid_strength_counter = 0; } } @@ -461,7 +568,7 @@ periodic_update (NMDeviceWifi *self) static gboolean periodic_update_cb (gpointer user_data) { - periodic_update (NM_DEVICE_WIFI (user_data)); + periodic_update (user_data); return TRUE; } @@ -477,12 +584,16 @@ ap_add_remove (NMDeviceWifi *self, 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); } @@ -593,7 +704,7 @@ deactivate (NMDevice *device) int ifindex = nm_device_get_ifindex (device); NM80211Mode old_mode = priv->mode; - nm_clear_g_source (&priv->periodic_source_id); + nm_clear_g_source (&priv->periodic_update_id); cleanup_association_attempt (self, TRUE); @@ -694,7 +805,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError } if (priv->sup_iface) { - if (nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) { + 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; @@ -708,7 +819,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection, GError } if (priv->sup_iface) { - if (nm_supplicant_interface_get_mesh_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) { + 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; @@ -936,7 +1047,7 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return FALSE; supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface); - if ( supplicant_state < NM_SUPPLICANT_INTERFACE_STATE_READY + if ( supplicant_state <= NM_SUPPLICANT_INTERFACE_STATE_STARTING || supplicant_state > NM_SUPPLICANT_INTERFACE_STATE_COMPLETED) return FALSE; @@ -1047,7 +1158,7 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset) return; } - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); if (now >= priv->hw_addr_scan_expire) { gs_free char *generate_mac_address_mask = NULL; @@ -1074,16 +1185,17 @@ _hw_addr_set_scanning (NMDeviceWifi *self, gboolean do_reset) static GPtrArray * ssids_options_to_ptrarray (GVariant *value, GError **error) { - GPtrArray *ssids = NULL; - const guint8 *bytes; - gsize len; - int num_ssids, i; + 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_NOT_ALLOWED, + NM_DEVICE_ERROR_INVALID_ARGUMENT, "too many SSIDs requested to scan"); return NULL; } @@ -1092,22 +1204,30 @@ ssids_options_to_ptrarray (GVariant *value, GError **error) 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_NOT_ALLOWED, - "SSID at index %d more than 32 bytes", i); - g_ptr_array_unref (ssids); + 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 ssids; + + return g_steal_pointer (&ssids); +} + +GPtrArray * +nmtst_ssids_options_to_ptrarray (GVariant *value, GError **error) +{ + return ssids_options_to_ptrarray (value, error); } static void @@ -1118,8 +1238,7 @@ dbus_request_scan_cb (NMDevice *device, gpointer user_data) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - gs_unref_variant GVariant *scan_options = user_data; - gs_unref_ptrarray GPtrArray *ssids = NULL; + gs_unref_ptrarray GPtrArray *ssids = user_data; if (error) { g_dbus_method_invocation_return_gerror (context, error); @@ -1134,41 +1253,42 @@ dbus_request_scan_cb (NMDevice *device, return; } - if (scan_options) { - gs_unref_variant GVariant *val = g_variant_lookup_value (scan_options, "ssids", NULL); + request_wireless_scan (self, FALSE, FALSE, ssids); + 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); + gint64 last_scan; + 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 (context, + g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, + 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 (context, ssid_error); + g_dbus_method_invocation_return_gerror (invocation, ssid_error); return; } } } - request_wireless_scan (self, FALSE, FALSE, ssids); - 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); - gint64 last_scan; - if ( !priv->enabled || !priv->sup_iface || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED @@ -1189,7 +1309,13 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, } last_scan = nm_supplicant_interface_get_last_scan (priv->sup_iface); - if (last_scan && (nm_utils_get_monotonic_timestamp_ms () - last_scan) < 10 * NM_UTILS_MSEC_PER_SECOND) { + if ( last_scan > 0 + && nm_utils_get_monotonic_timestamp_msec () < last_scan + (10 * NM_UTILS_MSEC_PER_SEC)) { + /* FIXME: we really should not outright reject a scan request in this case. We should + * ensure to start a scan request soon, possibly with rate limiting. And there is no + * need to tell the caller that we aren't going to scan... + * + * Same above, if we are currently scanning... */ g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ALLOWED, @@ -1204,16 +1330,19 @@ _nm_device_wifi_request_scan (NMDeviceWifi *self, NM_AUTH_PERMISSION_WIFI_SCAN, TRUE, dbus_request_scan_cb, - options ? g_variant_ref (options) : NULL); + g_steal_pointer (&ssids)); } static gboolean -scanning_prohibited (NMDeviceWifi *self, gboolean periodic) +check_scanning_prohibited (NMDeviceWifi *self, + gboolean periodic) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMSupplicantInterfaceState supplicant_state; - g_return_val_if_fail (priv->sup_iface != NULL, TRUE); + nm_assert (NM_IS_SUPPLICANT_INTERFACE (priv->sup_iface)); + + if (!c_list_is_empty (&priv->scanning_prohibited_lst_head)) + return TRUE; /* Don't scan when a an AP or Ad-Hoc connection is active as it will * disrupt connected clients or peers. @@ -1250,11 +1379,11 @@ scanning_prohibited (NMDeviceWifi *self, gboolean periodic) } /* Prohibit scans if the supplicant is busy */ - supplicant_state = nm_supplicant_interface_get_state (priv->sup_iface); - if ( supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING - || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED - || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE - || supplicant_state == NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE + if ( 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) || nm_supplicant_interface_get_scanning (priv->sup_iface)) return TRUE; @@ -1263,15 +1392,6 @@ scanning_prohibited (NMDeviceWifi *self, gboolean periodic) } static gboolean -check_scanning_prohibited (NMDeviceWifi *self, gboolean periodic) -{ - gboolean prohibited = FALSE; - - g_signal_emit (self, signals[SCANNING_PROHIBITED], 0, periodic, &prohibited); - return prohibited; -} - -static gboolean hidden_filter_func (NMSettings *settings, NMSettingsConnection *set_con, gpointer user_data) @@ -1420,16 +1540,17 @@ static void schedule_scan (NMDeviceWifi *self, gboolean backoff) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); - /* Cancel the pending scan if it would happen later than (now + the scan_interval) */ + /* Cancel the pending scan if it would happen later than (now + the scan_interval_sec) */ if (priv->pending_scan_id) { - if (now + priv->scan_interval < priv->scheduled_scan_time) + if (now + priv->scan_interval_sec < priv->scheduled_scan_time) nm_clear_g_source (&priv->pending_scan_id); } if (!priv->pending_scan_id) { - guint factor = 2, next_scan = priv->scan_interval; + guint factor = 2; + guint next_scan = priv->scan_interval_sec; if ( nm_device_is_activating (NM_DEVICE (self)) || (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED)) @@ -1439,41 +1560,25 @@ schedule_scan (NMDeviceWifi *self, gboolean backoff) request_wireless_scan_periodic, self); - priv->scheduled_scan_time = now + priv->scan_interval; - if (backoff && (priv->scan_interval < (SCAN_INTERVAL_MAX / factor))) { - priv->scan_interval += (SCAN_INTERVAL_STEP / factor); + priv->scheduled_scan_time = now + priv->scan_interval_sec; + if (backoff && (priv->scan_interval_sec < (SCAN_INTERVAL_SEC_MAX / factor))) { + priv->scan_interval_sec += (SCAN_INTERVAL_SEC_STEP / factor); /* Ensure the scan interval will never be less than 20s... */ - priv->scan_interval = MAX(priv->scan_interval, SCAN_INTERVAL_MIN + SCAN_INTERVAL_STEP); + priv->scan_interval_sec = MAX(priv->scan_interval_sec, SCAN_INTERVAL_SEC_MIN + SCAN_INTERVAL_SEC_STEP); /* ... or more than 120s */ - priv->scan_interval = MIN(priv->scan_interval, SCAN_INTERVAL_MAX); - } else if (!backoff && (priv->scan_interval == 0)) { + priv->scan_interval_sec = MIN(priv->scan_interval_sec, SCAN_INTERVAL_SEC_MAX); + } else if (!backoff && (priv->scan_interval_sec == 0)) { /* Invalid combination; would cause continual rescheduling of * the scan and hog CPU. Reset to something minimally sane. */ - priv->scan_interval = 5; + priv->scan_interval_sec = 5; } _LOGD (LOGD_WIFI, "wifi-scan: scheduled in %d seconds (interval now %d seconds)", - next_scan, priv->scan_interval); + next_scan, priv->scan_interval_sec); } } -static void -supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, - gboolean success, - NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - _LOGD (LOGD_WIFI, "wifi-scan: scan-done callback: %s", success ? "successful" : "failed"); - - priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); - _notify (self, PROP_LAST_SCAN); - schedule_scan (self, success); - - _requested_scan_set (self, FALSE); -} - /**************************************************************************** * WPA Supplicant control stuff * @@ -1489,14 +1594,21 @@ ap_list_dump (gpointer user_data) if (_LOGD_ENABLED (LOGD_WIFI_SCAN)) { NMWifiAP *ap; - gint32 now_s = nm_utils_get_monotonic_timestamp_s (); - - _LOGD (LOGD_WIFI_SCAN, "APs: [now:%u last:%" G_GINT64_FORMAT " next:%u]", - now_s, - priv->last_scan / NM_UTILS_MSEC_PER_SECOND, + gint64 now_msec = nm_utils_get_monotonic_timestamp_msec (); + char str_buf[100]; + + _LOGD (LOGD_WIFI_SCAN, "APs: [now:%u.%03u, last:%s, next:%u]", + (guint) (now_msec / NM_UTILS_MSEC_PER_SEC), + (guint) (now_msec % NM_UTILS_MSEC_PER_SEC), + priv->last_scan_msec > 0 + ? nm_sprintf_buf (str_buf, + "%u.%03u", + (guint) (priv->last_scan_msec / NM_UTILS_MSEC_PER_SEC), + (guint) (priv->last_scan_msec % NM_UTILS_MSEC_PER_SEC)) + : "-1", priv->scheduled_scan_time); c_list_for_each_entry (ap, &priv->aps_lst_head, aps_lst) - _ap_dump (self, LOGL_DEBUG, ap, "dump", now_s); + _ap_dump (self, LOGL_DEBUG, ap, "dump", now_msec); } return G_SOURCE_REMOVE; } @@ -1543,40 +1655,43 @@ try_fill_ssid_for_hidden_ap (NMDeviceWifi *self, } static void -supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, +supplicant_iface_bss_changed_cb (NMSupplicantInterface *iface, + NMSupplicantBssInfo *bss_info, + gboolean is_present, NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMDeviceState state; - NMWifiAP *found_ap = NULL; + NMWifiAP *found_ap; GBytes *ssid; - g_return_if_fail (self != NULL); - g_return_if_fail (properties != NULL); - g_return_if_fail (iface != NULL); + found_ap = g_hash_table_lookup (priv->aps_idx_by_supplicant_path, bss_info->bss_path); - /* Ignore new APs when unavailable, unmanaged, or in AP mode */ - state = nm_device_get_state (NM_DEVICE (self)); - if (state <= NM_DEVICE_STATE_UNAVAILABLE) - return; - if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP) + 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; + } - found_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, object_path); if (found_ap) { - if (!nm_wifi_ap_update_from_properties (found_ap, object_path, properties)) + 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; - ap = nm_wifi_ap_new_from_properties (object_path, properties); - if (!ap) { - _LOGD (LOGD_WIFI, "invalid AP properties received for %s", object_path); - 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); @@ -1606,43 +1721,13 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, /* Update the current AP if the supplicant notified a current BSS change * before it sent the current BSS's scan result. */ - if (g_strcmp0 (nm_supplicant_interface_get_current_bss (iface), object_path) == 0) + 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 -supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, - const char *object_path, - NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv; - NMWifiAP *ap; - - g_return_if_fail (self != NULL); - g_return_if_fail (object_path != NULL); - - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, object_path); - if (!ap) - return; - - if (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 (ap, TRUE)) - _ap_dump (self, LOGL_DEBUG, ap, "updated", 0); - } else { - ap_add_remove (self, FALSE, ap, TRUE); - schedule_ap_list_dump (self); - } -} - -static void cleanup_association_attempt (NMDeviceWifi *self, gboolean disconnect) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); @@ -1725,7 +1810,7 @@ wifi_secrets_cb (NMActRequest *req, return; } - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -1792,7 +1877,7 @@ supplicant_iface_wps_credentials_cb (NMSupplicantInterface *iface, } wifi_secrets_cancel (self); - nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self)); + nm_device_activate_schedule_stage1_device_prepare (NM_DEVICE (self), FALSE); } static gboolean @@ -2020,50 +2105,71 @@ reacquire_interface_cb (gpointer user_data) } 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_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) { - NMDeviceWifi *self = NM_DEVICE_WIFI (user_data); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); NMDeviceState devstate; gboolean scanning; - NMSupplicantInterfaceState new_state = new_state_i; - NMSupplicantInterfaceState old_state = old_state_i; - - if (new_state == old_state) - return; _LOGI (LOGD_DEVICE | LOGD_WIFI, - "supplicant interface state: %s -> %s", + "supplicant interface state: %s -> %s%s", nm_supplicant_interface_state_to_string (old_state), - nm_supplicant_interface_state_to_string (new_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 (iface); + 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_interval_sec = SCAN_INTERVAL_SEC_MIN; + } /* 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_READY - && new_state >= NM_SUPPLICANT_INTERFACE_STATE_READY) + if (old_state == NM_SUPPLICANT_INTERFACE_STATE_STARTING) recheck_p2p_availability (self); switch (new_state) { - case NM_SUPPLICANT_INTERFACE_STATE_READY: - _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_interval = SCAN_INTERVAL_MIN; - if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) - nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); - break; case NM_SUPPLICANT_INTERFACE_STATE_COMPLETED: nm_clear_g_source (&priv->sup_timeout_id); nm_clear_g_source (&priv->link_timeout_id); @@ -2118,26 +2224,6 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, } } break; - case NM_SUPPLICANT_INTERFACE_STATE_DOWN: - nm_device_queue_recheck_available (NM_DEVICE (device), - NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE, - NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - cleanup_association_attempt (self, FALSE); - - if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY) - nm_device_remove_pending_action (device, NM_PENDING_ACTION_WAITING_FOR_SUPPLICANT, TRUE); - - /* 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"); - break; case NM_SUPPLICANT_INTERFACE_STATE_INACTIVE: /* we would clear _requested_scan_set() and trigger a new scan. * However, we don't want to cancel the current pending action, so force @@ -2148,10 +2234,25 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, break; } - /* Signal scanning state changes */ - if ( new_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING - || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING) - _notify_scanning (self); +out: + _notify_scanning (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 @@ -2162,7 +2263,7 @@ supplicant_iface_assoc_cb (NMSupplicantInterface *iface, NMDeviceWifi *self = NM_DEVICE_WIFI (user_data); NMDevice *device = NM_DEVICE (self); - if ( error && !nm_utils_error_is_cancelled (error, TRUE) + 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); @@ -2170,30 +2271,17 @@ supplicant_iface_assoc_cb (NMSupplicantInterface *iface, } static void -supplicant_iface_notify_scanning_cb (NMSupplicantInterface *iface, - GParamSpec *pspec, - NMDeviceWifi *self) -{ - _notify_scanning (self); - - /* Run a quick update of current AP when coming out of a scan */ - if ( !NM_DEVICE_WIFI_GET_PRIVATE (self)->is_scanning - && nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED) - periodic_update (self); -} - -static void supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - const char *current_bss; + NMRefString *current_bss; NMWifiAP *new_ap = NULL; current_bss = nm_supplicant_interface_get_current_bss (iface); if (current_bss) - new_ap = nm_wifi_aps_find_by_supplicant_path (&priv->aps_lst_head, 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; @@ -2284,11 +2372,8 @@ supplicant_iface_notify_p2p_available (NMSupplicantInterface *iface, GParamSpec *pspec, NMDeviceWifi *self) { - /* Do not update when the interface is still initializing. */ - if (nm_supplicant_interface_get_state (iface) < NM_SUPPLICANT_INTERFACE_STATE_READY) - return; - - recheck_p2p_availability (self); + if (nm_supplicant_interface_get_state (iface) > NM_SUPPLICANT_INTERFACE_STATE_STARTING) + recheck_p2p_availability (self); } static gboolean @@ -2472,15 +2557,11 @@ build_supplicant_config (NMDeviceWifi *self, 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_pmf_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, - nm_supplicant_interface_get_fils_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, - nm_supplicant_interface_get_ft_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES, - nm_supplicant_interface_get_sha384_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_YES); + config = nm_supplicant_config_new (nm_supplicant_interface_get_capabilities (priv->sup_iface)); /* Warn if AP mode may not be supported */ - if ( g_strcmp0 (nm_setting_wireless_get_mode (s_wireless), NM_SETTING_WIRELESS_MODE_AP) == 0 - && nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_UNKNOWN) { + 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."); } @@ -2753,8 +2834,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMSupplicantConfig *config = NULL; + gs_unref_object NMSupplicantConfig *config = NULL; NM80211Mode ap_mode; NMActRequest *req; NMWifiAP *ap; @@ -2774,15 +2854,14 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) ap = priv->current_ap; if (!ap) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); - goto out; + goto out_fail; } + ap_mode = nm_wifi_ap_get_mode (ap); connection = nm_act_request_get_applied_connection (req); - g_assert (connection); - s_wireless = nm_connection_get_setting_wireless (connection); - g_assert (s_wireless); + nm_assert (s_wireless); /* If we need secrets, get them */ setting_name = nm_connection_need_secrets (connection, NULL); @@ -2791,13 +2870,12 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) "Activation: (wifi) access point '%s' has security, but secrets are required.", nm_connection_get_id (connection)); - if (handle_auth_or_fail (self, req, FALSE)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else { + if (!handle_auth_or_fail (self, req, FALSE)) { NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - ret = NM_ACT_STAGE_RETURN_FAILURE; + goto out_fail; } - goto out; + + return NM_ACT_STAGE_RETURN_POSTPONE; } if (!wake_on_wlan_enable (self)) @@ -2830,17 +2908,19 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) /* Build up the supplicant configuration */ config = build_supplicant_config (self, connection, nm_wifi_ap_get_freq (ap), &error); - if (config == NULL) { + 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; + goto out_fail; } - nm_supplicant_interface_assoc (priv->sup_iface, config, - supplicant_iface_assoc_cb, self); + 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)); @@ -2848,25 +2928,16 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) supplicant_connection_timeout_cb, self); - if (!priv->periodic_source_id) - priv->periodic_source_id = g_timeout_add_seconds (6, periodic_update_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 */ - ret = NM_ACT_STAGE_RETURN_POSTPONE; - -out: - if (ret == NM_ACT_STAGE_RETURN_FAILURE) { - cleanup_association_attempt (self, TRUE); - wake_on_wlan_restore (self); - } + return NM_ACT_STAGE_RETURN_POSTPONE; - if (config) { - /* Supplicant interface object refs the config; we no longer care about - * it after this function. - */ - g_object_unref (config); - } - return ret; +out_fail: + cleanup_association_attempt (self, TRUE); + wake_on_wlan_restore (self); + return NM_ACT_STAGE_RETURN_FAILURE; } static NMActStageReturn @@ -3033,7 +3104,7 @@ activation_success_handler (NMDevice *device) update_seen_bssids_cache (self, priv->current_ap); /* Reset scan interval to something reasonable */ - priv->scan_interval = SCAN_INTERVAL_MIN + (SCAN_INTERVAL_STEP * 2); + priv->scan_interval_sec = SCAN_INTERVAL_SEC_MIN + (SCAN_INTERVAL_SEC_STEP * 2); } static void @@ -3053,10 +3124,9 @@ device_state_changed (NMDevice *device, /* Clean up the supplicant interface because in these states the * device cannot be used. */ - if (priv->sup_iface) - supplicant_interface_release (self); + supplicant_interface_release (self); - nm_clear_g_source (&priv->periodic_source_id); + nm_clear_g_source (&priv->periodic_update_id); cleanup_association_attempt (self, TRUE); cleanup_supplicant_failures (self); @@ -3095,7 +3165,7 @@ device_state_changed (NMDevice *device, break; case NM_DEVICE_STATE_DISCONNECTED: /* Kick off a scan to get latest results */ - priv->scan_interval = SCAN_INTERVAL_MIN; + priv->scan_interval_sec = SCAN_INTERVAL_SEC_MIN; request_wireless_scan (self, FALSE, FALSE, NULL); break; default: @@ -3109,7 +3179,7 @@ device_state_changed (NMDevice *device, static gboolean get_enabled (NMDevice *device) { - return NM_DEVICE_WIFI_GET_PRIVATE ((NMDeviceWifi *) device)->enabled; + return NM_DEVICE_WIFI_GET_PRIVATE (device)->enabled; } static void @@ -3155,8 +3225,7 @@ set_enabled (NMDevice *device, gboolean enabled) /* Re-initialize the supplicant interface and wait for it to be ready */ cleanup_supplicant_failures (self); - if (priv->sup_iface) - supplicant_interface_release (self); + supplicant_interface_release (self); supplicant_interface_acquire (self); _LOGD (LOGD_WIFI, "enable waiting on supplicant state"); @@ -3251,13 +3320,13 @@ get_property (GObject *object, guint prop_id, nm_dbus_utils_g_value_set_object_path (value, priv->current_ap); break; case PROP_SCANNING: - g_value_set_boolean (value, priv->is_scanning); + g_value_set_boolean (value, nm_device_wifi_get_scanning (self)); 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_NS_PER_MSEC) - : (gint64) -1); + priv->last_scan_msec > 0 + ? nm_utils_monotonic_timestamp_as_boottime (priv->last_scan_msec, NM_UTILS_NSEC_PER_MSEC) + : (gint64) -1); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -3291,6 +3360,8 @@ 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); + priv->aps_idx_by_supplicant_path = g_hash_table_new (nm_direct_hash, NULL); priv->hidden_probe_scan_warn = TRUE; priv->mode = NM_802_11_MODE_INFRA; @@ -3331,7 +3402,9 @@ dispose (GObject *object) NMDeviceWifi *self = NM_DEVICE_WIFI (object); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - nm_clear_g_source (&priv->periodic_source_id); + nm_assert (c_list_is_empty (&priv->scanning_prohibited_lst_head)); + + nm_clear_g_source (&priv->periodic_update_id); wifi_secrets_cancel (self); @@ -3359,6 +3432,9 @@ finalize (GObject *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); } @@ -3406,8 +3482,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) device_class->state_changed = device_state_changed; - klass->scanning_prohibited = scanning_prohibited; - obj_properties[PROP_MODE] = g_param_spec_uint (NM_DEVICE_WIFI_MODE, "", "", NM_802_11_MODE_UNKNOWN, @@ -3454,14 +3528,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - signals[SCANNING_PROHIBITED] = - g_signal_new (NM_DEVICE_WIFI_SCANNING_PROHIBITED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceWifiClass, scanning_prohibited), - NULL, NULL, NULL, - G_TYPE_BOOLEAN, 1, G_TYPE_BOOLEAN); - signals[P2P_DEVICE_CREATED] = g_signal_new (NM_DEVICE_WIFI_P2P_DEVICE_CREATED, G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h index aaf47143..c9fce4e2 100644 --- a/src/devices/wifi/nm-device-wifi.h +++ b/src/devices/wifi/nm-device-wifi.h @@ -24,7 +24,6 @@ #define NM_DEVICE_WIFI_SCANNING "scanning" #define NM_DEVICE_WIFI_LAST_SCAN "last-scan" -#define NM_DEVICE_WIFI_SCANNING_PROHIBITED "scanning-prohibited" #define NM_DEVICE_WIFI_P2P_DEVICE_CREATED "p2p-device-created" typedef struct _NMDeviceWifi NMDeviceWifi; @@ -40,4 +39,12 @@ 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 index 470cb1c9..39c863a3 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -874,7 +874,8 @@ nm_iwd_manager_is_known_network (NMIwdManager *self, const char *name, } GDBusProxy * -nm_iwd_manager_get_dbus_interface (NMIwdManager *self, const char *path, +nm_iwd_manager_get_dbus_interface (NMIwdManager *self, + const char *path, const char *name) { NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index ee7dc236..e427c86f 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -10,15 +10,16 @@ #include <stdlib.h> -#include "nm-setting-wireless.h" - -#include "nm-wifi-utils.h" #include "NetworkManagerUtils.h" -#include "nm-utils.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.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" @@ -39,8 +40,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiAP, ); struct _NMWifiAPPrivate { - char *supplicant_path; /* D-Bus object path of this AP from wpa_supplicant */ - /* Scanned or cached values */ GBytes * ssid; char * address; @@ -49,6 +48,9 @@ struct _NMWifiAPPrivate { 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 */ @@ -58,7 +60,6 @@ struct _NMWifiAPPrivate { /* 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 */ - gint32 last_seen; /* Timestamp when the AP was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ }; typedef struct _NMWifiAPPrivate NMWifiAPPrivate; @@ -73,14 +74,6 @@ G_DEFINE_TYPE (NMWifiAP, nm_wifi_ap, NM_TYPE_DBUS_OBJECT) /*****************************************************************************/ -const char * -nm_wifi_ap_get_supplicant_path (NMWifiAP *ap) -{ - g_return_val_if_fail (NM_IS_WIFI_AP (ap), NULL); - - return NM_WIFI_AP_GET_PRIVATE (ap)->supplicant_path; -} - GBytes * nm_wifi_ap_get_ssid (const NMWifiAP *ap) { @@ -148,11 +141,7 @@ nm_wifi_ap_set_ssid (NMWifiAP *ap, GBytes *ssid) static gboolean nm_wifi_ap_set_flags (NMWifiAP *ap, NM80211ApFlags flags) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->flags != flags) { priv->flags = flags; @@ -165,11 +154,8 @@ nm_wifi_ap_set_flags (NMWifiAP *ap, NM80211ApFlags flags) static gboolean nm_wifi_ap_set_wpa_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); - priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->wpa_flags != flags) { priv->wpa_flags = flags; _notify (ap, PROP_WPA_FLAGS); @@ -181,11 +167,8 @@ nm_wifi_ap_set_wpa_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags) static gboolean nm_wifi_ap_set_rsn_flags (NMWifiAP *ap, NM80211ApSecurityFlags flags) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); - priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->rsn_flags != flags) { priv->rsn_flags = flags; _notify (ap, PROP_RSN_FLAGS); @@ -203,11 +186,9 @@ nm_wifi_ap_get_address (const NMWifiAP *ap) } static gboolean -nm_wifi_ap_set_address_bin (NMWifiAP *ap, const guint8 *addr /* ETH_ALEN bytes */) +nm_wifi_ap_set_address_bin (NMWifiAP *ap, const guint8 addr[static 6 /* ETH_ALEN */]) { - NMWifiAPPrivate *priv; - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); if ( !priv->address || !nm_utils_hwaddr_matches (addr, ETH_ALEN, priv->address, -1)) { @@ -241,16 +222,14 @@ nm_wifi_ap_get_mode (NMWifiAP *ap) } static gboolean -nm_wifi_ap_set_mode (NMWifiAP *ap, const NM80211Mode mode) +nm_wifi_ap_set_mode (NMWifiAP *ap, NM80211Mode mode) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - g_return_val_if_fail ( mode == NM_802_11_MODE_ADHOC - || mode == NM_802_11_MODE_INFRA - || mode == NM_802_11_MODE_MESH, FALSE); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); - 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; @@ -277,13 +256,9 @@ nm_wifi_ap_get_strength (NMWifiAP *ap) } gboolean -nm_wifi_ap_set_strength (NMWifiAP *ap, const gint8 strength) +nm_wifi_ap_set_strength (NMWifiAP *ap, gint8 strength) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->strength != strength) { priv->strength = strength; @@ -303,13 +278,9 @@ nm_wifi_ap_get_freq (NMWifiAP *ap) gboolean nm_wifi_ap_set_freq (NMWifiAP *ap, - const guint32 freq) + guint32 freq) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); if (priv->freq != freq) { priv->freq = freq; @@ -378,16 +349,12 @@ nm_wifi_ap_get_flags (const NMWifiAP *ap) } static gboolean -nm_wifi_ap_set_last_seen (NMWifiAP *ap, gint32 last_seen) +nm_wifi_ap_set_last_seen (NMWifiAP *ap, gint32 last_seen_msec) { - NMWifiAPPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - - priv = NM_WIFI_AP_GET_PRIVATE (ap); + NMWifiAPPrivate *priv = NM_WIFI_AP_GET_PRIVATE (ap); - if (priv->last_seen != last_seen) { - priv->last_seen = last_seen; + if (priv->last_seen_msec != last_seen_msec) { + priv->last_seen_msec = last_seen_msec; _notify (ap, PROP_LAST_SEEN); return TRUE; } @@ -402,501 +369,53 @@ nm_wifi_ap_get_metered (const NMWifiAP *self) /*****************************************************************************/ -static NM80211ApSecurityFlags -security_from_vardict (GVariant *security) -{ - NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; - const char **array, *tmp; - - g_return_val_if_fail (g_variant_is_of_type (security, G_VARIANT_TYPE_VARDICT), NM_802_11_AP_SEC_NONE); - - if ( g_variant_lookup (security, "KeyMgmt", "^a&s", &array) - && array) { - if (g_strv_contains (array, "wpa-psk") || - g_strv_contains (array, "wpa-ft-psk")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; - if (g_strv_contains (array, "wpa-eap") || - g_strv_contains (array, "wpa-ft-eap") || - g_strv_contains (array, "wpa-fils-sha256") || - g_strv_contains (array, "wpa-fils-sha384")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; - if (g_strv_contains (array, "sae")) - flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE; - g_free (array); - } - - if ( g_variant_lookup (security, "Pairwise", "^a&s", &array) - && array) { - if (g_strv_contains (array, "tkip")) - flags |= NM_802_11_AP_SEC_PAIR_TKIP; - if (g_strv_contains (array, "ccmp")) - flags |= NM_802_11_AP_SEC_PAIR_CCMP; - g_free (array); - } - - if (g_variant_lookup (security, "Group", "&s", &tmp)) { - if (strcmp (tmp, "wep40") == 0) - flags |= NM_802_11_AP_SEC_GROUP_WEP40; - if (strcmp (tmp, "wep104") == 0) - flags |= NM_802_11_AP_SEC_GROUP_WEP104; - if (strcmp (tmp, "tkip") == 0) - flags |= NM_802_11_AP_SEC_GROUP_TKIP; - if (strcmp (tmp, "ccmp") == 0) - flags |= NM_802_11_AP_SEC_GROUP_CCMP; - } - - return flags; -} - -/*****************************************************************************/ - -static guint32 -get_max_rate_ht_20 (int mcs) -{ - switch (mcs) { - case 0: return 6500000; - case 1: - case 8: return 13000000; - case 2: - case 16: return 19500000; - case 3: - case 9: - case 24: return 26000000; - case 4: - case 10: - case 17: return 39000000; - case 5: - case 11: - case 25: return 52000000; - case 6: - case 18: return 58500000; - case 7: return 65000000; - case 12: - case 19: - case 26: return 78000000; - case 13: - case 27: return 104000000; - case 14: - case 20: return 117000000; - case 15: return 130000000; - case 21: - case 28: return 156000000; - case 22: return 175500000; - case 23: return 195000000; - case 29: return 208000000; - case 30: return 234000000; - case 31: return 260000000; - } - return 0; -} - -static guint32 -get_max_rate_ht_40 (int mcs) -{ - switch (mcs) { - case 0: return 13500000; - case 1: - case 8: return 27000000; - case 2: return 40500000; - case 3: - case 9: - case 24: return 54000000; - case 4: - case 10: - case 17: return 81000000; - case 5: - case 11: - case 25: return 108000000; - case 6: - case 18: return 121500000; - case 7: return 135000000; - case 12: - case 19: - case 26: return 162000000; - case 13: - case 27: return 216000000; - case 14: - case 20: return 243000000; - case 15: return 270000000; - case 16: return 40500000; - case 21: - case 28: return 324000000; - case 22: return 364500000; - case 23: return 405000000; - case 29: return 432000000; - case 30: return 486000000; - case 31: return 540000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_80_ss1 (int mcs) -{ - switch (mcs) { - case 0: return 29300000; - case 1: return 58500000; - case 2: return 87800000; - case 3: return 117000000; - case 4: return 175500000; - case 5: return 234000000; - case 6: return 263300000; - case 7: return 292500000; - case 8: return 351000000; - case 9: return 390000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_80_ss2 (int mcs) -{ - switch (mcs) { - case 0: return 58500000; - case 1: return 117000000; - case 2: return 175500000; - case 3: return 234000000; - case 4: return 351000000; - case 5: return 468000000; - case 6: return 526500000; - case 7: return 585000000; - case 8: return 702000000; - case 9: return 780000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_80_ss3 (int mcs) -{ - switch (mcs) { - case 0: return 87800000; - case 1: return 175500000; - case 2: return 263300000; - case 3: return 351000000; - case 4: return 526500000; - case 5: return 702000000; - case 6: return 0; - case 7: return 877500000; - case 8: return 105300000; - case 9: return 117000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_160_ss1 (int mcs) -{ - switch (mcs) { - case 0: return 58500000; - case 1: return 117000000; - case 2: return 175500000; - case 3: return 234000000; - case 4: return 351000000; - case 5: return 468000000; - case 6: return 526500000; - case 7: return 585000000; - case 8: return 702000000; - case 9: return 780000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_160_ss2 (int mcs) -{ - switch (mcs) { - case 0: return 117000000; - case 1: return 234000000; - case 2: return 351000000; - case 3: return 468000000; - case 4: return 702000000; - case 5: return 936000000; - case 6: return 1053000000; - case 7: return 1170000000; - case 8: return 1404000000; - case 9: return 1560000000; - } - return 0; -} - -static guint32 -get_max_rate_vht_160_ss3 (int mcs) -{ - switch (mcs) { - case 0: return 175500000; - case 1: return 351000000; - case 2: return 526500000; - case 3: return 702000000; - case 4: return 1053000000; - case 5: return 1404000000; - case 6: return 1579500000; - case 7: return 1755000000; - case 8: return 2106000000; - case 9: return 0; - } - return 0; -} - -static gboolean -get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) -{ - guint32 i; - guint8 ht_cap_info; - const guint8 *supported_mcs_set; - guint32 rate; - - /* http://standards.ieee.org/getieee802/download/802.11-2012.pdf - * https://mrncciew.com/2014/10/19/cwap-ht-capabilities-ie/ - */ - - if (len != 26) - return FALSE; - - ht_cap_info = bytes[0]; - supported_mcs_set = &bytes[3]; - *out_maxrate = 0; - - /* Find the maximum supported mcs rate */ - for (i = 0; i <= 76; i++) { - unsigned int mcs_octet = i / 8; - unsigned int MCS_RATE_BIT = 1 << i % 8; - - if (supported_mcs_set[mcs_octet] & MCS_RATE_BIT) { - /* Check for 40Mhz wide channel support */ - if (ht_cap_info & (1 << 1)) - rate = get_max_rate_ht_40 (i); - else - rate = get_max_rate_ht_20 (i); - - if (rate > *out_maxrate) - *out_maxrate = rate; - } - } - - return TRUE; -} - -static gboolean -get_max_rate_vht (const guint8 *bytes, guint len, guint32 *out_maxrate) -{ - guint32 mcs, m; - guint8 vht_cap, tx_map; - - /* https://tda802dot11.blogspot.it/2014/10/vht-capabilities-element-vht.html - * http://chimera.labs.oreilly.com/books/1234000001739/ch03.html#management_frames */ - - if (len != 12) - return FALSE; - - vht_cap = bytes[0]; - tx_map = bytes[8]; - - /* Check for mcs rates 8 and 9 support */ - if (tx_map & 0x2a) - mcs = 9; - else if (tx_map & 0x15) - mcs = 8; - else - mcs = 7; - - /* Check for 160Mhz wide channel support and - * spatial stream support */ - if (vht_cap & (1 << 2)) { - if (tx_map & 0x30) - m = get_max_rate_vht_160_ss3 (mcs); - else if (tx_map & 0x0C) - m = get_max_rate_vht_160_ss2 (mcs); - else - m = get_max_rate_vht_160_ss1 (mcs); - } else { - if (tx_map & 0x30) - m = get_max_rate_vht_80_ss3 (mcs); - else if (tx_map & 0x0C) - m = get_max_rate_vht_80_ss2 (mcs); - else - m = get_max_rate_vht_80_ss1 (mcs); - } - - *out_maxrate = m; - return TRUE; -} - -/* Management Frame Information Element IDs, ieee80211_eid */ -#define WLAN_EID_HT_CAPABILITY 45 -#define WLAN_EID_VHT_CAPABILITY 191 -#define WLAN_EID_VENDOR_SPECIFIC 221 - -static void -parse_ies (const guint8 *bytes, gsize len, guint32 *out_max_rate, gboolean *out_metered) -{ - guint8 id, elem_len; - guint32 m; - - *out_max_rate = 0; - *out_metered = FALSE; - - while (len) { - if (len < 2) - break; - - id = *bytes++; - elem_len = *bytes++; - len -= 2; - - if (elem_len > len) - break; - - switch (id) { - case WLAN_EID_HT_CAPABILITY: - if (get_max_rate_ht (bytes, elem_len, &m)) - *out_max_rate = NM_MAX (*out_max_rate, m); - break; - case WLAN_EID_VHT_CAPABILITY: - if (get_max_rate_vht (bytes, elem_len, &m)) - *out_max_rate = NM_MAX (*out_max_rate, m); - break; - case WLAN_EID_VENDOR_SPECIFIC: - if ( len == 8 - && bytes[0] == 0x00 /* OUI: Microsoft */ - && bytes[1] == 0x50 - && bytes[2] == 0xf2 - && bytes[3] == 0x11) /* OUI type: Network cost */ - *out_metered = (bytes[7] > 1); /* Cost level > 1 */ - break; - } - - len -= elem_len; - bytes += elem_len; - } -} - -/*****************************************************************************/ - gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, - const char *supplicant_path, - GVariant *properties) + const NMSupplicantBssInfo *bss_info) { NMWifiAPPrivate *priv; - const guint8 *bytes; - GVariant *v; - gsize len; - gsize i; - gboolean b = FALSE; - const char *s; - gint16 i16; - guint16 u16; gboolean changed = FALSE; - gboolean metered; - guint32 max_rate, rate; g_return_val_if_fail (NM_IS_WIFI_AP (ap), FALSE); - g_return_val_if_fail (properties, 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); - g_object_freeze_notify (G_OBJECT (ap)); - - if (g_variant_lookup (properties, "Privacy", "b", &b) && b) - changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY); - - v = g_variant_lookup_value (properties, "WPS", G_VARIANT_TYPE_VARDICT); - if (v) { - if (g_variant_lookup (v, "Type", "&s", &s)) { - changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS); - if (strcmp (s, "pbc") == 0) - changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS_PBC); - else if (strcmp (s, "pin") == 0) - changed |= nm_wifi_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_WPS_PIN); - } - g_variant_unref (v); - } - - if (g_variant_lookup (properties, "Mode", "&s", &s)) { - if (!g_strcmp0 (s, "infrastructure")) - changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_INFRA); - else if (!g_strcmp0 (s, "ad-hoc")) - changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_ADHOC); - else if (!g_strcmp0 (s, "mesh")) - changed |= nm_wifi_ap_set_mode (ap, NM_802_11_MODE_MESH); - } - - if (g_variant_lookup (properties, "Signal", "n", &i16)) - changed |= nm_wifi_ap_set_strength (ap, nm_wifi_utils_level_to_quality (i16)); - - if (g_variant_lookup (properties, "Frequency", "q", &u16)) - changed |= nm_wifi_ap_set_freq (ap, u16); - - v = g_variant_lookup_value (properties, "SSID", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - len = MIN (32, len); + nm_assert ( !ap->_supplicant_path + || ap->_supplicant_path == bss_info->bss_path); - /* Stupid ieee80211 layer uses <hidden> */ - if ( bytes - && len - && !( NM_IN_SET (len, 8, 9) - && memcmp (bytes, "<hidden>", len) == 0) - && !nm_utils_is_empty_ssid (bytes, len)) { - /* good */ - } else - len = 0; - - changed |= nm_wifi_ap_set_ssid_arr (ap, bytes, len); - - g_variant_unref (v); - } + g_object_freeze_notify (G_OBJECT (ap)); - v = g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - if ( len == ETH_ALEN - && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 - && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) - changed |= nm_wifi_ap_set_address_bin (ap, bytes); - g_variant_unref (v); + if (!ap->_supplicant_path) { + ap->_supplicant_path = nm_ref_string_ref (bss_info->bss_path); + changed = TRUE; } - max_rate = 0; - v = g_variant_lookup_value (properties, "Rates", G_VARIANT_TYPE ("au")); - if (v) { - const guint32 *rates = g_variant_get_fixed_array (v, &len, sizeof (guint32)); + 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); - for (i = 0; i < len; i++) - max_rate = NM_MAX (max_rate, rates[i]); - g_variant_unref (v); - } - v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - parse_ies (bytes, len, &rate, &metered); - max_rate = NM_MAX (max_rate, rate); - g_variant_unref (v); - priv->metered = metered; + if (bss_info->bssid_valid) + changed |= nm_wifi_ap_set_address_bin (ap, bss_info->bssid); + else { + /* we don't actually clear the value. */ } - if (max_rate) - changed |= nm_wifi_ap_set_max_bitrate (ap, max_rate / 1000); + changed |= nm_wifi_ap_set_max_bitrate (ap, bss_info->max_rate); - v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); - if (v) { - changed |= nm_wifi_ap_set_wpa_flags (ap, priv->wpa_flags | security_from_vardict (v)); - g_variant_unref (v); + if (priv->metered != bss_info->metered) { + priv->metered = bss_info->metered; + changed = TRUE; } - v = g_variant_lookup_value (properties, "RSN", G_VARIANT_TYPE_VARDICT); - if (v) { - changed |= nm_wifi_ap_set_rsn_flags (ap, priv->rsn_flags | security_from_vardict (v)); - g_variant_unref (v); - } + changed |= nm_wifi_ap_set_wpa_flags (ap, bss_info->wpa_flags); + changed |= nm_wifi_ap_set_rsn_flags (ap, bss_info->rsn_flags); - if (!priv->supplicant_path) { - priv->supplicant_path = g_strdup (supplicant_path); - changed = TRUE; - } + changed |= nm_wifi_ap_set_last_seen (ap, bss_info->last_seen_msec); - changed |= nm_wifi_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); changed |= nm_wifi_ap_set_fake (ap, FALSE); g_object_thaw_notify (G_OBJECT (ap)); @@ -984,20 +503,22 @@ const char * nm_wifi_ap_to_string (const NMWifiAP *self, char *str_buf, gulong buf_len, - gint32 now_s) + 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 (priv->supplicant_path) - supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id; + 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) @@ -1005,8 +526,10 @@ nm_wifi_ap_to_string (const NMWifiAP *self, 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 ] %3us sup:%s [nm:%s]", + "%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 @@ -1024,7 +547,12 @@ nm_wifi_ap_to_string (const NMWifiAP *self, priv->metered ? 'M' : '_', priv->wpa_flags & 0xFFFF, priv->rsn_flags & 0xFFFF, - priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_s ()) - priv->last_seen) : -1, + 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; @@ -1177,9 +705,9 @@ get_property (GObject *object, guint prop_id, 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_NS_PER_SECOND) - : -1); + 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); @@ -1204,26 +732,16 @@ nm_wifi_ap_init (NMWifiAP *self) 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 = -1; + priv->last_seen_msec = G_MININT64; } NMWifiAP * -nm_wifi_ap_new_from_properties (const char *supplicant_path, GVariant *properties) +nm_wifi_ap_new_from_properties (const NMSupplicantBssInfo *bss_info) { NMWifiAP *ap; - g_return_val_if_fail (supplicant_path != NULL, NULL); - g_return_val_if_fail (properties != NULL, NULL); - - ap = (NMWifiAP *) g_object_new (NM_TYPE_WIFI_AP, NULL); - nm_wifi_ap_update_from_properties (ap, supplicant_path, properties); - - /* ignore APs with invalid or missing BSSIDs */ - if (!nm_wifi_ap_get_address (ap)) { - g_object_unref (ap); - return NULL; - } - + ap = g_object_new (NM_TYPE_WIFI_AP, NULL); + nm_wifi_ap_update_from_properties (ap, bss_info); return ap; } @@ -1349,7 +867,7 @@ finalize (GObject *object) nm_assert (!self->wifi_device); nm_assert (c_list_is_empty (&self->aps_lst)); - g_free (priv->supplicant_path); + nm_ref_string_unref (self->_supplicant_path); if (priv->ssid) g_bytes_unref (priv->ssid); g_free (priv->address); @@ -1394,7 +912,8 @@ nm_wifi_ap_class_init (NMWifiAPClass *ap_class) | 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_SAE \ + | NM_802_11_AP_SEC_KEY_MGMT_OWE ) GObjectClass *object_class = G_OBJECT_CLASS (ap_class); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (ap_class); @@ -1515,20 +1034,6 @@ nm_wifi_aps_find_first_compatible (const CList *aps_lst_head, return NULL; } -NMWifiAP * -nm_wifi_aps_find_by_supplicant_path (const CList *aps_lst_head, const char *path) -{ - NMWifiAP *ap; - - g_return_val_if_fail (path != NULL, NULL); - - c_list_for_each_entry (ap, aps_lst_head, aps_lst) { - if (nm_streq0 (path, nm_wifi_ap_get_supplicant_path (ap))) - return ap; - } - return NULL; -} - /*****************************************************************************/ NMWifiAP * diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 472dfdf9..1bf4e604 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -33,20 +33,21 @@ 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 char *supplicant_path, - GVariant *properties); -NMWifiAP * nm_wifi_ap_new_fake_from_connection (NMConnection *connection); +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 char *supplicant_path, - GVariant *properties); +gboolean nm_wifi_ap_update_from_properties (NMWifiAP *ap, + const struct _NMSupplicantBssInfo *bss_info); gboolean nm_wifi_ap_check_compatible (NMWifiAP *self, NMConnection *connection); @@ -56,7 +57,14 @@ gboolean nm_wifi_ap_complete_connection (NMWifiAP *self, gboolean lock_bssid, GError **error); -const char * nm_wifi_ap_get_supplicant_path (NMWifiAP *ap); +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, @@ -86,7 +94,7 @@ 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, - gint32 now_s); + gint64 now_msec); const char **nm_wifi_aps_get_paths (const CList *aps_lst_head, gboolean include_without_ssid); @@ -94,8 +102,6 @@ const char **nm_wifi_aps_get_paths (const CList *aps_lst_head, NMWifiAP *nm_wifi_aps_find_first_compatible (const CList *aps_lst_head, NMConnection *connection); -NMWifiAP *nm_wifi_aps_find_by_supplicant_path (const CList *aps_lst_head, const char *path); - 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-factory.c b/src/devices/wifi/nm-wifi-factory.c index 821460a5..9b87bbbf 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -95,7 +95,7 @@ create_device (NMDeviceFactory *factory, iface, NM_PRINT_FMT_QUOTE_STRING (backend), WITH_IWD ? " (iwd support enabled)" : ""); - if (!backend || !strcasecmp (backend, "wpa_supplicant")) { + if (!backend || !g_ascii_strcasecmp (backend, "wpa_supplicant")) { NMDevice *device; NMDeviceWifiCapabilities capabilities; NM80211Mode mode; @@ -129,7 +129,7 @@ create_device (NMDeviceFactory *factory, return device; } #if WITH_IWD - else if (!strcasecmp (backend, "iwd")) + else if (!g_ascii_strcasecmp (backend, "iwd")) return nm_device_iwd_new (iface); #endif diff --git a/src/devices/wifi/nm-wifi-p2p-peer.c b/src/devices/wifi/nm-wifi-p2p-peer.c index f8da0046..c58bd95e 100644 --- a/src/devices/wifi/nm-wifi-p2p-peer.c +++ b/src/devices/wifi/nm-wifi-p2p-peer.c @@ -9,15 +9,16 @@ #include <stdlib.h> -#include "nm-setting-wireless.h" - -#include "nm-wifi-utils.h" #include "NetworkManagerUtils.h" -#include "nm-utils.h" -#include "nm-core-internal.h" -#include "platform/nm-platform.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" /*****************************************************************************/ @@ -28,7 +29,6 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiP2PPeer, PROP_MODEL_NUMBER, PROP_SERIAL, PROP_WFD_IES, - PROP_GROUPS, PROP_HW_ADDRESS, PROP_STRENGTH, PROP_LAST_SEEN, @@ -36,7 +36,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMWifiP2PPeer, ); struct _NMWifiP2PPeerPrivate { - char *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */ + NMRefString *supplicant_path; /* D-Bus object path of this Peer from wpa_supplicant */ /* Scanned or cached values */ char * name; @@ -55,7 +55,7 @@ struct _NMWifiP2PPeerPrivate { NM80211ApFlags flags; /* General flags */ /* Non-scanned attributes */ - gint32 last_seen; /* Timestamp when the Peer was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ + gint32 last_seen; /* Timestamp when the Peer was seen lastly (obtained via nm_utils_get_monotonic_timestamp_sec()) */ }; typedef struct _NMWifiP2PPeerPrivate NMWifiP2PPeerPrivate; @@ -151,7 +151,7 @@ nm_wifi_p2p_peer_get_supplicant_path (NMWifiP2PPeer *peer) { g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); - return NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->supplicant_path; + return nm_ref_string_get_str (NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->supplicant_path); } const char * @@ -163,18 +163,12 @@ nm_wifi_p2p_peer_get_name (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_name (NMWifiP2PPeer *peer, const char *name) +nm_wifi_p2p_peer_set_name (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (name, priv->name) == 0) + if (!nm_utils_strdup_reset (&priv->name, str)) return FALSE; - - g_clear_pointer (&priv->name, g_free); - if (name) - priv->name = g_strdup (name); - _notify (peer, PROP_NAME); return TRUE; } @@ -188,18 +182,12 @@ nm_wifi_p2p_peer_get_manufacturer (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_manufacturer (NMWifiP2PPeer *peer, const char *manufacturer) +nm_wifi_p2p_peer_set_manufacturer (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (manufacturer, priv->manufacturer) == 0) + if (!nm_utils_strdup_reset (&priv->manufacturer, str)) return FALSE; - - g_clear_pointer (&priv->manufacturer, g_free); - if (manufacturer) - priv->manufacturer = g_strdup (manufacturer); - _notify (peer, PROP_MANUFACTURER); return TRUE; } @@ -213,18 +201,12 @@ nm_wifi_p2p_peer_get_model (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_model (NMWifiP2PPeer *peer, const char *model) +nm_wifi_p2p_peer_set_model (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (model, priv->model) == 0) + if (!nm_utils_strdup_reset (&priv->model, str)) return FALSE; - - g_clear_pointer (&priv->model, g_free); - if (model) - priv->model = g_strdup (model); - _notify (peer, PROP_MODEL); return TRUE; } @@ -238,18 +220,12 @@ nm_wifi_p2p_peer_get_model_number (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_model_number (NMWifiP2PPeer *peer, const char *model_number) +nm_wifi_p2p_peer_set_model_number (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (model_number, priv->model_number) == 0) + if (!nm_utils_strdup_reset (&priv->model_number, str)) return FALSE; - - g_clear_pointer (&priv->model_number, g_free); - if (model_number) - priv->model_number = g_strdup (model_number); - _notify (peer, PROP_MODEL_NUMBER); return TRUE; } @@ -263,18 +239,12 @@ nm_wifi_p2p_peer_get_serial (const NMWifiP2PPeer *peer) } gboolean -nm_wifi_p2p_peer_set_serial (NMWifiP2PPeer *peer, const char *serial) +nm_wifi_p2p_peer_set_serial (NMWifiP2PPeer *peer, const char *str) { NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - if (g_strcmp0 (serial, priv->serial) == 0) + if (!nm_utils_strdup_reset (&priv->serial, str)) return FALSE; - - g_clear_pointer (&priv->serial, g_free); - if (serial) - priv->serial = g_strdup (serial); - _notify (peer, PROP_SERIAL); return TRUE; } @@ -291,6 +261,7 @@ 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); @@ -299,7 +270,7 @@ nm_wifi_p2p_peer_set_wfd_ies (NMWifiP2PPeer *peer, GBytes *wfd_ies) if (nm_gbytes_equal0 (priv->wfd_ies, wfd_ies)) return FALSE; - g_bytes_unref (priv->wfd_ies); + 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); @@ -311,27 +282,7 @@ nm_wifi_p2p_peer_get_groups (const NMWifiP2PPeer *peer) { g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), NULL); - return (const char * const*) NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->groups; -} - -static gboolean -nm_wifi_p2p_peer_set_groups (NMWifiP2PPeer *peer, const char** groups) -{ - NMWifiP2PPeerPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - g_return_val_if_fail (groups != NULL, FALSE); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); - - if (_nm_utils_strv_equal (priv->groups, (char **) groups)) - return FALSE; - - g_strfreev (priv->groups); - priv->groups = g_strdupv ((char**) groups); - - _notify (peer, PROP_GROUPS); - return TRUE; + return (const char *const*) NM_WIFI_P2P_PEER_GET_PRIVATE (peer)->groups; } const char * @@ -382,11 +333,7 @@ nm_wifi_p2p_peer_get_strength (NMWifiP2PPeer *peer) gboolean nm_wifi_p2p_peer_set_strength (NMWifiP2PPeer *peer, const gint8 strength) { - NMWifiP2PPeerPrivate *priv; - - g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - - priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); + NMWifiP2PPeerPrivate *priv = NM_WIFI_P2P_PEER_GET_PRIVATE (peer); if (priv->strength != strength) { priv->strength = strength; @@ -426,80 +373,42 @@ nm_wifi_p2p_peer_set_last_seen (NMWifiP2PPeer *peer, gint32 last_seen) gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer, - const char *supplicant_path, - GVariant *properties) + const NMSupplicantPeerInfo *peer_info) { NMWifiP2PPeerPrivate *priv; - const guint8 *bytes; - GVariant *v; - gsize len; - const char *s; - const char **sv; - gint32 i32; gboolean changed = FALSE; g_return_val_if_fail (NM_IS_WIFI_P2P_PEER (peer), FALSE); - g_return_val_if_fail (properties, 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); - g_object_freeze_notify (G_OBJECT (peer)); - - if (g_variant_lookup (properties, "level", "i", &i32)) - changed |= nm_wifi_p2p_peer_set_strength (peer, nm_wifi_utils_level_to_quality (i32)); - - if (g_variant_lookup (properties, "DeviceName", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_name (peer, s); - - if (g_variant_lookup (properties, "Manufacturer", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_manufacturer (peer, s); - - if (g_variant_lookup (properties, "Model", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_model (peer, s); - - if (g_variant_lookup (properties, "ModelNumber", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_model_number (peer, s); - - if (g_variant_lookup (properties, "Serial", "&s", &s)) - changed |= nm_wifi_p2p_peer_set_serial (peer, s); + nm_assert ( !priv->supplicant_path + || priv->supplicant_path == peer_info->peer_path); - v = g_variant_lookup_value (properties, "DeviceAddress", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - if ( len == ETH_ALEN - && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 - && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) - changed |= nm_wifi_p2p_peer_set_address_bin (peer, bytes); - g_variant_unref (v); - } - - /* The IEs property contains the WFD R1 subelements */ - v = g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); - if (v) { - gs_unref_bytes GBytes *b = NULL; - - bytes = g_variant_get_fixed_array (v, &len, 1); - b = g_bytes_new (bytes, len); - changed |= nm_wifi_p2p_peer_set_wfd_ies (peer, b); - g_variant_unref (v); - } - - v = g_variant_lookup_value (properties, "Groups", G_VARIANT_TYPE_OBJECT_PATH_ARRAY); - if (v) { - sv = g_variant_get_objv (v, NULL); - changed |= nm_wifi_p2p_peer_set_groups (peer, sv); - g_free (sv); - } - - /*if (max_rate) - changed |= nm_wifi_p2p_peer_set_max_bitrate (peer, max_rate / 1000);*/ + g_object_freeze_notify (G_OBJECT (peer)); if (!priv->supplicant_path) { - priv->supplicant_path = g_strdup (supplicant_path); + priv->supplicant_path = nm_ref_string_ref (peer_info->peer_path); changed = TRUE; } - changed |= nm_wifi_p2p_peer_set_last_seen (peer, nm_utils_get_monotonic_timestamp_s ()); + 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); g_object_thaw_notify (G_OBJECT (peer)); @@ -521,7 +430,7 @@ nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self, priv = NM_WIFI_P2P_PEER_GET_PRIVATE (self); if (priv->supplicant_path) - supplicant_id = strrchr (priv->supplicant_path, '/') ?: supplicant_id; + supplicant_id = strrchr (priv->supplicant_path->str, '/') ?: supplicant_id; export_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (self)); if (export_path) @@ -537,7 +446,7 @@ nm_wifi_p2p_peer_to_string (const NMWifiP2PPeer *self, priv->model, priv->model_number, priv->serial, - priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_s ()) - priv->last_seen) : -1, + priv->last_seen > 0 ? ((now_s > 0 ? now_s : nm_utils_get_monotonic_timestamp_sec ()) - priv->last_seen) : -1, supplicant_id, export_path); @@ -601,12 +510,6 @@ get_property (GObject *object, guint prop_id, case PROP_WFD_IES: g_value_take_variant (value, nm_utils_gbytes_to_variant_ay (priv->wfd_ies)); break; - case PROP_GROUPS: - g_value_set_variant (value, - g_variant_new_strv ( (const char*const*) priv->groups - ?: NM_PTRARRAY_EMPTY (const char *), - -1)); - break; case PROP_HW_ADDRESS: g_value_set_string (value, priv->address); break; @@ -616,7 +519,7 @@ get_property (GObject *object, guint prop_id, 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_NS_PER_SECOND) + ? (int) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NSEC_PER_SEC) : -1); break; default: @@ -643,22 +546,14 @@ nm_wifi_p2p_peer_init (NMWifiP2PPeer *self) } NMWifiP2PPeer * -nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path, GVariant *properties) +nm_wifi_p2p_peer_new_from_properties (const NMSupplicantPeerInfo *peer_info) { NMWifiP2PPeer *peer; - g_return_val_if_fail (supplicant_path != NULL, NULL); - g_return_val_if_fail (properties != NULL, NULL); - - peer = (NMWifiP2PPeer *) g_object_new (NM_TYPE_WIFI_P2P_PEER, NULL); - nm_wifi_p2p_peer_update_from_properties (peer, supplicant_path, properties); - - /* ignore peers with invalid or missing address */ - if (!nm_wifi_p2p_peer_get_address (peer)) { - g_object_unref (peer); - return NULL; - } + 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; } @@ -671,7 +566,7 @@ finalize (GObject *object) nm_assert (!self->wifi_device); nm_assert (c_list_is_empty (&self->peers_lst)); - g_free (priv->supplicant_path); + nm_ref_string_unref (priv->supplicant_path); g_free (priv->name); g_free (priv->manufacturer); g_free (priv->model); @@ -688,6 +583,7 @@ 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), @@ -695,7 +591,6 @@ static const NMDBusInterfaceInfoExtended interface_info_p2p_peer = { 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 ("Groups", "as", NM_WIFI_P2P_PEER_GROUPS), 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), @@ -756,12 +651,6 @@ nm_wifi_p2p_peer_class_init (NMWifiP2PPeerClass *klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_GROUPS] = - g_param_spec_variant (NM_WIFI_P2P_PEER_GROUPS, "", "", - G_VARIANT_TYPE ("as"), - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_HW_ADDRESS] = g_param_spec_string (NM_WIFI_P2P_PEER_HW_ADDRESS, "", "", NULL, diff --git a/src/devices/wifi/nm-wifi-p2p-peer.h b/src/devices/wifi/nm-wifi-p2p-peer.h index 07f25cc1..59f9c5d2 100644 --- a/src/devices/wifi/nm-wifi-p2p-peer.h +++ b/src/devices/wifi/nm-wifi-p2p-peer.h @@ -24,7 +24,6 @@ #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_GROUPS "groups" #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" @@ -38,14 +37,14 @@ typedef struct { typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass; +struct _NMSupplicantPeerInfo; + GType nm_wifi_p2p_peer_get_type (void); -NMWifiP2PPeer * nm_wifi_p2p_peer_new_from_properties (const char *supplicant_path, - GVariant *properties); +NMWifiP2PPeer *nm_wifi_p2p_peer_new_from_properties (const struct _NMSupplicantPeerInfo *peer_info); -gboolean nm_wifi_p2p_peer_update_from_properties (NMWifiP2PPeer *peer, - const char *supplicant_path, - GVariant *properties); +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); diff --git a/src/devices/wifi/nm-wifi-utils.c b/src/devices/wifi/nm-wifi-utils.c index b9b7ec42..0903dc8b 100644 --- a/src/devices/wifi/nm-wifi-utils.c +++ b/src/devices/wifi/nm-wifi-utils.c @@ -759,6 +759,12 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL); + } else if ( (key_mgmt && !strcmp (key_mgmt, "owe")) + || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_OWE)) { + 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)) { @@ -780,25 +786,6 @@ nm_wifi_utils_complete_connection (GBytes *ap_ssid, return TRUE; } -guint32 -nm_wifi_utils_level_to_quality (int val) -{ - if (val < 0) { - /* Assume dBm already; rough conversion: best = -40, worst = -100 */ - val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */ - val = 100 - (int) ((100.0 * (double) val) / 60.0); - } else if (val > 110 && val < 256) { - /* assume old-style WEXT 8-bit unsigned signal level */ - val -= 256; /* subtract 256 to convert to dBm */ - val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */ - val = 100 - (int) ((100.0 * (double) val) / 60.0); - } else { - /* Assume signal is a "quality" percentage */ - } - - return CLAMP (val, 0, 100); -} - gboolean nm_wifi_utils_is_manf_default_ssid (GBytes *ssid) { diff --git a/src/devices/wifi/nm-wifi-utils.h b/src/devices/wifi/nm-wifi-utils.h index 982080b9..505baa84 100644 --- a/src/devices/wifi/nm-wifi-utils.h +++ b/src/devices/wifi/nm-wifi-utils.h @@ -30,8 +30,6 @@ gboolean nm_wifi_utils_complete_connection (GBytes *ssid, gboolean lock_bssid, GError **error); -guint32 nm_wifi_utils_level_to_quality (int val); - gboolean nm_wifi_utils_is_manf_default_ssid (GBytes *ssid); NMIwdNetworkSecurity nm_wifi_connection_get_iwd_security (NMConnection *connection, diff --git a/src/devices/wifi/tests/test-devices-wifi.c b/src/devices/wifi/tests/test-devices-wifi.c index a960e7a2..bde36307 100644 --- a/src/devices/wifi/tests/test-devices-wifi.c +++ b/src/devices/wifi/tests/test-devices-wifi.c @@ -6,6 +6,7 @@ #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" @@ -1337,6 +1338,60 @@ test_strength_all (void) /*****************************************************************************/ +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 @@ -1501,5 +1556,7 @@ main (int argc, char **argv) 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/meson.build b/src/devices/wwan/meson.build index ed6f8010..97252edc 100644 --- a/src/devices/wwan/meson.build +++ b/src/devices/wwan/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + nm_service_providers_source = files('nm-service-providers.c') sources = nm_service_providers_source + files( diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 3de5ae07..a2f2e7a6 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -156,7 +156,7 @@ modem_prepare_result (NMModem *modem, } priv->stage1_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -191,7 +191,7 @@ modem_auth_result (NMModem *modem, GError *error, gpointer user_data) } priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT; - nm_device_activate_schedule_stage1_device_prepare (device); + nm_device_activate_schedule_stage1_device_prepare (device, FALSE); } static void @@ -384,6 +384,15 @@ modem_state_cb (NMModem *modem, */ 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); } @@ -605,7 +614,6 @@ 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; } @@ -843,9 +851,9 @@ dispose (GObject *object) nm_clear_pointer (&priv->modem, nm_modem_unclaim); } - g_clear_pointer (&priv->device_id, g_free); - g_clear_pointer (&priv->operator_code, g_free); - g_clear_pointer (&priv->apn, g_free); + 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); } diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index 947aa4c8..f89ec86c 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -324,7 +324,7 @@ connect_context_clear (NMModemBroadband *self) ConnectContext *ctx = self->_priv.ctx; g_clear_error (&ctx->first_error); - g_clear_pointer (&ctx->ip_types, g_array_unref); + 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); diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c index b68cd7e8..2fc44881 100644 --- a/src/devices/wwan/nm-modem-ofono.c +++ b/src/devices/wwan/nm-modem-ofono.c @@ -449,7 +449,7 @@ handle_sim_iface (NMModemOfono *self, gboolean found) g_signal_handlers_disconnect_by_data (priv->sim_proxy, self); g_clear_object (&priv->sim_proxy); } - g_clear_pointer (&priv->imsi, g_free); + 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"); @@ -769,7 +769,7 @@ stage1_prepare_done (GObject *source, g_clear_object (&priv->context_proxy_cancellable); - g_clear_pointer (&priv->connect_properties, g_hash_table_destroy); + nm_clear_pointer (&priv->connect_properties, g_hash_table_destroy); if (error) { _LOGW ("connection failed: %s", error->message); diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index ad6449b1..bedc3844 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -975,7 +975,8 @@ modem_secrets_cb (NMActRequest *req, priv->secrets_id = NULL; - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + 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) @@ -1710,7 +1711,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); const char *s; switch (prop_id) { @@ -1747,7 +1748,7 @@ set_property (GObject *object, guint prop_id, priv->ip_types = g_value_get_uint (value); break; case PROP_SIM_OPERATOR_ID: - g_clear_pointer (&priv->sim_operator_id, g_free); + 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); @@ -1796,7 +1797,7 @@ constructed (GObject *object) static void dispose (GObject *object) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); g_clear_object (&priv->act_request); @@ -1806,7 +1807,7 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE ((NMModem *) object); + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); g_free (priv->uid); g_free (priv->path); diff --git a/src/devices/wwan/nm-service-providers.c b/src/devices/wwan/nm-service-providers.c index 5140f7ed..5694c99e 100644 --- a/src/devices/wwan/nm-service-providers.c +++ b/src/devices/wwan/nm-service-providers.c @@ -118,11 +118,11 @@ parser_gsm_start (ParseContext *parse_context, } } else if (strcmp (name, "apn") == 0) { parse_context->found_internet_apn = FALSE; - g_clear_pointer (&parse_context->apn, g_free); - g_clear_pointer (&parse_context->username, g_free); - g_clear_pointer (&parse_context->password, g_free); - g_clear_pointer (&parse_context->gateway, g_free); - g_clear_pointer (&parse_context->auth_method, g_free); + 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; @@ -155,7 +155,7 @@ parser_gsm_apn_start (ParseContext *parse_context, } else if (strcmp (name, "authentication") == 0) { for (i = 0; attribute_names && attribute_names[i]; i++) { if (strcmp (attribute_names[i], "method") == 0) { - g_clear_pointer (&parse_context->auth_method, g_free); + nm_clear_g_free (&parse_context->auth_method); parse_context->auth_method = g_strstrip (g_strdup (attribute_values[i])); break; } @@ -173,7 +173,7 @@ parser_start_element (GMarkupParseContext *context, { ParseContext *parse_context = user_data; - g_clear_pointer (&parse_context->text_buffer, g_free); + nm_clear_g_free (&parse_context->text_buffer); switch (parse_context->state) { case PARSER_TOPLEVEL: @@ -205,7 +205,7 @@ parser_country_end (ParseContext *parse_context, const char *name) { if (strcmp (name, "country") == 0) { - g_clear_pointer (&parse_context->text_buffer, g_free); + nm_clear_g_free (&parse_context->text_buffer); parse_context->state = PARSER_TOPLEVEL; } } @@ -215,7 +215,7 @@ parser_provider_end (ParseContext *parse_context, const char *name) { if (strcmp (name, "provider") == 0) { - g_clear_pointer (&parse_context->text_buffer, g_free); + nm_clear_g_free (&parse_context->text_buffer); parse_context->state = PARSER_COUNTRY; } } @@ -225,7 +225,7 @@ parser_gsm_end (ParseContext *parse_context, const char *name) { if (strcmp (name, "gsm") == 0) { - g_clear_pointer (&parse_context->text_buffer, g_free); + nm_clear_g_free (&parse_context->text_buffer); parse_context->state = PARSER_PROVIDER; } } @@ -235,19 +235,19 @@ parser_gsm_apn_end (ParseContext *parse_context, const char *name) { if (strcmp (name, "username") == 0) { - g_clear_pointer (&parse_context->username, g_free); + nm_clear_g_free (&parse_context->username); parse_context->username = g_steal_pointer (&parse_context->text_buffer); } else if (strcmp (name, "password") == 0) { - g_clear_pointer (&parse_context->password, g_free); + 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) { - g_clear_pointer (&parse_context->gateway, g_free); + nm_clear_g_free (&parse_context->gateway); parse_context->gateway = g_steal_pointer (&parse_context->text_buffer); } else if (strcmp (name, "apn") == 0) { - g_clear_pointer (&parse_context->text_buffer, g_free); + nm_clear_g_free (&parse_context->text_buffer); if (parse_context->mccmnc_matched && parse_context->found_internet_apn) parse_context->state = PARSER_DONE; @@ -262,7 +262,7 @@ parser_cdma_end (ParseContext *parse_context, const char *name) { if (strcmp (name, "cdma") == 0) { - g_clear_pointer (&parse_context->text_buffer, g_free); + nm_clear_g_free (&parse_context->text_buffer); parse_context->state = PARSER_PROVIDER; } } diff --git a/src/dhcp/meson.build b/src/dhcp/meson.build index 609fe663..67f055d9 100644 --- a/src/dhcp/meson.build +++ b/src/dhcp/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + name = 'nm-dhcp-helper' c_flags = [ diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c index 81c4ad9c..90a64aca 100644 --- a/src/dhcp/nm-dhcp-client.c +++ b/src/dhcp/nm-dhcp-client.c @@ -925,7 +925,7 @@ nm_dhcp_client_handle_event (gpointer unused, && !ip_config) { _LOGW ("client bound but IP config not received"); new_state = NM_DHCP_STATE_FAIL; - g_clear_pointer (&str_options, g_hash_table_unref); + nm_clear_pointer (&str_options, g_hash_table_unref); } nm_dhcp_client_set_state (self, new_state, ip_config, str_options); @@ -940,7 +940,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (object); switch (prop_id) { case PROP_IFACE: @@ -989,7 +989,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object); + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (object); guint flags; switch (prop_id) { @@ -1099,12 +1099,12 @@ dispose (GObject *object) watch_cleanup (self); timeout_cleanup (self); - g_clear_pointer (&priv->iface, g_free); - g_clear_pointer (&priv->hostname, g_free); - g_clear_pointer (&priv->uuid, g_free); - g_clear_pointer (&priv->client_id, g_bytes_unref); - g_clear_pointer (&priv->hwaddr, g_bytes_unref); - g_clear_pointer (&priv->bcast_hwaddr, g_bytes_unref); + nm_clear_g_free (&priv->iface); + nm_clear_g_free (&priv->hostname); + nm_clear_g_free (&priv->uuid); + nm_clear_pointer (&priv->client_id, g_bytes_unref); + nm_clear_pointer (&priv->hwaddr, g_bytes_unref); + nm_clear_pointer (&priv->bcast_hwaddr, g_bytes_unref); G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object); diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c index f31c493c..da28abad 100644 --- a/src/dhcp/nm-dhcp-dhclient-utils.c +++ b/src/dhcp/nm-dhcp-dhclient-utils.c @@ -385,7 +385,7 @@ nm_dhcp_dhclient_create_config (const char *interface, /* Otherwise capture and return the existing client id */ if (out_new_client_id) - g_clear_pointer (out_new_client_id, g_bytes_unref); + nm_clear_pointer (out_new_client_id, g_bytes_unref); NM_SET_OUT (out_new_client_id, read_client_id (p)); } diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c index 869966fb..617ce236 100644 --- a/src/dhcp/nm-dhcp-dhclient.c +++ b/src/dhcp/nm-dhcp-dhclient.c @@ -665,7 +665,7 @@ nm_dhcp_dhclient_init (NMDhcpDhclient *self) static void dispose (GObject *object) { - NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE ((NMDhcpDhclient *) object); + NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (object); if (priv->dhcp_listener) { g_signal_handlers_disconnect_by_func (priv->dhcp_listener, diff --git a/src/dhcp/nm-dhcp-dhcpcanon.c b/src/dhcp/nm-dhcp-dhcpcanon.c index f9cc0f0a..63484a4b 100644 --- a/src/dhcp/nm-dhcp-dhcpcanon.c +++ b/src/dhcp/nm-dhcp-dhcpcanon.c @@ -207,7 +207,7 @@ nm_dhcp_dhcpcanon_init (NMDhcpDhcpcanon *self) static void dispose (GObject *object) { - NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE ((NMDhcpDhcpcanon *) object); + NMDhcpDhcpcanonPrivate *priv = NM_DHCP_DHCPCANON_GET_PRIVATE (object); if (priv->dhcp_listener) { g_signal_handlers_disconnect_by_func (priv->dhcp_listener, diff --git a/src/dhcp/nm-dhcp-dhcpcd.c b/src/dhcp/nm-dhcp-dhcpcd.c index 1690bce5..ff695dbe 100644 --- a/src/dhcp/nm-dhcp-dhcpcd.c +++ b/src/dhcp/nm-dhcp-dhcpcd.c @@ -200,7 +200,7 @@ nm_dhcp_dhcpcd_init (NMDhcpDhcpcd *self) static void dispose (GObject *object) { - NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE ((NMDhcpDhcpcd *) object); + NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (object); if (priv->dhcp_listener) { g_signal_handlers_disconnect_by_func (priv->dhcp_listener, diff --git a/src/dhcp/nm-dhcp-listener.c b/src/dhcp/nm-dhcp-listener.c index a54b9643..79dea898 100644 --- a/src/dhcp/nm-dhcp-listener.c +++ b/src/dhcp/nm-dhcp-listener.c @@ -287,12 +287,12 @@ nm_dhcp_listener_init (NMDhcpListener *self) static void dispose (GObject *object) { - NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE ((NMDhcpListener *) object); + NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (object); nm_clear_g_signal_handler (priv->dbus_mgr, &priv->new_conn_id); nm_clear_g_signal_handler (priv->dbus_mgr, &priv->dis_conn_id); - g_clear_pointer (&priv->connections, g_hash_table_destroy); + nm_clear_pointer (&priv->connections, g_hash_table_destroy); g_clear_object (&priv->dbus_mgr); diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c index 10ed9589..333744dd 100644 --- a/src/dhcp/nm-dhcp-manager.c +++ b/src/dhcp/nm-dhcp-manager.c @@ -515,7 +515,7 @@ nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostna { NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (manager); - g_clear_pointer (&priv->default_hostname, g_free); + nm_clear_g_free (&priv->default_hostname); /* Never send 'localhost'-type names to the DHCP server */ if (!nm_utils_is_specific_hostname (hostname)) diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h index fb1c9834..1b793c22 100644 --- a/src/dhcp/nm-dhcp-manager.h +++ b/src/dhcp/nm-dhcp-manager.h @@ -9,7 +9,7 @@ #include "nm-dhcp-client.h" #include "nm-ip4-config.h" -#include "nm-dhcp4-config.h" +#include "nm-dhcp-config.h" #define NM_TYPE_DHCP_MANAGER (nm_dhcp_manager_get_type ()) #define NM_DHCP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_MANAGER, NMDhcpManager)) diff --git a/src/dhcp/nm-dhcp-nettools.c b/src/dhcp/nm-dhcp-nettools.c index 622251a3..00b416da 100644 --- a/src/dhcp/nm-dhcp-nettools.c +++ b/src/dhcp/nm-dhcp-nettools.c @@ -49,8 +49,7 @@ typedef struct { NDhcp4Client *client; NDhcp4ClientProbe *probe; NDhcp4ClientLease *lease; - GIOChannel *channel; - guint event_id; + GSource *event_source; char *lease_file; } NMDhcpNettoolsPrivate; @@ -376,8 +375,8 @@ lease_parse_address (NDhcp4ClientLease *lease, * Here we still do it... it seems safe enough. */ nm_assert (nettools_basetime > 0); nm_assert (nettools_lifetime >= nettools_basetime); - nm_assert (((nettools_lifetime - nettools_basetime) % NM_UTILS_NS_PER_SECOND) == 0); - nm_assert ((nettools_lifetime - nettools_basetime) / NM_UTILS_NS_PER_SECOND <= G_MAXUINT32); + nm_assert (((nettools_lifetime - nettools_basetime) % NM_UTILS_NSEC_PER_SEC) == 0); + nm_assert ((nettools_lifetime - nettools_basetime) / NM_UTILS_NSEC_PER_SEC <= G_MAXUINT32); if (nettools_lifetime <= nettools_basetime) { /* A lease time of 0 is allowed on some dhcp servers, so, let's accept it. */ @@ -387,7 +386,7 @@ lease_parse_address (NDhcp4ClientLease *lease, /* we "ceil" the value to the next second. In practice, we don't expect any sub-second values * from n-dhcp4 anyway, so this should have no effect. */ - lifetime += NM_UTILS_NS_PER_SECOND - 1; + lifetime += NM_UTILS_NSEC_PER_SEC - 1; } ts = nm_utils_monotonic_timestamp_from_boottime (nettools_basetime, 1); @@ -395,11 +394,11 @@ lease_parse_address (NDhcp4ClientLease *lease, /* the timestamp must be positive, because we only started nettools DHCP client * after obtaining the first monotonic timestamp. Hence, the lease must have been * received afterwards. */ - nm_assert (ts >= NM_UTILS_NS_PER_SECOND); + nm_assert (ts >= NM_UTILS_NSEC_PER_SEC); - a_timestamp = ts / NM_UTILS_NS_PER_SECOND; - a_lifetime = NM_MIN (lifetime / NM_UTILS_NS_PER_SECOND, NM_PLATFORM_LIFETIME_PERMANENT - 1); - a_expiry = time (NULL) + ((lifetime - (nm_utils_clock_gettime_ns (CLOCK_BOOTTIME) - nettools_basetime)) / NM_UTILS_NS_PER_SECOND); + a_timestamp = ts / NM_UTILS_NSEC_PER_SEC; + a_lifetime = NM_MIN (lifetime / NM_UTILS_NSEC_PER_SEC, NM_PLATFORM_LIFETIME_PERMANENT - 1); + a_expiry = time (NULL) + ((lifetime - (nm_utils_clock_gettime_nsec (CLOCK_BOOTTIME) - nettools_basetime)) / NM_UTILS_NSEC_PER_SEC); } if (!lease_get_in_addr (lease, NM_DHCP_OPTION_DHCP4_SUBNET_MASK, &a_netmask)) { @@ -407,7 +406,7 @@ lease_parse_address (NDhcp4ClientLease *lease, return FALSE; } - nm_utils_inet4_ntop (a_address.s_addr, addr_str); + _nm_utils_inet4_ntop (a_address.s_addr, addr_str); a_plen = nm_utils_ip4_netmask_to_prefix (a_netmask.s_addr); nm_dhcp_option_add_option (options, @@ -417,7 +416,7 @@ lease_parse_address (NDhcp4ClientLease *lease, nm_dhcp_option_add_option (options, _nm_dhcp_option_dhcp4_options, NM_DHCP_OPTION_DHCP4_SUBNET_MASK, - nm_utils_inet4_ntop (a_netmask.s_addr, addr_str)); + _nm_utils_inet4_ntop (a_netmask.s_addr, addr_str)); nm_dhcp_option_add_option_u64 (options, _nm_dhcp_option_dhcp4_options, @@ -434,7 +433,7 @@ lease_parse_address (NDhcp4ClientLease *lease, n_dhcp4_client_lease_get_siaddr (lease, &a_next_server); if (a_next_server.s_addr != INADDR_ANY) { - nm_utils_inet4_ntop (a_next_server.s_addr, addr_str); + _nm_utils_inet4_ntop (a_next_server.s_addr, addr_str); nm_dhcp_option_add_option (options, _nm_dhcp_option_dhcp4_options, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, @@ -475,7 +474,7 @@ lease_parse_domain_name_servers (NDhcp4ClientLease *lease, while (lease_option_next_in_addr (&addr, &data, &n_data)) { - nm_utils_inet4_ntop (addr.s_addr, addr_str); + _nm_utils_inet4_ntop (addr.s_addr, addr_str); g_string_append (nm_gstring_add_space_delimiter (str), addr_str); if ( addr.s_addr == 0 @@ -521,8 +520,8 @@ lease_parse_routes (NDhcp4ClientLease *lease, while (lease_option_next_route (&dest, &plen, &gateway, TRUE, &data, &n_data)) { - nm_utils_inet4_ntop (dest.s_addr, dest_str); - nm_utils_inet4_ntop (gateway.s_addr, gateway_str); + _nm_utils_inet4_ntop (dest.s_addr, dest_str); + _nm_utils_inet4_ntop (gateway.s_addr, gateway_str); g_string_append_printf (nm_gstring_add_space_delimiter (str), "%s/%d %s", @@ -565,8 +564,8 @@ lease_parse_routes (NDhcp4ClientLease *lease, while (lease_option_next_route (&dest, &plen, &gateway, FALSE, &data, &n_data)) { - nm_utils_inet4_ntop (dest.s_addr, dest_str); - nm_utils_inet4_ntop (gateway.s_addr, gateway_str); + _nm_utils_inet4_ntop (dest.s_addr, dest_str); + _nm_utils_inet4_ntop (gateway.s_addr, gateway_str); g_string_append_printf (nm_gstring_add_space_delimiter (str), "%s/%d %s", @@ -611,7 +610,7 @@ lease_parse_routes (NDhcp4ClientLease *lease, nm_gstring_prepare (&str); while (lease_option_next_in_addr (&gateway, &data, &n_data)) { - s = nm_utils_inet4_ntop (gateway.s_addr, gateway_str); + s = _nm_utils_inet4_ntop (gateway.s_addr, gateway_str); g_string_append (nm_gstring_add_space_delimiter (str), s); if (gateway.s_addr == 0) { @@ -710,7 +709,7 @@ lease_parse_ntps (NDhcp4ClientLease *lease, nm_gstring_prepare (&str); while (lease_option_next_in_addr (&addr, &data, &n_data)) { - nm_utils_inet4_ntop (addr.s_addr, addr_str); + _nm_utils_inet4_ntop (addr.s_addr, addr_str); g_string_append (nm_gstring_add_space_delimiter (str), addr_str); } @@ -967,7 +966,7 @@ lease_save (NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fi return; g_string_append_printf (new_contents, - "ADDRESS=%s\n", nm_utils_inet4_ntop (a_address.s_addr, sbuf)); + "ADDRESS=%s\n", _nm_utils_inet4_ntop (a_address.s_addr, sbuf)); if (!g_file_set_contents (lease_file, new_contents->str, @@ -1054,7 +1053,7 @@ dhcp4_event_handle (NMDhcpNettools *self, } static gboolean -dhcp4_event_cb (GIOChannel *source, +dhcp4_event_cb (int fd, GIOCondition condition, gpointer data) { @@ -1073,7 +1072,7 @@ dhcp4_event_cb (GIOChannel *source, * a predefined number of times (possibly infinite). */ _LOGE ("error %d dispatching events", r); - priv->event_id = 0; + nm_clear_g_source_inst (&priv->event_source); nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL); return G_SOURCE_REMOVE; } @@ -1199,8 +1198,14 @@ nettools_create (NMDhcpNettools *self, client = NULL; n_dhcp4_client_get_fd (priv->client, &fd); - priv->channel = g_io_channel_unix_new (fd); - priv->event_id = g_io_add_watch (priv->channel, G_IO_IN, dhcp4_event_cb, self); + + priv->event_source = nm_g_unix_fd_source_new (fd, + G_IO_IN, + G_PRIORITY_DEFAULT, + dhcp4_event_cb, + self, + NULL); + g_source_attach (priv->event_source, NULL); return TRUE; } @@ -1427,11 +1432,10 @@ nm_dhcp_nettools_init (NMDhcpNettools *self) static void dispose (GObject *object) { - NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE ((NMDhcpNettools *) object); + NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE (object); nm_clear_pointer (&priv->lease_file, g_free); - nm_clear_pointer (&priv->channel, g_io_channel_unref); - nm_clear_g_source (&priv->event_id); + nm_clear_g_source_inst (&priv->event_source); nm_clear_pointer (&priv->lease, n_dhcp4_client_lease_unref); nm_clear_pointer (&priv->probe, n_dhcp4_client_probe_free); nm_clear_pointer (&priv->client, n_dhcp4_client_unref); diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index 6e6aa243..23862e9e 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -93,7 +93,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, gboolean has_router_from_classless = FALSE; gboolean has_classless_route = FALSE; gboolean has_static_route = FALSE; - const gint32 ts = nm_utils_get_monotonic_timestamp_s (); + const gint32 ts = nm_utils_get_monotonic_timestamp_sec (); gint64 ts_time = time (NULL); struct in_addr a_address; struct in_addr a_netmask; @@ -128,7 +128,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, options = out_options ? nm_dhcp_option_create_options_dict () : NULL; - nm_utils_inet4_ntop (a_address.s_addr, addr_str); + _nm_utils_inet4_ntop (a_address.s_addr, addr_str); nm_dhcp_option_add_option (options, _nm_dhcp_option_dhcp4_options, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, @@ -138,7 +138,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, nm_dhcp_option_add_option (options, _nm_dhcp_option_dhcp4_options, NM_DHCP_OPTION_DHCP4_SUBNET_MASK, - nm_utils_inet4_ntop (a_netmask.s_addr, addr_str)); + _nm_utils_inet4_ntop (a_netmask.s_addr, addr_str)); nm_dhcp_option_add_option_u64 (options, _nm_dhcp_option_dhcp4_options, @@ -150,7 +150,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, (guint64) (ts_time + a_lifetime)); if (sd_dhcp_lease_get_next_server (lease, &a_next_server) == 0) { - nm_utils_inet4_ntop (a_next_server.s_addr, addr_str); + _nm_utils_inet4_ntop (a_next_server.s_addr, addr_str); nm_dhcp_option_add_option (options, _nm_dhcp_option_dhcp4_options, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, @@ -169,7 +169,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, })); if (sd_dhcp_lease_get_server_identifier (lease, &server_id) >= 0) { - nm_utils_inet4_ntop (server_id.s_addr, addr_str); + _nm_utils_inet4_ntop (server_id.s_addr, addr_str); nm_dhcp_option_add_option (options, _nm_dhcp_option_dhcp4_options, NM_DHCP_OPTION_DHCP4_SERVER_ID, @@ -177,7 +177,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, } if (sd_dhcp_lease_get_broadcast (lease, &broadcast) >= 0) { - nm_utils_inet4_ntop (broadcast.s_addr, addr_str); + _nm_utils_inet4_ntop (broadcast.s_addr, addr_str); nm_dhcp_option_add_option (options, _nm_dhcp_option_dhcp4_options, NM_DHCP_OPTION_DHCP4_BROADCAST, @@ -188,7 +188,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, if (num > 0) { nm_gstring_prepare (&str); for (i = 0; i < num; i++) { - nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str); + _nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str); g_string_append (nm_gstring_add_space_delimiter (str), addr_str); if ( addr_list[i].s_addr == 0 @@ -288,8 +288,8 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, network_net = nm_utils_ip4_address_clear_host_address (r_network.s_addr, r_plen); - nm_utils_inet4_ntop (network_net, network_net_str); - nm_utils_inet4_ntop (r_gateway.s_addr, gateway_str); + _nm_utils_inet4_ntop (network_net, network_net_str); + _nm_utils_inet4_ntop (r_gateway.s_addr, gateway_str); g_string_append_printf (nm_gstring_add_space_delimiter ( option == NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE ? str_classless @@ -359,7 +359,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, for (i = 0; i < num; i++) { guint32 m; - s = nm_utils_inet4_ntop (a_router[i].s_addr, addr_str); + s = _nm_utils_inet4_ntop (a_router[i].s_addr, addr_str); g_string_append (nm_gstring_add_space_delimiter (str), s); if (a_router[i].s_addr == 0) { @@ -411,7 +411,7 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, if (num > 0) { nm_gstring_prepare (&str); for (i = 0; i < num; i++) { - nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str); + _nm_utils_inet4_ntop (addr_list[i].s_addr, addr_str); g_string_append (nm_gstring_add_space_delimiter (str), addr_str); } nm_dhcp_option_add_option (options, @@ -752,7 +752,7 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx, nm_ip6_config_add_address (ip6_config, &address); - nm_utils_inet6_ntop (&tmp_addr, addr_str); + _nm_utils_inet6_ntop (&tmp_addr, addr_str); g_string_append (nm_gstring_add_space_delimiter (str), addr_str); }; if (str->len) @@ -774,7 +774,7 @@ lease_to_ip6_config (NMDedupMultiIndex *multi_idx, if (num > 0) { nm_gstring_prepare (&str); for (i = 0; i < num; i++) { - nm_utils_inet6_ntop (&dns[i], addr_str); + _nm_utils_inet6_ntop (&dns[i], addr_str); g_string_append (nm_gstring_add_space_delimiter (str), addr_str); nm_ip6_config_add_nameserver (ip6_config, &dns[i]); } @@ -805,7 +805,7 @@ static void bound6_handle (NMDhcpSystemd *self) { NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); - const gint32 ts = nm_utils_get_monotonic_timestamp_s (); + const gint32 ts = nm_utils_get_monotonic_timestamp_sec (); const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self)); gs_unref_object NMIP6Config *ip6_config = NULL; gs_unref_hashtable GHashTable *options = NULL; @@ -1056,9 +1056,9 @@ nm_dhcp_systemd_init (NMDhcpSystemd *self) static void dispose (GObject *object) { - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE ((NMDhcpSystemd *) object); + NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (object); - g_clear_pointer (&priv->lease_file, g_free); + nm_clear_g_free (&priv->lease_file); if (priv->client4) { sd_dhcp_client_stop (priv->client4); diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index c5da3e02..d8e5a653 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -181,9 +181,9 @@ ip4_process_dhclient_rfc3442_routes (const char *iface, nm_ip4_config_add_route (ip4_config, &route, NULL); _LOG2I (LOGD_DHCP4, iface, " classless static route %s/%d gw %s", - nm_utils_inet4_ntop (route.network, b1), + _nm_utils_inet4_ntop (route.network, b1), route.plen, - nm_utils_inet4_ntop (route.gateway, b2)); + _nm_utils_inet4_ntop (route.gateway, b2)); } } @@ -388,7 +388,7 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx, ip4_config = nm_ip4_config_new (multi_idx, ifindex); memset (&address, 0, sizeof (address)); - address.timestamp = nm_utils_get_monotonic_timestamp_s (); + address.timestamp = nm_utils_get_monotonic_timestamp_sec (); str = g_hash_table_lookup (options, "ip_address"); if (str && (inet_pton (AF_INET, str, &addr) > 0)) @@ -414,7 +414,7 @@ nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx, process_classful_routes (iface, options, route_table, route_metric, ip4_config); if (gateway) { - _LOG2I (LOGD_DHCP4, iface, " gateway %s", nm_utils_inet4_ntop (gateway, sbuf)); + _LOG2I (LOGD_DHCP4, iface, " gateway %s", _nm_utils_inet4_ntop (gateway, sbuf)); gateway_has = TRUE; } else { /* If the gateway wasn't provided as a classless static route with a @@ -601,7 +601,7 @@ nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options) address.address = tmp_addr; address.addr_source = NM_IP_CONFIG_SOURCE_DHCP; address.plen = prefix; - address.timestamp = nm_utils_get_monotonic_timestamp_s (); + address.timestamp = nm_utils_get_monotonic_timestamp_sec (); str = g_hash_table_lookup (options, "max_life"); if (str) @@ -630,7 +630,7 @@ nm_dhcp_utils_ip6_config_from_options (NMDedupMultiIndex *multi_idx, memset (&address, 0, sizeof (address)); address.plen = 128; - address.timestamp = nm_utils_get_monotonic_timestamp_s (); + address.timestamp = nm_utils_get_monotonic_timestamp_sec (); ip6_config = nm_ip6_config_new (multi_idx, ifindex); diff --git a/src/dhcp/tests/meson.build b/src/dhcp/tests/meson.build index 031e2efd..59a647cc 100644 --- a/src/dhcp/tests/meson.build +++ b/src/dhcp/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_units = [ 'test-dhcp-dhclient', 'test-dhcp-utils', diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index a5028e42..fdff3af1 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -129,7 +129,7 @@ _gl_pid_kill_external_timeout_cb (gpointer user_data) goto process_gone; } - now = nm_utils_get_monotonic_timestamp_ms (); + now = nm_utils_get_monotonic_timestamp_msec (); if (gl_pid.kill_external_data->started_at + WAIT_MSEC_AFTER_SIGTERM < now) { if (!gl_pid.kill_external_data->sigkilled) { @@ -240,7 +240,7 @@ handle_kill: gl_pid.kill_external_data = g_slice_new (GlPidKillExternalData); *gl_pid.kill_external_data = (GlPidKillExternalData) { .shutdown_wait_handle = nm_shutdown_wait_obj_register_handle_full (g_strdup_printf ("kill-external-dnsmasq-process-%"G_PID_FORMAT, pid), TRUE), - .started_at = nm_utils_get_monotonic_timestamp_ms (), + .started_at = nm_utils_get_monotonic_timestamp_msec (), .pid = pid, .p_start_time = p_start_time, }; @@ -304,7 +304,7 @@ _gl_pid_spawn_notify (GlPidSpawnAsyncData *sdata, if (error) { nm_assert (pid == 0); nm_assert (!p_exit_code); - if (!nm_utils_error_is_cancelled (error, FALSE)) + if (!nm_utils_error_is_cancelled (error)) _LOGD ("spawn: dnsmasq failed: %s", error->message); } else if (p_exit_code) { /* the only caller already logged about this condition extensively. */ @@ -726,9 +726,9 @@ ip_addr_to_string (int addr_family, gconstpointer addr, const char *iface, char separator = "@"; } else { if (IN6_IS_ADDR_V4MAPPED (addr)) - nm_utils_inet4_ntop (((const struct in6_addr *) addr)->s6_addr32[3], buf2); + _nm_utils_inet4_ntop (((const struct in6_addr *) addr)->s6_addr32[3], buf2); else - nm_utils_inet6_ntop (addr, buf2); + _nm_utils_inet6_ntop (addr, buf2); /* Need to scope link-local addresses with %<zone-id>. Before dnsmasq 2.58, * only '@' was supported as delimiter. Since 2.58, '@' and '%' are * supported. Due to a bug, since 2.73 only '%' works properly as "server" @@ -838,7 +838,7 @@ dnsmasq_update_done (GObject *source_object, GAsyncResult *res, gpointer user_da response = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, &error); - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; self = user_data; @@ -987,7 +987,7 @@ spawn_notify (GCancellable *cancellable, NMDnsDnsmasq *self; NMDnsDnsmasqPrivate *priv; - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; self = notify_user_data; @@ -1058,7 +1058,7 @@ start_dnsmasq (NMDnsDnsmasq *self, gboolean force_start, GError **error) } } - now = nm_utils_get_monotonic_timestamp_ms (); + now = nm_utils_get_monotonic_timestamp_msec (); if ( force_start || priv->burst_start_at == 0 || priv->burst_start_at + RATELIMIT_INTERVAL_MSEC <= now) { @@ -1161,7 +1161,7 @@ dispose (GObject *object) _main_cleanup (self, FALSE); - g_clear_pointer (&priv->set_server_ex_args, g_variant_unref); + nm_clear_pointer (&priv->set_server_ex_args, g_variant_unref); G_OBJECT_CLASS (nm_dns_dnsmasq_parent_class)->dispose (object); diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index d731e7bf..b40dd6b6 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -178,7 +178,8 @@ domain_is_routing (const char *domain) /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConfManager, +static +NM_UTILS_LOOKUP_STR_DEFINE (_rc_manager_to_string, NMDnsManagerResolvConfManager, NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNKNOWN, "unknown"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED, "unmanaged"), @@ -189,7 +190,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConf NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, "netconfig"), ); -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_config_type_to_string, NMDnsIPConfigType, +static +NM_UTILS_LOOKUP_STR_DEFINE (_config_type_to_string, NMDnsIPConfigType, NM_UTILS_LOOKUP_DEFAULT_WARN ("<unknown>"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_REMOVED, "removed"), NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_IP_CONFIG_TYPE_DEFAULT, "default"), @@ -425,9 +427,9 @@ merge_one_ip_config (NMResolvConfData *rc, if (addr_family == AF_INET) nm_utils_inet_ntop (addr_family, addr, buf); else if (IN6_IS_ADDR_V4MAPPED (addr)) - nm_utils_inet4_ntop (addr->addr6.s6_addr32[3], buf); + _nm_utils_inet4_ntop (addr->addr6.s6_addr32[3], buf); else { - nm_utils_inet6_ntop (&addr->addr6, buf); + _nm_utils_inet6_ntop (&addr->addr6, buf); if (IN6_IS_ADDR_LINKLOCAL (addr)) { const char *ifname; @@ -457,7 +459,7 @@ merge_one_ip_config (NMResolvConfData *rc, num = nm_ip4_config_get_num_nis_servers (ip4_config); for (i = 0; i < num; i++) { add_string_item (rc->nis_servers, - nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (ip4_config, i), buf), + _nm_utils_inet4_ntop (nm_ip4_config_get_nis_server (ip4_config, i), buf), TRUE); } @@ -858,9 +860,11 @@ update_resolv_conf (NMDnsManager *self, if (!g_file_set_contents (rc_path, content, -1, &local)) { _LOGT ("update-resolv-conf: write to %s failed (rc-manager=%s, %s)", rc_path, _rc_manager_to_string (rc_manager), local->message); - write_file_result = SR_ERROR; g_propagate_error (error, local); + /* clear @error, so that we don't try reset it. This is the error + * we want to propagate to the caller. */ error = NULL; + write_file_result = SR_ERROR; } else { _LOGT ("update-resolv-conf: write to %s succeeded (rc-manager=%s)", rc_path, _rc_manager_to_string (rc_manager)); @@ -928,7 +932,7 @@ update_resolv_conf (NMDnsManager *self, if ( rc_manager != NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK || !_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link)) { _LOGT ("update-resolv-conf: write internal file %s succeeded", MY_RESOLV_CONF); - return SR_SUCCESS; + return write_file_result; } if (!nm_streq0 (_read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link), @@ -936,7 +940,7 @@ update_resolv_conf (NMDnsManager *self, _LOGT ("update-resolv-conf: write internal file %s succeeded (don't touch symlink %s linking to %s)", MY_RESOLV_CONF, _PATH_RESCONF, _read_link_cached (_PATH_RESCONF, &resconf_link_cached, &resconf_link)); - return SR_SUCCESS; + return write_file_result; } /* By this point, /etc/resolv.conf exists and is a symlink to our internal @@ -989,7 +993,7 @@ update_resolv_conf (NMDnsManager *self, _LOGT ("update-resolv-conf: write internal file %s succeeded and update symlink %s", MY_RESOLV_CONF, _PATH_RESCONF); - return SR_SUCCESS; + return write_file_result; } static void @@ -1161,7 +1165,7 @@ _collect_resolv_conf_data (NMDnsManager *self, const char *hostdomain = strchr (priv->hostname, '.'); if ( hostdomain - && !nm_utils_ipaddr_valid (AF_UNSPEC, priv->hostname)) { + && !nm_utils_ipaddr_is_valid (AF_UNSPEC, priv->hostname)) { hostdomain++; if (domain_is_valid (hostdomain, TRUE)) add_string_item (rc.searches, hostdomain, TRUE); @@ -1227,26 +1231,34 @@ get_ip_rdns_domains (NMIPConfig *ip_config) /* Check if the domain is shadowed by a parent domain with more negative priority */ static gboolean domain_is_shadowed (GHashTable *ht, - const char *domain, int priority, - const char **out_parent, int *out_parent_priority) + const char *domain, + int priority, + const char **out_parent, + int *out_parent_priority) { char *parent; int parent_priority; + if (!ht) + return FALSE; + nm_assert (!g_hash_table_contains (ht, domain)); parent_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, "")); - if (parent_priority < 0 && parent_priority < priority) { + if ( parent_priority < 0 + && parent_priority < priority) { *out_parent = ""; *out_parent_priority = parent_priority; return TRUE; } parent = strchr (domain, '.'); - while (parent && parent[1]) { + while ( parent + && parent[1]) { parent++; parent_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, parent)); - if (parent_priority < 0 && parent_priority < priority) { + if ( parent_priority < 0 + && parent_priority < priority) { *out_parent = parent; *out_parent_priority = parent_priority; return TRUE; @@ -1265,8 +1277,6 @@ rebuild_domain_lists (NMDnsManager *self) gboolean default_route_found = FALSE; CList *head; - ht = g_hash_table_new (nm_str_hash, g_str_equal); - head = _ip_config_lst_head (self); c_list_for_each_entry (ip_data, head, ip_config_lst) { NMIPConfig *ip_config = ip_data->ip_config; @@ -1281,55 +1291,71 @@ rebuild_domain_lists (NMDnsManager *self) c_list_for_each_entry (ip_data, head, ip_config_lst) { NMIPConfig *ip_config = ip_data->ip_config; - int priority, old_priority; - guint i, n, n_domains = 0; + int priority; const char **domains; + guint n_searches; + guint n_domains; + guint num_dom1; + guint num_dom2; + guint cap_dom; + guint i; if (!nm_ip_config_get_num_nameservers (ip_config)) continue; + n_searches = nm_ip_config_get_num_searches (ip_config); + n_domains = nm_ip_config_get_num_domains (ip_config); + priority = nm_ip_config_get_dns_priority (ip_config); nm_assert (priority != 0); + + cap_dom = 2u + NM_MAX (n_domains, n_searches); + g_free (ip_data->domains.search); - domains = g_new0 (const char *, - 2 + NM_MAX (nm_ip_config_get_num_searches (ip_config), - nm_ip_config_get_num_domains (ip_config))); + domains = g_new (const char *, cap_dom); ip_data->domains.search = domains; + num_dom1 = 0; + /* Add wildcard lookup domain to connections with the default route. * If there is no default route, add the wildcard domain to all non-VPN * connections */ if (default_route_found) { + /* FIXME: this heuristic of which device has a default route does + * not work with policy routing (as used by default with WireGuard). + * We should have a more stable mechanism where an NMIPConfig indicates + * whether it is suitable for certain operations (like having an automatically + * added "~" domain). */ if (nm_ip_config_best_default_route_get (ip_config)) - domains[n_domains++] = "~"; + domains[num_dom1++] = "~"; } else { if (ip_data->ip_config_type != NM_DNS_IP_CONFIG_TYPE_VPN) - domains[n_domains++] = "~"; + domains[num_dom1++] = "~"; } /* searches are preferred over domains */ - n = nm_ip_config_get_num_searches (ip_config); - for (i = 0; i < n; i++) - domains[n_domains++] = nm_ip_config_get_search (ip_config, i); - - if (n == 0) { - /* If not searches, use any domains */ - n = nm_ip_config_get_num_domains (ip_config); - for (i = 0; i < n; i++) - domains[n_domains++] = nm_ip_config_get_domain (ip_config, i); + if (n_searches > 0) { + for (i = 0; i < n_searches; i++) + domains[num_dom1++] = nm_ip_config_get_search (ip_config, i); + } else { + for (i = 0; i < n_domains; i++) + domains[num_dom1++] = nm_ip_config_get_domain (ip_config, i); } - n = 0; - for (i = 0; i < n_domains; i++) { + nm_assert (num_dom1 < cap_dom); + + num_dom2 = 0; + for (i = 0; i < num_dom1; i++) { const char *domain_clean; const char *parent; + int old_priority; int parent_priority; domain_clean = nm_utils_parse_dns_domain (domains[i], NULL); /* Remove domains with lower priority */ - old_priority = GPOINTER_TO_INT (g_hash_table_lookup (ht, domain_clean)); - if (old_priority) { + old_priority = GPOINTER_TO_INT (nm_g_hash_table_lookup (ht, domain_clean)); + if (old_priority != 0) { if (old_priority < priority) { _LOGT ("plugin: drop domain '%s' (i=%d, p=%d) because it already exists with p=%d", domains[i], ip_data->data->ifindex, @@ -1345,10 +1371,13 @@ rebuild_domain_lists (NMDnsManager *self) } _LOGT ("plugin: add domain '%s' (i=%d, p=%d)", domains[i], ip_data->data->ifindex, priority); + if (!ht) + ht = g_hash_table_new (nm_str_hash, g_str_equal); g_hash_table_insert (ht, (gpointer) domain_clean, GINT_TO_POINTER (priority)); - domains[n++] = domains[i]; + domains[num_dom2++] = domains[i]; } - domains[n] = NULL; + nm_assert (num_dom2 < cap_dom); + domains[num_dom2] = NULL; g_strfreev (ip_data->domains.reverse); ip_data->domains.reverse = get_ip_rdns_domains (ip_config); @@ -1363,8 +1392,8 @@ clear_domain_lists (NMDnsManager *self) head = _ip_config_lst_head (self); c_list_for_each_entry (ip_data, head, ip_config_lst) { - g_clear_pointer (&ip_data->domains.search, g_free); - g_clear_pointer (&ip_data->domains.reverse, g_strfreev); + nm_clear_g_free (&ip_data->domains.search); + nm_clear_pointer (&ip_data->domains.reverse, g_strfreev); } } @@ -1373,21 +1402,24 @@ update_dns (NMDnsManager *self, gboolean no_caching, GError **error) { - NMDnsManagerPrivate *priv; + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); const char *nis_domain = NULL; gs_strfreev char **searches = NULL; gs_strfreev char **options = NULL; gs_strfreev char **nameservers = NULL; gs_strfreev char **nis_servers = NULL; - gboolean caching = FALSE, update = TRUE; + gboolean caching = FALSE; + gboolean do_update = TRUE; gboolean resolv_conf_updated = FALSE; - SpawnResult result = SR_ERROR; + SpawnResult result = SR_SUCCESS; NMConfigData *data; NMGlobalDnsConfig *global_config; + gs_free_error GError *local_error = NULL; + GError **const p_local_error = error + ? &local_error + : NULL; - g_return_val_if_fail (!error || !*error, FALSE); - - priv = NM_DNS_MANAGER_GET_PRIVATE (self); + nm_assert (!error || !*error); if (priv->is_stopped) { _LOGD ("update-dns: not updating resolv.conf (is stopped)"); @@ -1398,7 +1430,7 @@ update_dns (NMDnsManager *self, if (NM_IN_SET (priv->rc_manager, NM_DNS_MANAGER_RESOLV_CONF_MAN_UNMANAGED, NM_DNS_MANAGER_RESOLV_CONF_MAN_IMMUTABLE)) { - update = FALSE; + do_update = FALSE; _LOGD ("update-dns: not updating resolv.conf"); } else { priv->dns_touched = TRUE; @@ -1436,7 +1468,7 @@ update_dns (NMDnsManager *self, if (no_caching) { _LOGD ("update-dns: plugin %s ignored (caching disabled)", plugin_name); - goto skip; + goto plugin_skip; } caching = TRUE; } @@ -1455,7 +1487,7 @@ update_dns (NMDnsManager *self, caching = FALSE; } - skip: +plugin_skip: ; } @@ -1486,7 +1518,7 @@ update_dns (NMDnsManager *self, nameservers[0] = g_strdup (lladdr); } - if (update) { + if (do_update) { switch (priv->rc_manager) { case NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK: case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: @@ -1494,7 +1526,7 @@ update_dns (NMDnsManager *self, NM_CAST_STRV_CC (searches), NM_CAST_STRV_CC (nameservers), NM_CAST_STRV_CC (options), - error, + p_local_error, priv->rc_manager); resolv_conf_updated = TRUE; /* If we have ended with no nameservers avoid updating again resolv.conf @@ -1503,7 +1535,11 @@ update_dns (NMDnsManager *self, priv->dns_touched = FALSE; break; case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: - result = dispatch_resolvconf (self, searches, nameservers, options, error); + result = dispatch_resolvconf (self, + searches, + nameservers, + options, + p_local_error); break; case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: result = dispatch_netconfig (self, @@ -1511,20 +1547,20 @@ update_dns (NMDnsManager *self, (const char *const*) nameservers, nis_domain, (const char *const*) nis_servers, - error); + p_local_error); break; default: - g_assert_not_reached (); + nm_assert_not_reached (); } if (result == SR_NOTFOUND) { _LOGD ("update-dns: program not available, writing to resolv.conf"); - g_clear_error (error); + g_clear_error (&local_error); result = update_resolv_conf (self, NM_CAST_STRV_CC (searches), NM_CAST_STRV_CC (nameservers), NM_CAST_STRV_CC (options), - error, + p_local_error, NM_DNS_MANAGER_RESOLV_CONF_MAN_SYMLINK); resolv_conf_updated = TRUE; } @@ -1542,13 +1578,21 @@ update_dns (NMDnsManager *self, } /* signal that resolv.conf was changed */ - if (update && result == SR_SUCCESS) + if ( do_update + && result == SR_SUCCESS) g_signal_emit (self, signals[CONFIG_CHANGED], 0); - g_clear_pointer (&priv->config_variant, g_variant_unref); + nm_clear_pointer (&priv->config_variant, g_variant_unref); _notify (self, PROP_CONFIGURATION); - return !update || result == SR_SUCCESS; + if (result != SR_SUCCESS) { + if (error) + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + nm_assert (!local_error); + return TRUE; } /*****************************************************************************/ @@ -1569,7 +1613,6 @@ nm_dns_manager_set_ip_config (NMDnsManager *self, NMDnsIPConfigType ip_config_type) { NMDnsManagerPrivate *priv; - GError *error = NULL; NMDnsIPConfigData *ip_data; NMDnsConfigData *data; int ifindex; @@ -1642,10 +1685,11 @@ nm_dns_manager_set_ip_config (NMDnsManager *self, } changed: - if ( !priv->updates_queue - && !update_dns (self, FALSE, &error)) { - _LOGW ("could not commit DNS changes: %s", error->message); - g_clear_error (&error); + if (!priv->updates_queue) { + gs_free_error GError *error = NULL; + + if (!update_dns (self, FALSE, &error)) + _LOGW ("could not commit DNS changes: %s", error->message); } return TRUE; @@ -1667,7 +1711,6 @@ nm_dns_manager_set_hostname (NMDnsManager *self, gboolean skip_update) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - GError *error = NULL; const char *filtered = NULL; /* Certain hostnames we don't want to include in resolv.conf 'searches' */ @@ -1687,9 +1730,12 @@ nm_dns_manager_set_hostname (NMDnsManager *self, if (skip_update) return; - if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { - _LOGW ("could not commit DNS changes: %s", error->message); - g_clear_error (&error); + + if (!priv->updates_queue) { + gs_free_error GError *error = NULL; + + if (!update_dns (self, FALSE, &error)) + _LOGW ("could not commit DNS changes: %s", error->message); } } @@ -1714,7 +1760,7 @@ void nm_dns_manager_end_updates (NMDnsManager *self, const char *func) { NMDnsManagerPrivate *priv; - GError *error = NULL; + gs_free_error GError *error = NULL; gboolean changed; guint8 new[HASH_LEN]; @@ -1735,10 +1781,8 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func) /* Commit all the outstanding changes */ _LOGD ("(%s): committing DNS changes (%d)", func, priv->updates_queue); - if (!update_dns (self, FALSE, &error)) { + if (!update_dns (self, FALSE, &error)) _LOGW ("could not commit DNS changes: %s", error->message); - g_clear_error (&error); - } memset (priv->prev_hash, 0, sizeof (priv->prev_hash)); } @@ -1747,7 +1791,6 @@ void nm_dns_manager_stop (NMDnsManager *self) { NMDnsManagerPrivate *priv; - GError *error = NULL; priv = NM_DNS_MANAGER_GET_PRIVATE (self); @@ -1764,10 +1807,11 @@ nm_dns_manager_stop (NMDnsManager *self) if ( priv->dns_touched && priv->plugin && NM_IS_DNS_DNSMASQ (priv->plugin)) { - if (!update_dns (self, TRUE, &error)) { + gs_free_error GError *error = NULL; + + if (!update_dns (self, TRUE, &error)) _LOGW ("could not commit DNS changes on shutdown: %s", error->message); - g_clear_error (&error); - } + priv->dns_touched = FALSE; } @@ -2041,8 +2085,6 @@ config_changed_cb (NMConfig *config, NMConfigData *old_data, NMDnsManager *self) { - GError *error = NULL; - if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_DNS_MODE | NM_CONFIG_CHANGE_RC_MANAGER | NM_CONFIG_CHANGE_CAUSE_SIGHUP | @@ -2063,10 +2105,10 @@ config_changed_cb (NMConfig *config, NM_CONFIG_CHANGE_DNS_MODE | NM_CONFIG_CHANGE_RC_MANAGER | NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) { - if (!update_dns (self, FALSE, &error)) { + gs_free_error GError *error = NULL; + + if (!update_dns (self, FALSE, &error)) _LOGW ("could not commit DNS changes: %s", error->message); - g_clear_error (&error); - } } } @@ -2296,7 +2338,7 @@ dispose (GObject *object) c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_config_lst_head, ip_config_lst) _ip_config_data_free (ip_data); - g_clear_pointer (&priv->configs, g_hash_table_destroy); + nm_clear_pointer (&priv->configs, g_hash_table_destroy); nm_clear_g_source (&priv->plugin_ratelimit.timer); @@ -2304,7 +2346,7 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_dns_manager_parent_class)->dispose (object); - g_clear_pointer (&priv->config_variant, g_variant_unref); + nm_clear_pointer (&priv->config_variant, g_variant_unref); } static void diff --git a/src/dnsmasq/nm-dnsmasq-manager.c b/src/dnsmasq/nm-dnsmasq-manager.c index 735605ee..5581f3fe 100644 --- a/src/dnsmasq/nm-dnsmasq-manager.c +++ b/src/dnsmasq/nm-dnsmasq-manager.c @@ -140,7 +140,7 @@ create_dm_cmd_line (const char *iface, */ nm_strv_ptrarray_add_string_dup (cmd, "--strict-order"); - nm_utils_inet4_ntop (listen_address->address, listen_address_s); + _nm_utils_inet4_ntop (listen_address->address, listen_address_s); nm_strv_ptrarray_add_string_concat (cmd, "--listen-address=", listen_address_s); @@ -169,7 +169,7 @@ create_dm_cmd_line (const char *iface, g_string_append (s, "--dhcp-option=option:dns-server"); for (i = 0; i < n; i++) { g_string_append_c (s, ','); - g_string_append (s, nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (ip4_config, i), tmpaddr)); + g_string_append (s, _nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (ip4_config, i), tmpaddr)); } nm_strv_ptrarray_take_gstring (cmd, &s); } @@ -339,7 +339,7 @@ nm_dnsmasq_manager_new (const char *iface) static void finalize (GObject *object) { - NMDnsMasqManagerPrivate *priv = NM_DNSMASQ_MANAGER_GET_PRIVATE ((NMDnsMasqManager *) object); + NMDnsMasqManagerPrivate *priv = NM_DNSMASQ_MANAGER_GET_PRIVATE (object); nm_dnsmasq_manager_stop (NM_DNSMASQ_MANAGER (object)); diff --git a/src/dnsmasq/nm-dnsmasq-utils.c b/src/dnsmasq/nm-dnsmasq-utils.c index 01d59ecc..2373b422 100644 --- a/src/dnsmasq/nm-dnsmasq-utils.c +++ b/src/dnsmasq/nm-dnsmasq-utils.c @@ -95,9 +95,8 @@ nm_dnsmasq_utils_get_range (const NMPlatformIP4Address *addr, first = htonl (first); last = htonl (last); - nm_utils_inet4_ntop (first, out_first); - nm_utils_inet4_ntop (last, out_last); + _nm_utils_inet4_ntop (first, out_first); + _nm_utils_inet4_ntop (last, out_last); return TRUE; } - diff --git a/src/dnsmasq/tests/meson.build b/src/dnsmasq/tests/meson.build index 6e429899..4584086e 100644 --- a/src/dnsmasq/tests/meson.build +++ b/src/dnsmasq/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_unit = 'test-dnsmasq-utils' exe = executable( diff --git a/src/initrd/meson.build b/src/initrd/meson.build index 09036f27..c056f3c2 100644 --- a/src/initrd/meson.build +++ b/src/initrd/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + sources = files( 'nmi-cmdline-reader.c', 'nmi-dt-reader.c', diff --git a/src/initrd/nm-initrd-generator.c b/src/initrd/nm-initrd-generator.c index f3f53acf..dccb21f8 100644 --- a/src/initrd/nm-initrd-generator.c +++ b/src/initrd/nm-initrd-generator.c @@ -6,7 +6,7 @@ #include "nm-default.h" #include "nm-core-utils.h" #include "nm-core-internal.h" -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" #include "nm-initrd-generator.h" #include "nm-glib-aux/nm-io-utils.h" @@ -109,7 +109,7 @@ main (int argc, char *argv[]) if (!sysfs_dir) sysfs_dir = g_strdup (DEFAULT_SYSFS_DIR); if (dump_to_stdout) - g_clear_pointer (&connections_dir, g_free); + nm_clear_g_free (&connections_dir); if (connections_dir && g_mkdir_with_parents (connections_dir, 0755) != 0) { errsv = errno; diff --git a/src/initrd/nmi-cmdline-reader.c b/src/initrd/nmi-cmdline-reader.c index 2cb93a2d..2eb6d7e5 100644 --- a/src/initrd/nmi-cmdline-reader.c +++ b/src/initrd/nmi-cmdline-reader.c @@ -17,33 +17,67 @@ /*****************************************************************************/ -static gboolean -_connection_matches_type (gpointer key, gpointer value, gpointer user_data) +typedef struct { + GHashTable *hash; + GPtrArray *array; + NMConnection *bootdev_connection; /* connection for bootdev=$ifname */ + NMConnection *default_connection; /* connection not bound to any ifname */ +} Reader; + +static Reader * +reader_new (void) { - NMConnection *connection = value; - const char *type_name = user_data; - NMSettingConnection *s_con; + Reader *reader; - s_con = nm_connection_get_setting_connection (connection); - if (type_name == NULL) - return nm_setting_connection_get_master (s_con) == NULL; - else - return strcmp (nm_setting_connection_get_connection_type (s_con), type_name) == 0; + reader = g_slice_new (Reader); + *reader = (Reader) { + .hash = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref), + .array = g_ptr_array_new (), + }; + + return reader; +} + +static GHashTable * +reader_destroy (Reader *reader, gboolean free_hash) +{ + gs_unref_hashtable GHashTable *hash = NULL; + + g_ptr_array_unref (reader->array); + hash = g_steal_pointer (&reader->hash); + nm_g_slice_free (reader); + if (!free_hash) + return g_steal_pointer (&hash); + return NULL; +} + +static NMConnection * +reader_add_connection (Reader *reader, const char *name, NMConnection *connection_take) +{ + char *name_dup; + + name_dup = g_strdup (name); + if (g_hash_table_insert (reader->hash, name_dup, connection_take)) + g_ptr_array_add (reader->array, name_dup); + + return connection_take; } +/* Returns a new connection owned by the reader */ static NMConnection * -add_conn (GHashTable *connections, - const char *basename, - const char *id, - const char *ifname, - const char *type_name, - NMConnectionMultiConnect multi_connect) +reader_create_connection (Reader *reader, + const char *basename, + const char *id, + const char *ifname, + const char *type_name, + NMConnectionMultiConnect multi_connect) { NMConnection *connection; NMSetting *setting; - connection = nm_simple_connection_new (); - g_hash_table_insert (connections, g_strdup (basename), connection); + connection = reader_add_connection (reader, + basename, + nm_simple_connection_new ()); /* Start off assuming dynamic IP configurations. */ @@ -76,44 +110,74 @@ add_conn (GHashTable *connections, } static NMConnection * -get_conn (GHashTable *connections, const char *ifname, const char *type_name) +reader_get_default_connection (Reader *reader) { - NMConnection *connection; + NMConnection *con; + + if (!reader->default_connection) { + con = reader_create_connection (reader, + "default_connection", + "Wired Connection", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NM_CONNECTION_MULTI_CONNECT_MULTIPLE); + reader->default_connection = con; + } + return reader->default_connection; +} + +static NMConnection * +reader_get_connection (Reader *reader, + const char *ifname, + const char *type_name, + gboolean create_if_missing) +{ + NMConnection *connection = NULL; NMSetting *setting; - const char *basename; - NMConnectionMultiConnect multi_connect; - if (ifname) { - basename = ifname; - multi_connect = NM_CONNECTION_MULTI_CONNECT_SINGLE; - } else { - /* This is essentially for the "ip=dhcp" scenario. */ - basename = "default_connection"; - multi_connect = NM_CONNECTION_MULTI_CONNECT_MULTIPLE; - } + if (!ifname) { + NMConnection *candidate; + NMSettingConnection *s_con; + guint i; - connection = g_hash_table_lookup (connections, (gpointer) basename); - if (!connection && !ifname) { /* * If ifname was not given, we'll match the connection by type. * If the type was not given either, then we're happy with any connection but slaves. * This is so that things like "bond=bond0:eth1,eth2 nameserver=1.3.3.7 end up * slapping the nameserver to the most reasonable connection (bond0). */ - connection = g_hash_table_find (connections, - _connection_matches_type, - (gpointer) type_name); - } + for (i = 0; i < reader->array->len; i++) { + candidate = g_hash_table_lookup (reader->hash, reader->array->pdata[i]); + s_con = nm_connection_get_setting_connection (candidate); + + if ( type_name == NULL + && nm_setting_connection_get_master (s_con) == NULL) { + connection = candidate; + break; + } + + if ( type_name != NULL + && nm_streq (nm_setting_connection_get_connection_type (s_con), type_name)) { + connection = candidate; + break; + } + } + } else + connection = g_hash_table_lookup (reader->hash, (gpointer) ifname); if (!connection) { + if (!create_if_missing) + return NULL; + if (!type_name) type_name = NM_SETTING_WIRED_SETTING_NAME; - connection = add_conn (connections, basename, - ifname ?: "Wired Connection", - ifname, type_name, multi_connect); + connection = reader_create_connection (reader, ifname, + ifname ?: "Wired Connection", + ifname, type_name, + NM_CONNECTION_MULTI_CONNECT_SINGLE); } - setting = (NMSetting *)nm_connection_get_setting_connection (connection); + setting = (NMSetting *) nm_connection_get_setting_connection (connection); if (type_name) { g_object_set (setting, NM_SETTING_CONNECTION_TYPE, type_name, NULL); @@ -195,22 +259,27 @@ _base_setting_set (NMConnection *connection, const char *property, const char *v } static void -read_all_connections_from_fw (GHashTable *connections, const char *sysfs_dir) +reader_read_all_connections_from_fw (Reader *reader, const char *sysfs_dir) { gs_unref_hashtable GHashTable *ibft = NULL; - NMConnection *connection; - GHashTableIter iter; + NMConnection *dt_connection; const char *mac; GHashTable *nic; const char *index; GError *error = NULL; + guint i, length; + gs_free const char **keys = NULL; ibft = nmi_ibft_read (sysfs_dir); + keys = nm_utils_strdict_get_keys (ibft, TRUE, &length); - g_hash_table_iter_init (&iter, ibft); - while (g_hash_table_iter_next (&iter, (gpointer *) &mac, (gpointer *) &nic)) { - connection = nm_simple_connection_new (); + for (i = 0; i < length; i++) { + gs_unref_object NMConnection *connection = NULL; + gs_free char *name = NULL; + mac = keys[i]; + nic = g_hash_table_lookup (ibft, mac); + connection = nm_simple_connection_new (); index = g_hash_table_lookup (nic, "index"); if (!index) { _LOGW (LOGD_CORE, "Ignoring an iBFT entry without an index"); @@ -220,23 +289,20 @@ read_all_connections_from_fw (GHashTable *connections, const char *sysfs_dir) if (!nmi_ibft_update_connection_from_nic (connection, nic, &error)) { _LOGW (LOGD_CORE, "Unable to merge iBFT configuration: %s", error->message); g_error_free (error); + continue; } - g_hash_table_insert (connections, - g_strdup_printf ("ibft%s", index), - connection); + name = g_strdup_printf ("ibft%s", index); + reader_add_connection (reader, name, g_steal_pointer (&connection)); } - connection = nmi_dt_reader_parse (sysfs_dir); - if (connection) { - g_hash_table_insert (connections, - g_strdup ("ofw"), - connection); - } + dt_connection = nmi_dt_reader_parse (sysfs_dir); + if (dt_connection) + reader_add_connection (reader, "ofw", dt_connection); } static void -parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument) +reader_parse_ip (Reader *reader, const char *sysfs_dir, char *argument) { NMConnection *connection; NMSettingIPConfig *s_ip4 = NULL, *s_ip6 = NULL; @@ -299,12 +365,16 @@ parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument) if (ifname == NULL && ( g_strcmp0 (kind, "fw") == 0 || g_strcmp0 (kind, "ibft") == 0)) { - read_all_connections_from_fw (connections, sysfs_dir); + reader_read_all_connections_from_fw (reader, sysfs_dir); return; } /* Parsing done, construct the NMConnection. */ - connection = get_conn (connections, ifname, NULL); + if (ifname) + connection = reader_get_connection (reader, ifname, NULL, TRUE); + else + connection = reader_get_default_connection (reader); + s_ip4 = nm_connection_get_setting_ip4_config (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); @@ -390,7 +460,7 @@ parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument) NULL); if (nm_setting_ip_config_get_num_addresses (s_ip6) == 0) { g_object_set (s_ip6, - NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_DISABLED, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); } } else if (g_strcmp0 (kind, "dhcp6") == 0) { @@ -445,7 +515,7 @@ parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument) if (gateway_ip && *gateway_ip) { int addr_family = guess_ip_address_family (gateway_ip); - if (nm_utils_ipaddr_valid (addr_family, gateway_ip)) { + if (nm_utils_ipaddr_is_valid (addr_family, gateway_ip)) { switch (addr_family) { case AF_INET: g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway_ip, NULL); @@ -470,7 +540,7 @@ parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument) for (i = 0; i < 2; i++) { if (dns_addr_family[i] == AF_UNSPEC) break; - if (nm_utils_ipaddr_valid (dns_addr_family[i], dns[i])) { + if (nm_utils_ipaddr_is_valid (dns_addr_family[i], dns[i])) { switch (dns_addr_family[i]) { case AF_INET: nm_setting_ip_config_add_dns (s_ip4, dns[i]); @@ -495,10 +565,10 @@ parse_ip (GHashTable *connections, const char *sysfs_dir, char *argument) } static void -parse_master (GHashTable *connections, - char *argument, - const char *type_name, - const char *default_name) +reader_parse_master (Reader *reader, + char *argument, + const char *type_name, + const char *default_name) { NMConnection *connection; NMSettingConnection *s_con; @@ -517,7 +587,7 @@ parse_master (GHashTable *connections, master = master_to_free = g_strdup_printf ("%s0", default_name ?: type_name); slaves = get_word (&argument, ':'); - connection = get_conn (connections, master, type_name); + connection = reader_get_connection (reader, master, type_name, TRUE); s_con = nm_connection_get_setting_connection (connection); master = nm_setting_connection_get_uuid (s_con); @@ -539,7 +609,7 @@ parse_master (GHashTable *connections, if (slave == NULL) slave = "eth0"; - connection = get_conn (connections, slave, NULL); + connection = reader_get_connection (reader, slave, NULL, TRUE); s_con = nm_connection_get_setting_connection (connection); g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, type_name, @@ -554,69 +624,81 @@ parse_master (GHashTable *connections, } static void -parse_rd_route (GHashTable *connections, char *argument) +reader_add_routes (Reader *reader, GPtrArray *array) { - NMConnection *connection; - const char *net; - const char *gateway; - const char *interface; - int family = AF_UNSPEC; - NMIPAddr net_addr = { }; - NMIPAddr gateway_addr = { }; - int net_prefix = -1; - NMIPRoute *route; - NMSettingIPConfig *s_ip; - GError *error = NULL; - - net = get_word (&argument, ':'); - gateway = get_word (&argument, ':'); - interface = get_word (&argument, ':'); - - connection = get_conn (connections, interface, NULL); + guint i; + + for (i = 0; i < array->len; i++) { + NMConnection *connection = NULL; + const char *net; + const char *gateway; + const char *interface; + int family = AF_UNSPEC; + NMIPAddr net_addr = { }; + NMIPAddr gateway_addr = { }; + int net_prefix = -1; + NMIPRoute *route; + NMSettingIPConfig *s_ip; + char *argument; + gs_free_error GError *error = NULL; + + argument = array->pdata[i]; + net = get_word (&argument, ':'); + gateway = get_word (&argument, ':'); + interface = get_word (&argument, ':'); + + if (interface) + connection = reader_get_connection (reader, interface, NULL, TRUE); + if (!connection) + connection = reader->bootdev_connection; + if (!connection) + connection = reader_get_connection (reader, interface, NULL, FALSE); + if (!connection) + connection = reader_get_default_connection (reader); + + if (net && *net) { + if (!nm_utils_parse_inaddr_prefix_bin (family, net, &family, &net_addr, &net_prefix)) { + _LOGW (LOGD_CORE, "Unrecognized address: %s", net); + continue; + } + } - if (net && *net) { - if (!nm_utils_parse_inaddr_prefix_bin (family, net, &family, &net_addr, &net_prefix)) { - _LOGW (LOGD_CORE, "Unrecognized address: %s", net); - return; + if (gateway && *gateway) { + if (!nm_utils_parse_inaddr_bin (family, gateway, &family, &gateway_addr)) { + _LOGW (LOGD_CORE, "Unrecognized address: %s", gateway); + continue; + } } - } - if (gateway && *gateway) { - if (!nm_utils_parse_inaddr_bin (family, gateway, &family, &gateway_addr)) { - _LOGW (LOGD_CORE, "Unrecognized address: %s", gateway); - return; + switch (family) { + case AF_INET: + s_ip = nm_connection_get_setting_ip4_config (connection); + if (net_prefix == -1) + net_prefix = 32; + break; + case AF_INET6: + s_ip = nm_connection_get_setting_ip6_config (connection); + if (net_prefix == -1) + net_prefix = 128; + break; + default: + _LOGW (LOGD_CORE, "Unknown address family: %s", net); + continue; } - } - switch (family) { - case AF_INET: - s_ip = nm_connection_get_setting_ip4_config (connection); - if (net_prefix == -1) - net_prefix = 32; - break; - case AF_INET6: - s_ip = nm_connection_get_setting_ip6_config (connection); - if (net_prefix == -1) - net_prefix = 128; - break; - default: - _LOGW (LOGD_CORE, "Unknown address family: %s", net); - return; - } + route = nm_ip_route_new_binary (family, &net_addr.addr_ptr, net_prefix, &gateway_addr.addr_ptr, -1, &error); + if (!route) { + g_warning ("Invalid route '%s via %s': %s\n", net, gateway, error->message); + continue; + } - route = nm_ip_route_new_binary (family, &net_addr.addr_ptr, net_prefix, &gateway_addr.addr_ptr, -1, &error); - if (!route) { - g_warning ("Invalid route '%s via %s': %s\n", net, gateway, error->message); - g_clear_error (&error); - return; + nm_setting_ip_config_add_route (s_ip, route); + nm_ip_route_unref (route); } - - nm_setting_ip_config_add_route (s_ip, route); - nm_ip_route_unref (route); } static void -parse_vlan (GHashTable *connections, char *argument) +reader_parse_vlan (Reader *reader, char *argument) { NMConnection *connection; NMSettingVlan *s_vlan; @@ -632,90 +714,20 @@ parse_vlan (GHashTable *connections, char *argument) break; } - connection = get_conn (connections, vlan, NM_SETTING_VLAN_SETTING_NAME); + connection = reader_get_connection (reader, vlan, NM_SETTING_VLAN_SETTING_NAME, TRUE); s_vlan = nm_connection_get_setting_vlan (connection); g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, phy, - NM_SETTING_VLAN_ID, g_ascii_strtoull (vlanid, NULL, 10), - NULL); - - if (argument && *argument) - _LOGW (LOGD_CORE, "Ignoring extra: '%s'.", argument); -} - -static void -parse_bootdev (GHashTable *connections, char *argument) -{ - NMConnection *connection; - NMSettingConnection *s_con; - - connection = get_conn (connections, NULL, NULL); - - if ( nm_connection_get_interface_name (connection) - && strcmp (nm_connection_get_interface_name (connection), argument) != 0) { - /* If the default connection already has an interface name, - * we should not overwrite it. Create a new one instead. */ - connection = get_conn (connections, argument, NULL); - } - - s_con = nm_connection_get_setting_connection (connection); - g_object_set (s_con, - NM_SETTING_CONNECTION_INTERFACE_NAME, argument, + NM_SETTING_VLAN_ID, (guint) _nm_utils_ascii_str_to_int64 (vlanid, 10, 0, G_MAXUINT, G_MAXUINT), NULL); -} - -static void -parse_nameserver (GHashTable *connections, char *argument) -{ - NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - char *dns; - - connection = get_conn (connections, NULL, NULL); - - dns = get_word (&argument, '\0'); - - switch (guess_ip_address_family (dns)) { - case AF_INET: - s_ip = nm_connection_get_setting_ip4_config (connection); - break; - case AF_INET6: - s_ip = nm_connection_get_setting_ip6_config (connection); - break; - default: - _LOGW (LOGD_CORE, "Unknown address family: %s", dns); - break; - } - - nm_setting_ip_config_add_dns (s_ip, dns); if (argument && *argument) _LOGW (LOGD_CORE, "Ignoring extra: '%s'.", argument); } static void -parse_rd_peerdns (GHashTable *connections, char *argument) -{ - gboolean auto_dns = !_nm_utils_ascii_str_to_bool (argument, TRUE); - NMConnection *connection; - NMSettingIPConfig *s_ip = NULL; - - connection = get_conn (connections, NULL, NULL); - - s_ip = nm_connection_get_setting_ip4_config (connection); - g_object_set (s_ip, - NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, auto_dns, - NULL); - - s_ip = nm_connection_get_setting_ip6_config (connection); - g_object_set (s_ip, - NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, auto_dns, - NULL); -} - -static void -parse_rd_znet (GHashTable *connections, char *argument, gboolean net_ifnames) +reader_parse_rd_znet (Reader *reader, char *argument, gboolean net_ifnames) { const char *nettype; const char *subchannels[4] = { 0, 0, 0, 0 }; @@ -765,7 +777,7 @@ parse_rd_znet (GHashTable *connections, char *argument, gboolean net_ifnames) ifname = g_strdup_printf ("%s%d", prefix, index); } - connection = get_conn (connections, ifname, NM_SETTING_WIRED_SETTING_NAME); + connection = reader_get_connection (reader, ifname, NM_SETTING_WIRED_SETTING_NAME, TRUE); s_wired = nm_connection_get_setting_wired (connection); g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, nettype, @@ -795,18 +807,89 @@ _normalize_conn (gpointer key, gpointer value, gpointer user_data) nm_connection_normalize (connection, NULL, NULL, NULL); } +static void +reader_set_ignore_auto_dns (Reader *reader) +{ + GHashTableIter iter; + NMConnection *connection; + NMSettingIPConfig *s_ip = NULL; + + g_hash_table_iter_init (&iter, reader->hash); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) { + s_ip = nm_connection_get_setting_ip4_config (connection); + g_object_set (s_ip, + NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, TRUE, + NULL); + + s_ip = nm_connection_get_setting_ip6_config (connection); + g_object_set (s_ip, + NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, TRUE, + NULL); + } +} + +static void +reader_add_nameservers (Reader *reader, GPtrArray *nameservers) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip; + GHashTableIter iter; + int addr_family; + const char *ns; + guint i; + + for (i = 0; i < nameservers->len; i++) { + ns = nameservers->pdata[i]; + addr_family = guess_ip_address_family (ns); + if (addr_family == AF_UNSPEC) { + _LOGW (LOGD_CORE, "Unknown address family: %s", ns); + continue; + } + + g_hash_table_iter_init (&iter, reader->hash); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &connection)) { + switch (addr_family) { + case AF_INET: + s_ip = nm_connection_get_setting_ip4_config (connection); + if (!NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip), + NM_SETTING_IP4_CONFIG_METHOD_AUTO, + NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + continue; + break; + case AF_INET6: + s_ip = nm_connection_get_setting_ip6_config (connection); + if (!NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip), + NM_SETTING_IP6_CONFIG_METHOD_AUTO, + NM_SETTING_IP6_CONFIG_METHOD_DHCP, + NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) + continue; + break; + default: + nm_assert_not_reached (); + continue; + } + + nm_setting_ip_config_add_dns (s_ip, ns); + } + } +} + GHashTable * nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv) { - GHashTable *connections; + Reader *reader; const char *tag; gboolean ignore_bootif = FALSE; gboolean neednet = FALSE; gs_free char *bootif_val = NULL; + gs_free char *bootdev = NULL; gboolean net_ifnames = TRUE; + gs_unref_ptrarray GPtrArray *nameservers = NULL; + gs_unref_ptrarray GPtrArray *routes = NULL; + gboolean ignore_auto_dns = FALSE; int i; - connections = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); + reader = reader_new (); for (i = 0; argv[i]; i++) { if (strcmp (argv[i], "net.ifnames=0") == 0) @@ -818,38 +901,49 @@ nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv) for (i = 0; argv[i]; i++) { gs_free char *argument_clone = NULL; char *argument; + char *word; argument_clone = g_strdup (argv[i]); argument = argument_clone; tag = get_word (&argument, '='); if (strcmp (tag, "ip") == 0) - parse_ip (connections, sysfs_dir, argument); - else if (strcmp (tag, "rd.route") == 0) - parse_rd_route (connections, argument); - else if (strcmp (tag, "bridge") == 0) - parse_master (connections, argument, NM_SETTING_BRIDGE_SETTING_NAME, "br"); + reader_parse_ip (reader, sysfs_dir, argument); + else if (strcmp (tag, "rd.route") == 0) { + if (!routes) + routes = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (routes, g_strdup (argument)); + } else if (strcmp (tag, "bridge") == 0) + reader_parse_master (reader, argument, NM_SETTING_BRIDGE_SETTING_NAME, "br"); else if (strcmp (tag, "bond") == 0) - parse_master (connections, argument, NM_SETTING_BOND_SETTING_NAME, NULL); + reader_parse_master (reader, argument, NM_SETTING_BOND_SETTING_NAME, NULL); else if (strcmp (tag, "team") == 0) - parse_master (connections, argument, NM_SETTING_TEAM_SETTING_NAME, NULL); + reader_parse_master (reader, argument, NM_SETTING_TEAM_SETTING_NAME, NULL); else if (strcmp (tag, "vlan") == 0) - parse_vlan (connections, argument); - else if (strcmp (tag, "bootdev") == 0) - parse_bootdev (connections, argument); - else if (strcmp (tag, "nameserver") == 0) - parse_nameserver (connections, argument); - else if (strcmp (tag, "rd.peerdns") == 0) - parse_rd_peerdns (connections, argument); + reader_parse_vlan (reader, argument); + else if (strcmp (tag, "bootdev") == 0) { + g_free (bootdev); + bootdev = g_strdup (argument); + } else if (strcmp (tag, "nameserver") == 0) { + word = get_word (&argument, '\0'); + if (word) { + if (!nameservers) + nameservers = g_ptr_array_new_with_free_func (g_free); + g_ptr_array_add (nameservers, g_strdup (word)); + } + if (argument && *argument) + _LOGW (LOGD_CORE, "Ignoring extra: '%s'.", argument); + } else if (strcmp (tag, "rd.peerdns") == 0) + ignore_auto_dns = !_nm_utils_ascii_str_to_bool (argument, TRUE); else if (strcmp (tag, "rd.iscsi.ibft") == 0 && _nm_utils_ascii_str_to_bool (argument, TRUE)) - read_all_connections_from_fw (connections, sysfs_dir); + reader_read_all_connections_from_fw (reader, sysfs_dir); else if (strcmp (tag, "rd.bootif") == 0) ignore_bootif = !_nm_utils_ascii_str_to_bool (argument, TRUE); else if (strcmp (tag, "rd.neednet") == 0) neednet = _nm_utils_ascii_str_to_bool (argument, TRUE); else if (strcmp (tag, "rd.znet") == 0) - parse_rd_znet (connections, argument, net_ifnames); - else if (strcasecmp (tag, "BOOTIF") == 0) { + reader_parse_rd_znet (reader, argument, net_ifnames); + else if (g_ascii_strcasecmp (tag, "BOOTIF") == 0) { nm_clear_g_free (&bootif_val); bootif_val = g_strdup (argument); } @@ -872,16 +966,22 @@ nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv) bootif += 3; } - connection = get_conn (connections, NULL, NM_SETTING_WIRED_SETTING_NAME); + connection = reader_get_connection (reader, NULL, NM_SETTING_WIRED_SETTING_NAME, FALSE); + if (!connection) + connection = reader_get_default_connection (reader); + s_wired = nm_connection_get_setting_wired (connection); if ( nm_connection_get_interface_name (connection) || ( nm_setting_wired_get_mac_address (s_wired) && !nm_utils_hwaddr_matches (nm_setting_wired_get_mac_address (s_wired), -1, bootif, -1))) { - connection = add_conn (connections, "bootif_connection", "BOOTIF Connection", - NULL, NM_SETTING_WIRED_SETTING_NAME, - NM_CONNECTION_MULTI_CONNECT_SINGLE); + connection = reader_create_connection (reader, + "bootif_connection", + "BOOTIF Connection", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NM_CONNECTION_MULTI_CONNECT_SINGLE); s_wired = (NMSettingWired *) nm_setting_wired_new (); nm_connection_add_setting (connection, (NMSetting *) s_wired); } @@ -890,12 +990,28 @@ nmi_cmdline_reader_parse (const char *sysfs_dir, const char *const*argv) NM_SETTING_WIRED_MAC_ADDRESS, bootif, NULL); } - if (neednet && g_hash_table_size (connections) == 0) { + + if (bootdev) { + NMConnection *connection; + + connection = reader_get_connection (reader, bootdev, NULL, TRUE); + reader->bootdev_connection = connection; + } + + if (neednet && g_hash_table_size (reader->hash) == 0) { /* Make sure there's some connection. */ - get_conn (connections, NULL, NM_SETTING_WIRED_SETTING_NAME); + reader_get_default_connection (reader); } - g_hash_table_foreach (connections, _normalize_conn, NULL); + if (routes) + reader_add_routes (reader, routes); + + if (nameservers) + reader_add_nameservers (reader, nameservers); + + if (ignore_auto_dns) + reader_set_ignore_auto_dns (reader); - return connections; + g_hash_table_foreach (reader->hash, _normalize_conn, NULL); + return reader_destroy (reader, FALSE); } diff --git a/src/initrd/nmi-dt-reader.c b/src/initrd/nmi-dt-reader.c index a8677ed9..f118adc3 100644 --- a/src/initrd/nmi-dt-reader.c +++ b/src/initrd/nmi-dt-reader.c @@ -157,7 +157,7 @@ nmi_dt_reader_parse (const char *sysfs_dir) local_hwaddr = dt_get_hwaddr_property (base, bootpath, "local-mac-address"); hwaddr = dt_get_hwaddr_property (base, bootpath, "mac-address"); if (g_strcmp0 (local_hwaddr, hwaddr) == 0) - g_clear_pointer (&local_hwaddr, g_free); + nm_clear_g_free (&local_hwaddr); tokens = g_strsplit (path, ",", 0); @@ -363,7 +363,7 @@ nmi_dt_reader_parse (const char *sysfs_dir) if (!nm_connection_normalize (connection, NULL, NULL, &error)) { _LOGW (LOGD_CORE, "Generated an invalid connection: %s", error->message); - g_clear_pointer (&connection, g_object_unref); + nm_clear_pointer (&connection, g_object_unref); } return g_steal_pointer (&connection); diff --git a/src/initrd/nmi-ibft-reader.c b/src/initrd/nmi-ibft-reader.c index 47b90ebf..477bc0bf 100644 --- a/src/initrd/nmi-ibft-reader.c +++ b/src/initrd/nmi-ibft-reader.c @@ -200,23 +200,23 @@ ip_setting_add_from_block (GHashTable *nic, g_return_val_if_reached (FALSE); } g_object_set (s_ip, - NM_SETTING_IP_CONFIG_METHOD, method, - NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, + NM_SETTING_IP_CONFIG_METHOD, method, + NM_SETTING_IP_CONFIG_MAY_FAIL, FALSE, NULL); - if (s_gateway && !nm_utils_ipaddr_valid (family, s_gateway)) { + if (s_gateway && !nm_utils_ipaddr_is_valid (family, s_gateway)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "iBFT: invalid IP gateway '%s'.", s_gateway); return FALSE; } - if (s_dns1 && !nm_utils_ipaddr_valid (family, s_dns1)) { + if (s_dns1 && !nm_utils_ipaddr_is_valid (family, s_dns1)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "iBFT: invalid DNS1 address '%s'.", s_dns1); return FALSE; } - if (s_dns2 && !nm_utils_ipaddr_valid (family, s_dns2)) { + if (s_dns2 && !nm_utils_ipaddr_is_valid (family, s_dns2)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "iBFT: invalid DNS2 address '%s'.", s_dns2); return FALSE; diff --git a/src/initrd/tests/meson.build b/src/initrd/tests/meson.build index 5dd2873c..1d0908b9 100644 --- a/src/initrd/tests/meson.build +++ b/src/initrd/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + c_flags = test_c_flags + ['-DTEST_INITRD_DIR="@0@"'.format(meson.current_source_dir())] test_units = [ diff --git a/src/initrd/tests/test-cmdline-reader.c b/src/initrd/tests/test-cmdline-reader.c index 8951e491..b2b06e27 100644 --- a/src/initrd/tests/test-cmdline-reader.c +++ b/src/initrd/tests/test-cmdline-reader.c @@ -264,7 +264,7 @@ test_if_ip6_manual (void) } static void -test_multiple (void) +test_multiple_merge (void) { gs_unref_hashtable GHashTable *connections = NULL; const char *const*ARGV = NM_MAKE_STRV ("ip=192.0.2.2:::::eth0", @@ -307,6 +307,37 @@ test_multiple (void) } static void +test_multiple_bootdev (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + const char *const*ARGV = NM_MAKE_STRV ("nameserver=1.2.3.4", + "ip=eth3:auto6", + "ip=eth4:dhcp", + "bootdev=eth4"); + NMConnection *connection; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 2); + + connection = g_hash_table_lookup (connections, "eth3"); + g_assert (connection); + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + + connection = g_hash_table_lookup (connections, "eth4"); + g_assert (connection); + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_AUTO); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 1); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 0), ==, "1.2.3.4"); +} + +static void test_bootdev (void) { gs_unref_hashtable GHashTable *connections = NULL; @@ -358,16 +389,16 @@ test_some_more (void) g_assert (connections); g_assert_cmpint (g_hash_table_size (connections), ==, 2); - connection = g_hash_table_lookup (connections, "default_connection"); + connection = g_hash_table_lookup (connections, "eth1"); g_assert (connection); nmtst_assert_connection_verifies_without_normalization (connection); s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_WIRED_SETTING_NAME); - g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "Wired Connection"); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "eth1"); g_assert_cmpstr (nm_setting_connection_get_interface_name (s_con), ==, "eth1"); - g_assert_cmpint (nm_setting_connection_get_multi_connect (s_con), ==, NM_CONNECTION_MULTI_CONNECT_MULTIPLE); + g_assert_cmpint (nm_setting_connection_get_multi_connect (s_con), ==, NM_CONNECTION_MULTI_CONNECT_SINGLE); s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); @@ -409,7 +440,8 @@ test_some_more (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_AUTO); - g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 0); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 1); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip6, 0), ==, "2001:db8:3::53"); g_assert_cmpint (nm_setting_ip_config_get_num_routes (s_ip6), ==, 1); g_assert (!nm_setting_ip_config_get_gateway (s_ip6)); ip_route = nm_setting_ip_config_get_route (s_ip6, 0); @@ -991,7 +1023,7 @@ test_bootif (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DISABLED); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE); g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); } @@ -1027,7 +1059,7 @@ test_bootif_hwtype (void) s_ip6 = nm_connection_get_setting_ip6_config (connection); g_assert (s_ip6); - g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_DISABLED); + g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE); g_assert (!nm_setting_ip_config_get_ignore_auto_dns (s_ip6)); connection = g_hash_table_lookup (connections, "bootif_connection"); @@ -1052,6 +1084,57 @@ test_bootif_hwtype (void) g_assert (nm_setting_ip_config_get_may_fail (s_ip6)); } +/* Check that nameservers are assigned to all existing + * connections that support the specific IPv4/IPv6 address + * family. + */ +static void +test_nameserver (void) +{ + gs_unref_hashtable GHashTable *connections = NULL; + const char *const*ARGV = NM_MAKE_STRV ("nameserver=1.1.1.1", + "ip=eth0:dhcp", + "ip=eth1:auto6", + "ip=10.11.12.13::10.11.12.1:24:foo.example.com:eth2:none", + "nameserver=1.0.0.1", + "nameserver=[2606:4700:4700::1111]"); + NMConnection *connection; + NMSettingIPConfig *s_ip; + + connections = nmi_cmdline_reader_parse (TEST_INITRD_DIR "/sysfs", ARGV); + g_assert (connections); + g_assert_cmpint (g_hash_table_size (connections), ==, 3); + + connection = g_hash_table_lookup (connections, "eth0"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + + s_ip = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip), ==, 2); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip, 0), ==, "1.1.1.1"); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip, 1), ==, "1.0.0.1"); + + connection = g_hash_table_lookup (connections, "eth1"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + + s_ip = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip), ==, 1); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip, 0), ==, "2606:4700:4700::1111"); + + connection = g_hash_table_lookup (connections, "eth2"); + g_assert (connection); + nmtst_assert_connection_verifies_without_normalization (connection); + + s_ip = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip); + g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip), ==, 2); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip, 0), ==, "1.1.1.1"); + g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip, 1), ==, "1.0.0.1"); +} + static void test_bootif_off (void) { @@ -1075,7 +1158,9 @@ int main (int argc, char **argv) g_test_add_func ("/initrd/cmdline/if_auto_with_mtu_and_mac", test_if_auto_with_mtu_and_mac); g_test_add_func ("/initrd/cmdline/if_ip4_manual", test_if_ip4_manual); g_test_add_func ("/initrd/cmdline/if_ip6_manual", test_if_ip6_manual); - g_test_add_func ("/initrd/cmdline/multiple", test_multiple); + g_test_add_func ("/initrd/cmdline/multiple/merge", test_multiple_merge); + g_test_add_func ("/initrd/cmdline/multiple/bootdev", test_multiple_bootdev); + g_test_add_func ("/initrd/cmdline/nameserver", test_nameserver); g_test_add_func ("/initrd/cmdline/some_more", test_some_more); g_test_add_func ("/initrd/cmdline/bootdev", test_bootdev); g_test_add_func ("/initrd/cmdline/bond", test_bond); diff --git a/src/main-utils.c b/src/main-utils.c index 80222495..e17feb41 100644 --- a/src/main-utils.c +++ b/src/main-utils.c @@ -185,7 +185,7 @@ nm_main_utils_ensure_not_running_pidfile (const char *pidfile) if (pid <= 0 || pid > 65536 || errno) return; - g_clear_pointer (&contents, g_free); + nm_clear_g_free (&contents); proc_cmdline = g_strdup_printf ("/proc/%ld/cmdline", pid); if (!g_file_get_contents (proc_cmdline, &contents, &len, NULL)) return; diff --git a/src/meson.build b/src/meson.build index 748fa519..8ff9bd11 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + src_inc = include_directories('.') daemon_nm_default_dep = declare_dependency( @@ -49,6 +51,7 @@ sources = files( deps = [ daemon_nm_default_dep, libn_dhcp4_dep, + libnm_keyfile_dep, libnm_core_dep, libnm_systemd_shared_dep, libnm_udev_aux_dep, @@ -86,6 +89,7 @@ sources = files( 'devices/nm-device-tun.c', 'devices/nm-device-veth.c', 'devices/nm-device-vlan.c', + 'devices/nm-device-vrf.c', 'devices/nm-device-vxlan.c', 'devices/nm-device-wireguard.c', 'devices/nm-device-wpan.c', @@ -125,7 +129,6 @@ sources = files( 'nm-act-request.c', 'nm-audit-manager.c', 'nm-auth-manager.c', - 'nm-auth-subject.c', 'nm-auth-utils.c', 'nm-dbus-manager.c', 'nm-checkpoint.c', @@ -134,8 +137,7 @@ sources = files( 'nm-config-data.c', 'nm-connectivity.c', 'nm-dcb.c', - 'nm-dhcp4-config.c', - 'nm-dhcp6-config.c', + 'nm-dhcp-config.c', 'nm-dispatcher.c', 'nm-firewall-manager.c', 'nm-hostname-manager.c', diff --git a/src/ndisc/nm-fake-ndisc.c b/src/ndisc/nm-fake-ndisc.c index 020764d3..5f4594b9 100644 --- a/src/ndisc/nm-fake-ndisc.c +++ b/src/ndisc/nm-fake-ndisc.c @@ -62,7 +62,7 @@ struct _NMFakeRNDiscClass { G_DEFINE_TYPE (NMFakeNDisc, nm_fake_ndisc, NM_TYPE_NDISC) -#define NM_FAKE_NDISC_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMFakeNDisc, NM_IS_FAKE_NDISC) +#define NM_FAKE_NDISC_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMFakeNDisc, NM_IS_FAKE_NDISC, NMNDisc) /*****************************************************************************/ @@ -234,7 +234,7 @@ receive_ra (gpointer user_data) NMNDiscDataInternal *rdata = ndisc->rdata; FakeRa *ra = priv->ras->data; NMNDiscConfigMap changed = 0; - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); guint i; NMNDiscDHCPLevel dhcp_level; @@ -326,7 +326,7 @@ receive_ra (gpointer user_data) static void start (NMNDisc *ndisc) { - NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE ((NMFakeNDisc *) ndisc); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (ndisc); FakeRa *ra; /* Queue up the first fake RA */ @@ -366,7 +366,7 @@ nm_fake_ndisc_new (int ifindex, const char *ifname) static void dispose (GObject *object) { - NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE ((NMFakeNDisc *) object); + NMFakeNDiscPrivate *priv = NM_FAKE_NDISC_GET_PRIVATE (object); nm_clear_g_source (&priv->receive_ra_id); diff --git a/src/ndisc/nm-lndp-ndisc.c b/src/ndisc/nm-lndp-ndisc.c index 6f2815ef..b698489c 100644 --- a/src/ndisc/nm-lndp-ndisc.c +++ b/src/ndisc/nm-lndp-ndisc.c @@ -24,9 +24,7 @@ typedef struct { struct ndp *ndp; - - GIOChannel *event_channel; - guint event_id; + GSource *event_source; } NMLndpNDiscPrivate; /*****************************************************************************/ @@ -44,14 +42,14 @@ struct _NMLndpNDiscClass { G_DEFINE_TYPE (NMLndpNDisc, nm_lndp_ndisc, NM_TYPE_NDISC) -#define NM_LNDP_NDISC_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMLndpNDisc, NM_IS_LNDP_NDISC) +#define NM_LNDP_NDISC_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMLndpNDisc, NM_IS_LNDP_NDISC, NMNDisc) /*****************************************************************************/ static gboolean send_rs (NMNDisc *ndisc, GError **error) { - NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE (ndisc); struct ndp_msg *msg; int errsv; @@ -99,10 +97,12 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) NMNDiscConfigMap changed = 0; struct ndp_msgra *msgra = ndp_msgra (msg); struct in6_addr gateway_addr; - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); int offset; int hop_limit; guint32 val; + guint32 clamp_pltime; + guint32 clamp_vltime; /* Router discovery is subject to the following RFC documents: * @@ -167,7 +167,22 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) changed |= NM_NDISC_CONFIG_GATEWAYS; } - /* Addresses & Routes */ + /* Addresses & Routes + * + * The Preferred Lifetime and Valid Lifetime of PIOs are capped to Router Lifetime + * and NM_NDISC_VLTIME_MULT * Preferred Lifetime, respectively. + * + * The Lifetime of RIOs is capped to the Router Lifetime (there is no point in + * maintaining a route if it employs a dead router). + * + * See draft-gont-6man-slaac-renum + */ + #define NM_NDISC_VLTIME_MULT ((guint32) 48) + clamp_pltime = ndp_msgra_router_lifetime (msgra); + clamp_vltime = (clamp_pltime < G_MAXUINT32 / NM_NDISC_VLTIME_MULT) + ? clamp_pltime * NM_NDISC_VLTIME_MULT + : G_MAXUINT32; + ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_PREFIX) { guint8 r_plen; struct in6_addr r_network; @@ -188,7 +203,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) .network = r_network, .plen = r_plen, .timestamp = now, - .lifetime = ndp_msg_opt_prefix_valid_time (msg, offset), + .lifetime = NM_MIN (ndp_msg_opt_prefix_valid_time (msg, offset), clamp_vltime), }; if (nm_ndisc_add_route (ndisc, &route)) @@ -201,8 +216,8 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) NMNDiscAddress address = { .address = r_network, .timestamp = now, - .lifetime = ndp_msg_opt_prefix_valid_time (msg, offset), - .preferred = ndp_msg_opt_prefix_preferred_time (msg, offset), + .lifetime = NM_MIN (ndp_msg_opt_prefix_valid_time (msg, offset), clamp_vltime), + .preferred = NM_MIN (ndp_msg_opt_prefix_preferred_time (msg, offset), clamp_pltime), }; if (address.preferred <= address.lifetime) { @@ -216,7 +231,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) .gateway = gateway_addr, .plen = ndp_msg_opt_route_prefix_len (msg, offset), .timestamp = now, - .lifetime = ndp_msg_opt_route_lifetime (msg, offset), + .lifetime = NM_MIN (ndp_msg_opt_route_lifetime (msg, offset), clamp_pltime), .preference = _route_preference_coerce (ndp_msg_opt_route_preference (msg, offset)), }; @@ -231,7 +246,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) /* DNS information */ ndp_msg_opt_for_each_offset(offset, msg, NDP_MSG_OPT_RDNSS) { - static struct in6_addr *addr; + struct in6_addr *addr; int addr_index; ndp_msg_opt_rdnss_for_each_addr (addr, addr_index, msg, offset) { @@ -260,7 +275,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) NMNDiscDNSDomain dns_domain = { .domain = domain, .timestamp = now, - .lifetime = ndp_msg_opt_rdnss_lifetime (msg, offset), + .lifetime = ndp_msg_opt_dnssl_lifetime (msg, offset), }; /* Pad the lifetime somewhat to give a bit of slack in cases @@ -346,9 +361,9 @@ typedef struct { static gboolean send_ra (NMNDisc *ndisc, GError **error) { - NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE (ndisc); NMNDiscDataInternal *rdata = ndisc->rdata; - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); int errsv; struct in6_addr *addr; struct ndp_msg *msg; @@ -484,17 +499,19 @@ receive_rs (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) } static gboolean -event_ready (GIOChannel *source, GIOCondition condition, NMNDisc *ndisc) +event_ready (int fd, + GIOCondition condition, + gpointer user_data) { - _nm_unused gs_unref_object NMNDisc *ndisc_keep_alive = g_object_ref (ndisc); + gs_unref_object NMNDisc *ndisc = g_object_ref (NM_NDISC (user_data)); nm_auto_pop_netns NMPNetns *netns = NULL; - NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE (ndisc); _LOGD ("processing libndp events"); if (!nm_ndisc_netns_push (ndisc, &netns)) { /* something is very wrong. Stop handling events. */ - priv->event_id = 0; + nm_clear_g_source_inst (&priv->event_source); return G_SOURCE_REMOVE; } @@ -505,17 +522,23 @@ event_ready (GIOChannel *source, GIOCondition condition, NMNDisc *ndisc) static void start (NMNDisc *ndisc) { - NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); - int fd = ndp_get_eventfd (priv->ndp); + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE (ndisc); + int fd; + + g_return_if_fail (!priv->event_source); - g_return_if_fail (!priv->event_channel); - g_return_if_fail (!priv->event_id); + fd = ndp_get_eventfd (priv->ndp); - priv->event_channel = g_io_channel_unix_new (fd); - priv->event_id = g_io_add_watch (priv->event_channel, G_IO_IN, (GIOFunc) event_ready, ndisc); + priv->event_source = nm_g_unix_fd_source_new (fd, + G_IO_IN, + G_PRIORITY_DEFAULT, + event_ready, + ndisc, + NULL); + g_source_attach (priv->event_source, NULL); /* Flush any pending messages to avoid using obsolete information */ - event_ready (priv->event_channel, 0, ndisc); + event_ready (fd, 0, ndisc); switch (nm_ndisc_get_node_type (ndisc)) { case NM_NDISC_NODE_TYPE_HOST: @@ -592,7 +615,7 @@ nm_lndp_ndisc_new (NMPlatform *platform, 1, G_MAXINT32, NM_NDISC_ROUTER_SOLICITATION_INTERVAL_DEFAULT), NULL); - priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); + priv = NM_LNDP_NDISC_GET_PRIVATE (ndisc); errsv = ndp_open (&priv->ndp); @@ -610,11 +633,10 @@ nm_lndp_ndisc_new (NMPlatform *platform, static void dispose (GObject *object) { - NMNDisc *ndisc = (NMNDisc *) object; - NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE ((NMLndpNDisc *) ndisc); + NMNDisc *ndisc = NM_NDISC (object); + NMLndpNDiscPrivate *priv = NM_LNDP_NDISC_GET_PRIVATE (ndisc); - nm_clear_g_source (&priv->event_id); - g_clear_pointer (&priv->event_channel, g_io_channel_unref); + nm_clear_g_source_inst (&priv->event_source); if (priv->ndp) { switch (nm_ndisc_get_node_type (ndisc)) { diff --git a/src/ndisc/nm-ndisc.c b/src/ndisc/nm-ndisc.c index 0afca26b..bb3a92b0 100644 --- a/src/ndisc/nm-ndisc.c +++ b/src/ndisc/nm-ndisc.c @@ -173,7 +173,7 @@ _get_exp (char *buf, gsize buf_size, gint64 now_ns, gint64 expiry_time) return "permanent"; l = g_snprintf (buf, buf_size, "%.4f", - ((double) ((expiry_time * NM_UTILS_NS_PER_SECOND) - now_ns)) / ((double) NM_UTILS_NS_PER_SECOND)); + ((double) ((expiry_time * NM_UTILS_NSEC_PER_SEC) - now_ns)) / ((double) NM_UTILS_NSEC_PER_SEC)); nm_assert (l < buf_size); return buf; } @@ -442,8 +442,15 @@ nm_ndisc_add_address (NMNDisc *ndisc, } if (existing) { + /* A Valid Lifetime of 0 eliminates the corresponding address(es). This deviates + * from RFC4862 Section 5.5.3, item e), as recommended in IETF draft draft-gont-6man-slaac-renum. + */ + if (new->lifetime == 0) { + g_array_remove_index (rdata->addresses, i); + return TRUE; + } + if (from_ra) { - const gint32 NM_NDISC_PREFIX_LFT_MIN = 7200; /* seconds, RFC4862 5.5.3.e */ gint64 old_expiry_lifetime, old_expiry_preferred; old_expiry_lifetime = get_expiry (existing); @@ -452,25 +459,16 @@ nm_ndisc_add_address (NMNDisc *ndisc, if (new->lifetime == NM_NDISC_INFINITY) existing->lifetime = NM_NDISC_INFINITY; else { - gint64 new_lifetime, remaining_lifetime; + gint64 new_lifetime; - /* see RFC4862 5.5.3.e */ - if (existing->lifetime == NM_NDISC_INFINITY) - remaining_lifetime = G_MAXINT64; - else - remaining_lifetime = ((gint64) existing->timestamp) + ((gint64) existing->lifetime) - ((gint64) now_s); + /* Honor small valid lifetimes, as discussed in + * draft-gont-6man-slaac-renum, to allow for more timelier + * reaction to renumbering events. This deviates from + * RFC4862 Section 5.5.3, item e). + */ new_lifetime = ((gint64) new->timestamp) + ((gint64) new->lifetime) - ((gint64) now_s); - - if ( new_lifetime > (gint64) NM_NDISC_PREFIX_LFT_MIN - || new_lifetime > remaining_lifetime) { - existing->timestamp = now_s; - existing->lifetime = CLAMP (new_lifetime, (gint64) 0, (gint64) (G_MAXUINT32 - 1)); - } else if (remaining_lifetime <= (gint64) NM_NDISC_PREFIX_LFT_MIN) { - /* keep the current lifetime. */ - } else { - existing->timestamp = now_s; - existing->lifetime = NM_NDISC_PREFIX_LFT_MIN; - } + existing->timestamp = now_s; + existing->lifetime = CLAMP (new_lifetime, (gint64) 0, (gint64) (G_MAXUINT32 - 1)); } if (new->preferred == NM_NDISC_INFINITY) { @@ -487,11 +485,6 @@ nm_ndisc_add_address (NMNDisc *ndisc, || old_expiry_preferred != get_expiry_preferred (existing); } - if (new->lifetime == 0) { - g_array_remove_index (rdata->addresses, i); - return TRUE; - } - if ( get_expiry (existing) == get_expiry (new) && get_expiry_preferred (existing) == get_expiry_preferred (new)) return FALSE; @@ -676,7 +669,7 @@ nm_ndisc_add_dns_domain (NMNDisc *ndisc, const NMNDiscDNSDomain *new) _different_message = g_strcmp0 (priv->last_error, error->message) != 0; \ _NMLOG (_different_message ? LOGL_WARN : LOGL_DEBUG, __VA_ARGS__); \ if (_different_message) { \ - g_clear_pointer (&priv->last_error, g_free); \ + nm_clear_g_free (&priv->last_error); \ priv->last_error = g_strdup (error->message); \ } \ } G_STMT_END @@ -697,13 +690,13 @@ send_rs_timeout (NMNDisc *ndisc) if (klass->send_rs (ndisc, &error)) { _LOGD ("router solicitation sent"); priv->solicitations_left--; - g_clear_pointer (&priv->last_error, g_free); + nm_clear_g_free (&priv->last_error); } else { _MAYBE_WARN ("failure sending router solicitation: %s", error->message); g_clear_error (&error); } - priv->last_rs = nm_utils_get_monotonic_timestamp_s (); + priv->last_rs = nm_utils_get_monotonic_timestamp_sec (); if (priv->solicitations_left > 0) { _LOGD ("scheduling router solicitation retry in %d seconds.", (int) priv->router_solicitation_interval); @@ -727,7 +720,7 @@ solicit_routers (NMNDisc *ndisc) if (priv->send_rs_id) return; - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); priv->solicitations_left = priv->router_solicitations; t = (((gint64) priv->last_rs) + priv->router_solicitation_interval) - now; @@ -748,10 +741,10 @@ announce_router (NMNDisc *ndisc) if (!nm_ndisc_netns_push (ndisc, &netns)) return G_SOURCE_REMOVE; - priv->last_ra = nm_utils_get_monotonic_timestamp_s (); + priv->last_ra = nm_utils_get_monotonic_timestamp_sec (); if (klass->send_ra (ndisc, &error)) { _LOGD ("router advertisement sent"); - g_clear_pointer (&priv->last_error, g_free); + nm_clear_g_free (&priv->last_error); } else { _MAYBE_WARN ("failure sending router advertisement: %s", error->message); g_clear_error (&error); @@ -788,7 +781,7 @@ announce_router_initial (NMNDisc *ndisc) priv->announcements_left = NM_NDISC_ROUTER_ADVERTISEMENTS_DEFAULT; /* Unschedule an unsolicited resend if we are allowed to send now. */ - if (G_LIKELY (nm_utils_get_monotonic_timestamp_s () - priv->last_ra > NM_NDISC_ROUTER_ADVERT_DELAY)) + if (G_LIKELY (nm_utils_get_monotonic_timestamp_sec () - priv->last_ra > NM_NDISC_ROUTER_ADVERT_DELAY)) nm_clear_g_source (&priv->send_ra_id); /* Schedule the initial send rather early. Clamp the delay by minimal @@ -807,7 +800,7 @@ announce_router_solicited (NMNDisc *ndisc) _LOGD ("will send an solicited router advertisement"); /* Unschedule an unsolicited resend if we are allowed to send now. */ - if (nm_utils_get_monotonic_timestamp_s () - priv->last_ra > NM_NDISC_ROUTER_ADVERT_DELAY) + if (nm_utils_get_monotonic_timestamp_sec () - priv->last_ra > NM_NDISC_ROUTER_ADVERT_DELAY) nm_clear_g_source (&priv->send_ra_id); if (!priv->send_ra_id) { @@ -965,7 +958,7 @@ nm_ndisc_dad_failed (NMNDisc *ndisc, const struct in6_addr *address, gboolean em if (IN6_ARE_ADDR_EQUAL (&item->address, address)) { char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - _LOGD ("DAD failed for discovered address %s", nm_utils_inet6_ntop (address, sbuf)); + _LOGD ("DAD failed for discovered address %s", _nm_utils_inet6_ntop (address, sbuf)); changed = TRUE; if (!complete_address (ndisc, item)) { g_array_remove_index (rdata->addresses, i); @@ -1031,7 +1024,7 @@ _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed) if (!_LOGD_ENABLED ()) return; - now_ns = nm_utils_get_monotonic_timestamp_ns (); + now_ns = nm_utils_get_monotonic_timestamp_nsec (); priv = NM_NDISC_GET_PRIVATE (ndisc); rdata = &priv->rdata; @@ -1068,7 +1061,7 @@ _config_changed_log (NMNDisc *ndisc, NMNDiscConfigMap changed) inet_ntop (AF_INET6, &route->network, addrstr, sizeof (addrstr)); _LOGD (" route %s/%u via %s pref %s exp %s", addrstr, (guint) route->plen, - nm_utils_inet6_ntop (&route->gateway, sbuf), + _nm_utils_inet6_ntop (&route->gateway, sbuf), nm_icmpv6_router_pref_to_string (route->preference, str_pref, sizeof (str_pref)), get_exp (str_exp, now_ns, route)); } @@ -1245,7 +1238,7 @@ timeout_cb (gpointer user_data) NMNDisc *self = user_data; NM_NDISC_GET_PRIVATE (self)->timeout_id = 0; - check_timestamps (self, nm_utils_get_monotonic_timestamp_s (), 0); + check_timestamps (self, nm_utils_get_monotonic_timestamp_sec (), 0); return G_SOURCE_REMOVE; } @@ -1256,7 +1249,7 @@ nm_ndisc_ra_received (NMNDisc *ndisc, gint32 now, NMNDiscConfigMap changed) nm_clear_g_source (&priv->ra_timeout_id); nm_clear_g_source (&priv->send_rs_id); - g_clear_pointer (&priv->last_error, g_free); + nm_clear_g_free (&priv->last_error); check_timestamps (ndisc, now, changed); } @@ -1265,7 +1258,7 @@ nm_ndisc_rs_received (NMNDisc *ndisc) { NMNDiscPrivate *priv = NM_NDISC_GET_PRIVATE (ndisc); - g_clear_pointer (&priv->last_error, g_free); + nm_clear_g_free (&priv->last_error); announce_router_solicited (ndisc); } @@ -1370,7 +1363,7 @@ nm_ndisc_init (NMNDisc *ndisc) priv->rdata.public.hop_limit = 64; /* Start at very low number so that last_rs - router_solicitation_interval - * is much lower than nm_utils_get_monotonic_timestamp_s() at startup. + * is much lower than nm_utils_get_monotonic_timestamp_sec() at startup. */ priv->last_rs = G_MININT32; } @@ -1384,7 +1377,7 @@ dispose (GObject *object) nm_clear_g_source (&priv->ra_timeout_id); nm_clear_g_source (&priv->send_rs_id); nm_clear_g_source (&priv->send_ra_id); - g_clear_pointer (&priv->last_error, g_free); + nm_clear_g_free (&priv->last_error); nm_clear_g_source (&priv->timeout_id); diff --git a/src/ndisc/tests/meson.build b/src/ndisc/tests/meson.build index c81e24ad..349eebba 100644 --- a/src/ndisc/tests/meson.build +++ b/src/ndisc/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_unit = 'test-ndisc-fake' exe = executable( diff --git a/src/ndisc/tests/test-ndisc-fake.c b/src/ndisc/tests/test-ndisc-fake.c index 8bdc053d..7a5eea01 100644 --- a/src/ndisc/tests/test-ndisc-fake.c +++ b/src/ndisc/tests/test-ndisc-fake.c @@ -157,7 +157,7 @@ static void test_simple (void) { NMFakeNDisc *ndisc = ndisc_new (); - guint32 now = nm_utils_get_monotonic_timestamp_s (); + guint32 now = nm_utils_get_monotonic_timestamp_sec (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now }; guint id; @@ -217,9 +217,8 @@ test_everything_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed g_assert_cmpint (rdata->gateways_n, ==, 1); match_gateway (rdata, 0, "fe80::2", data->timestamp1, 10, NM_ICMPV6_ROUTER_PREF_MEDIUM); - g_assert_cmpint (rdata->addresses_n, ==, 2); - match_address (rdata, 0, "2001:db8:a:a::1", data->timestamp1, 10, 0); - match_address (rdata, 1, "2001:db8:a:b::1", data->timestamp1, 10, 10); + g_assert_cmpint (rdata->addresses_n, ==, 1); + match_address (rdata, 0, "2001:db8:a:b::1", data->timestamp1, 10, 10); g_assert_cmpint (rdata->routes_n, ==, 1); match_route (rdata, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1, 10, 10); g_assert_cmpint (rdata->dns_servers_n, ==, 1); @@ -239,7 +238,7 @@ static void test_everything (void) { NMFakeNDisc *ndisc = ndisc_new (); - guint32 now = nm_utils_get_monotonic_timestamp_s (); + guint32 now = nm_utils_get_monotonic_timestamp_sec (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now }; guint id; @@ -313,7 +312,7 @@ static void test_preference_order (void) { NMFakeNDisc *ndisc = ndisc_new (); - guint32 now = nm_utils_get_monotonic_timestamp_s (); + guint32 now = nm_utils_get_monotonic_timestamp_sec (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now }; guint id; @@ -386,7 +385,7 @@ static void test_preference_changed (void) { NMFakeNDisc *ndisc = ndisc_new (); - guint32 now = nm_utils_get_monotonic_timestamp_s (); + guint32 now = nm_utils_get_monotonic_timestamp_sec (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now }; guint id; @@ -440,7 +439,7 @@ success_timeout (TestData *data) static void test_dns_solicit_loop_rs_sent (NMFakeNDisc *ndisc, TestData *data) { - guint32 now = nm_utils_get_monotonic_timestamp_s (); + guint32 now = nm_utils_get_monotonic_timestamp_sec (); guint id; if (data->rs_counter > 0 && data->rs_counter < 6) { @@ -472,7 +471,7 @@ static void test_dns_solicit_loop (void) { NMFakeNDisc *ndisc = ndisc_new (); - guint32 now = nm_utils_get_monotonic_timestamp_s (); + guint32 now = nm_utils_get_monotonic_timestamp_sec (); TestData data = { g_main_loop_new (NULL, FALSE), 0, 0, now, 0 }; guint id; diff --git a/src/nm-act-request.c b/src/nm-act-request.c index ef36a40d..1c252052 100644 --- a/src/nm-act-request.c +++ b/src/nm-act-request.c @@ -19,7 +19,7 @@ #include "devices/nm-device.h" #include "nm-active-connection.h" #include "settings/nm-settings-connection.h" -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" typedef struct { char *table; diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index bf50e55d..63dd8910 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -14,7 +14,7 @@ #include "nm-simple-connection.h" #include "nm-auth-utils.h" #include "nm-auth-manager.h" -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "nm-keep-alive.h" #include "NetworkManagerUtils.h" #include "nm-core-internal.h" @@ -138,7 +138,8 @@ static void auth_complete (NMActiveConnection *self, gboolean result, const char /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_state_to_string, NMActiveConnectionState, +static +NM_UTILS_LOOKUP_STR_DEFINE (_state_to_string, NMActiveConnectionState, NM_UTILS_LOOKUP_DEFAULT (NULL), NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVE_CONNECTION_STATE_UNKNOWN, "unknown"), NM_UTILS_LOOKUP_STR_ITEM (NM_ACTIVE_CONNECTION_STATE_ACTIVATING, "activating"), @@ -152,7 +153,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_state_to_string, NMActiveConnectionState, /* the maximum required buffer size for _state_flags_to_string(). */ #define _NM_ACTIVATION_STATE_FLAG_TO_STRING_BUFSIZE (255) -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_state_flags_to_string, NMActivationStateFlags, +static +NM_UTILS_FLAGS2STR_DEFINE (_state_flags_to_string, NMActivationStateFlags, NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_NONE, "none"), NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_MASTER, "is-master"), NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_SLAVE, "is-slave"), @@ -279,7 +281,7 @@ nm_active_connection_set_state (NMActiveConnection *self, priv->pending_activation_id) { nm_device_remove_pending_action (priv->device, priv->pending_activation_id, TRUE); - g_clear_pointer (&priv->pending_activation_id, g_free); + nm_clear_g_free (&priv->pending_activation_id); } } @@ -598,7 +600,9 @@ nm_active_connection_get_user_requested (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); - return nm_auth_subject_is_unix_process (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject); + return nm_auth_subject_get_subject_type ( + NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject + ) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS; } NMDevice * @@ -941,7 +945,7 @@ static void _settings_connection_flags_changed (NMSettingsConnection *settings_connection, NMActiveConnection *self) { - GError *error = NULL; + NMDevice *device; nm_assert (NM_IS_ACTIVE_CONNECTION (self)); nm_assert (NM_IS_SETTINGS_CONNECTION (settings_connection)); @@ -953,12 +957,17 @@ _settings_connection_flags_changed (NMSettingsConnection *settings_connection, return; _set_activation_type_managed (self); - if (!nm_device_reapply (nm_active_connection_get_device (self), - nm_settings_connection_get_connection ((nm_active_connection_get_settings_connection (self))), - &error)) { - _LOGW ("failed to reapply new device settings on previously externally managed device: %s", - error->message); - g_error_free (error); + + device = nm_active_connection_get_device (self); + if (device) { + gs_free_error GError *error = NULL; + + if (!nm_device_reapply (device, + nm_settings_connection_get_connection (nm_active_connection_get_settings_connection (self)), + &error)) { + _LOGW ("failed to reapply new device settings on previously externally managed device: %s", + error->message); + } } } @@ -1230,7 +1239,7 @@ _device_cleanup (NMActiveConnection *self) if (priv->pending_activation_id) { nm_device_remove_pending_action (priv->device, priv->pending_activation_id, TRUE); - g_clear_pointer (&priv->pending_activation_id, g_free); + nm_clear_g_free (&priv->pending_activation_id); } g_clear_object (&priv->device); @@ -1242,7 +1251,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE ((NMActiveConnection *) object); + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); char **strv; NMDevice *master_device = NULL; @@ -1396,7 +1405,7 @@ set_property (GObject *object, guint prop_id, case PROP_SPECIFIC_OBJECT: /* construct-only */ tmp = g_value_get_string (value); - tmp = nm_utils_dbus_normalize_object_path (tmp); + tmp = nm_dbus_path_not_empty (tmp); priv->specific_object = g_strdup (tmp); break; case PROP_DEFAULT: diff --git a/src/nm-audit-manager.c b/src/nm-audit-manager.c index b219b35a..26ba48f5 100644 --- a/src/nm-audit-manager.c +++ b/src/nm-audit-manager.c @@ -11,8 +11,9 @@ #include <libaudit.h> #endif -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "nm-config.h" +#include "nm-dbus-manager.h" #include "settings/nm-settings-connection.h" /*****************************************************************************/ @@ -195,11 +196,12 @@ _audit_log_helper (NMAuditManager *self, else if (G_IS_DBUS_METHOD_INVOCATION (subject_context)) { GDBusMethodInvocation *context = subject_context; - subject = subject_free = nm_auth_subject_new_unix_process_from_context (context); + subject = subject_free = nm_dbus_manager_new_auth_subject_from_context (context); } else g_warn_if_reached (); } - if (subject && nm_auth_subject_is_unix_process (subject)) { + if (subject && + nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) { pid = nm_auth_subject_get_unix_process_pid (subject); uid = nm_auth_subject_get_unix_process_uid (subject); if (pid != G_MAXULONG) { diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c index 3f248aee..88e6cb94 100644 --- a/src/nm-auth-manager.c +++ b/src/nm-auth-manager.c @@ -322,7 +322,7 @@ nm_auth_manager_check_authorization (NMAuthManager *self, }; c_list_link_tail (&priv->calls_lst_head, &call_id->calls_lst); - if (nm_auth_subject_is_internal (subject)) { + if (nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL) { _LOG2T (call_id, "CheckAuthorization(%s), subject=%s (succeeding for internal request)", action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf))); call_id->idle_id = g_idle_add (_call_on_idle, call_id); } else if (nm_auth_subject_get_unix_process_uid (subject) == 0) { @@ -339,7 +339,7 @@ nm_auth_manager_check_authorization (NMAuthManager *self, GVariant *subject_value; GVariant *details_value; - subject_value = nm_auth_subject_unix_process_to_polkit_gvariant (subject); + subject_value = nm_auth_subject_unix_to_polkit_gvariant (subject); nm_assert (g_variant_is_floating (subject_value)); /* ((PolkitDetails *)NULL) */ @@ -465,7 +465,7 @@ nm_auth_manager_force_shutdown (NMAuthManager *self) static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE ((NMAuthManager *) object); + NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (object); int v_int; switch (prop_id) { diff --git a/src/nm-auth-manager.h b/src/nm-auth-manager.h index 33e3bb2c..0a17055e 100644 --- a/src/nm-auth-manager.h +++ b/src/nm-auth-manager.h @@ -6,18 +6,24 @@ #ifndef NM_AUTH_MANAGER_H #define NM_AUTH_MANAGER_H -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "nm-config-data.h" /*****************************************************************************/ typedef enum { - NM_AUTH_CALL_RESULT_UNKNOWN, - NM_AUTH_CALL_RESULT_YES, - NM_AUTH_CALL_RESULT_AUTH, - NM_AUTH_CALL_RESULT_NO, + NM_AUTH_CALL_RESULT_UNKNOWN = NM_CLIENT_PERMISSION_RESULT_UNKNOWN, + NM_AUTH_CALL_RESULT_YES = NM_CLIENT_PERMISSION_RESULT_YES, + NM_AUTH_CALL_RESULT_AUTH = NM_CLIENT_PERMISSION_RESULT_AUTH, + NM_AUTH_CALL_RESULT_NO = NM_CLIENT_PERMISSION_RESULT_NO, } NMAuthCallResult; +static inline NMClientPermissionResult +nm_auth_call_result_to_client (NMAuthCallResult result) +{ + return (NMClientPermissionResult) result; +} + static inline NMAuthCallResult nm_auth_call_result_eval (gboolean is_authorized, gboolean is_challenge, diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c deleted file mode 100644 index ecf6b013..00000000 --- a/src/nm-auth-subject.c +++ /dev/null @@ -1,432 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2013 - 2014 Red Hat, Inc. - */ - -/** - * SECTION:nm-auth-subject - * @short_description: Encapsulates authentication information about a requestor - * - * #NMAuthSubject encpasulates identifying information about an entity that - * makes requests, like process identifier and user UID. - */ - -#include "nm-default.h" - -#include "nm-auth-subject.h" - -#include <stdlib.h> - -#include "nm-dbus-manager.h" - -enum { - PROP_0, - PROP_SUBJECT_TYPE, - PROP_UNIX_PROCESS_DBUS_SENDER, - PROP_UNIX_PROCESS_PID, - PROP_UNIX_PROCESS_UID, - - PROP_LAST, -}; - -typedef struct { - NMAuthSubjectType subject_type; - struct { - gulong pid; - gulong uid; - guint64 start_time; - char *dbus_sender; - } unix_process; -} NMAuthSubjectPrivate; - -struct _NMAuthSubject { - GObject parent; - NMAuthSubjectPrivate _priv; -}; - -struct _NMAuthSubjectClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT) - -#define NM_AUTH_SUBJECT_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMAuthSubject, NM_IS_AUTH_SUBJECT) - -/*****************************************************************************/ - -#define CHECK_SUBJECT(self, error_value) \ - NMAuthSubjectPrivate *priv; \ - g_return_val_if_fail (NM_IS_AUTH_SUBJECT (self), error_value); \ - priv = NM_AUTH_SUBJECT_GET_PRIVATE (self); \ - -#define CHECK_SUBJECT_TYPED(self, expected_subject_type, error_value) \ - CHECK_SUBJECT (self, error_value); \ - g_return_val_if_fail (priv->subject_type == (expected_subject_type), error_value); - -const char * -nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len) -{ - CHECK_SUBJECT (self, NULL); - - switch (priv->subject_type) { - case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS: - g_snprintf (buf, buf_len, "unix-process[pid=%lu, uid=%lu, start=%llu]", - (unsigned long) priv->unix_process.pid, - (unsigned long) priv->unix_process.uid, - (unsigned long long) priv->unix_process.start_time); - break; - case NM_AUTH_SUBJECT_TYPE_INTERNAL: - g_strlcpy (buf, "internal", buf_len); - break; - default: - g_strlcpy (buf, "invalid", buf_len); - break; - } - return buf; -} - -/* returns a floating variant */ -GVariant * -nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self) -{ - GVariantBuilder builder; - GVariant *dict; - GVariant *ret; - CHECK_SUBJECT_TYPED (self, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL); - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - g_variant_builder_add (&builder, "{sv}", "pid", - g_variant_new_uint32 (priv->unix_process.pid)); - g_variant_builder_add (&builder, "{sv}", "start-time", - g_variant_new_uint64 (priv->unix_process.start_time)); - g_variant_builder_add (&builder, "{sv}", "uid", - g_variant_new_int32 (priv->unix_process.uid)); - dict = g_variant_builder_end (&builder); - ret = g_variant_new ("(s@a{sv})", "unix-process", dict); - return ret; -} - -NMAuthSubjectType -nm_auth_subject_get_subject_type (NMAuthSubject *subject) -{ - CHECK_SUBJECT (subject, NM_AUTH_SUBJECT_TYPE_INVALID); - - return priv->subject_type; -} - -gboolean -nm_auth_subject_is_internal (NMAuthSubject *subject) -{ - return nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL; -} - -gboolean -nm_auth_subject_is_unix_process (NMAuthSubject *subject) -{ - return nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS; -} - -gulong -nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject) -{ - CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG); - - return priv->unix_process.pid; -} - -gulong -nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject) -{ - CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG); - - return priv->unix_process.uid; -} - -const char * -nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject) -{ - CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL); - - return priv->unix_process.dbus_sender; -} - -/*****************************************************************************/ - -static NMAuthSubject * -_new_unix_process (GDBusMethodInvocation *context, - GDBusConnection *connection, - GDBusMessage *message) -{ - NMAuthSubject *self; - const char *dbus_sender = NULL; - gulong uid = 0; - gulong pid = 0; - gboolean success; - - g_return_val_if_fail (context || (connection && message), NULL); - - if (context) { - success = nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), - context, - &dbus_sender, - &uid, - &pid); - } else { - nm_assert (message); - success = nm_dbus_manager_get_caller_info_from_message (nm_dbus_manager_get (), - connection, - message, - &dbus_sender, - &uid, - &pid); - } - - if (!success) - return NULL; - - g_return_val_if_fail (dbus_sender && *dbus_sender, NULL); - /* polkit glib library stores uid and pid as int. There might be some - * pitfalls if the id ever happens to be larger then that. Just assert against - * it here. */ - g_return_val_if_fail (uid <= MIN (G_MAXINT, G_MAXINT32), NULL); - g_return_val_if_fail (pid > 0 && pid <= MIN (G_MAXINT, G_MAXINT32), NULL); - - self = NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT, - NM_AUTH_SUBJECT_SUBJECT_TYPE, (int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, - NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, dbus_sender, - NM_AUTH_SUBJECT_UNIX_PROCESS_PID, (gulong) pid, - NM_AUTH_SUBJECT_UNIX_PROCESS_UID, (gulong) uid, - NULL)); - - if (NM_AUTH_SUBJECT_GET_PRIVATE (self)->subject_type != NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) { - /* this most likely happened because the process is gone (start_time==0). - * Either that is not assert-worthy, or constructed() already asserted. - * Just return NULL. */ - g_clear_object (&self); - } - return self; -} - -NMAuthSubject * -nm_auth_subject_new_unix_process_from_context (GDBusMethodInvocation *context) -{ - return _new_unix_process (context, NULL, NULL); -} - -NMAuthSubject * -nm_auth_subject_new_unix_process_from_message (GDBusConnection *connection, - GDBusMessage *message) -{ - return _new_unix_process (NULL, connection, message); -} - -/** - * nm_auth_subject_new_internal(): - * - * Creates a new auth subject representing the NetworkManager process itself. - * - * Returns: the new #NMAuthSubject - */ -NMAuthSubject * -nm_auth_subject_new_internal (void) -{ - return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT, - NM_AUTH_SUBJECT_SUBJECT_TYPE, (int) NM_AUTH_SUBJECT_TYPE_INTERNAL, - NULL)); -} - -/*****************************************************************************/ - -static void -get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE ((NMAuthSubject *) object); - - switch (prop_id) { - case PROP_SUBJECT_TYPE: - g_value_set_int (value, priv->subject_type); - break; - case PROP_UNIX_PROCESS_DBUS_SENDER: - g_value_set_string (value, priv->unix_process.dbus_sender); - break; - case PROP_UNIX_PROCESS_PID: - g_value_set_ulong (value, priv->unix_process.pid); - break; - case PROP_UNIX_PROCESS_UID: - g_value_set_ulong (value, priv->unix_process.uid); - 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) -{ - NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE ((NMAuthSubject *) object); - NMAuthSubjectType subject_type; - int i; - const char *str; - gulong id; - - switch (prop_id) { - case PROP_SUBJECT_TYPE: - /* construct-only */ - i = g_value_get_int (value); - g_return_if_fail (NM_IN_SET (i, (int) NM_AUTH_SUBJECT_TYPE_INTERNAL, (int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS)); - subject_type = i; - priv->subject_type |= subject_type; - g_return_if_fail (priv->subject_type == subject_type); - break; - case PROP_UNIX_PROCESS_DBUS_SENDER: - /* construct-only */ - if ((str = g_value_get_string (value))) { - priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS; - g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS); - priv->unix_process.dbus_sender = g_strdup (str); - } - break; - case PROP_UNIX_PROCESS_PID: - /* construct-only */ - if ((id = g_value_get_ulong (value)) != G_MAXULONG) { - priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS; - g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS); - priv->unix_process.pid = id; - } - break; - case PROP_UNIX_PROCESS_UID: - /* construct-only */ - if ((id = g_value_get_ulong (value)) != G_MAXULONG) { - priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS; - g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS); - priv->unix_process.uid = id; - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -_clear_private (NMAuthSubject *self) -{ - NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self); - - priv->subject_type = NM_AUTH_SUBJECT_TYPE_INVALID; - priv->unix_process.pid = G_MAXULONG; - priv->unix_process.uid = G_MAXULONG; - g_clear_pointer (&priv->unix_process.dbus_sender, g_free); -} - -static void -nm_auth_subject_init (NMAuthSubject *self) -{ - _clear_private (self); -} - -static void -constructed (GObject *object) -{ - NMAuthSubject *self = NM_AUTH_SUBJECT (object); - NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self); - - /* validate that the created instance. */ - - switch (priv->subject_type) { - case NM_AUTH_SUBJECT_TYPE_INTERNAL: - priv->unix_process.pid = G_MAXULONG; - priv->unix_process.uid = 0; /* internal uses 'root' user */ - return; - case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS: - /* Ensure pid and uid to be representable as int32. - * DBUS treats them as uint32, polkit library as int. */ - if (priv->unix_process.pid > MIN (G_MAXINT, G_MAXINT32)) - break; - if (priv->unix_process.uid > MIN (G_MAXINT, G_MAXINT32)) { - /* for uid==-1, libpolkit-gobject-1 detects the user based on the process id. - * Don't bother and require the user id as parameter. */ - break; - } - if (!priv->unix_process.dbus_sender || !*priv->unix_process.dbus_sender) - break; - - priv->unix_process.start_time = nm_utils_get_start_time_for_pid (priv->unix_process.pid, NULL, NULL); - - if (!priv->unix_process.start_time) { - /* Is the process already gone? Then fail creation of the auth subject - * by clearing the type. */ - if (kill (priv->unix_process.pid, 0) != 0) - _clear_private (self); - - /* Otherwise, although we didn't detect a start_time, the process is still around. - * That could be due to procfs mounted with hidepid. So just accept the request. - * - * Polkit on the other side, will accept 0 and try to lookup /proc/$PID/stat - * itself (and if it fails to do so, assume a start-time of 0 and proceed). - * The only combination that would fail here, is when NM is able to read the - * start-time, but polkit is not. */ - } - return; - default: - break; - } - - _clear_private (self); - g_return_if_reached (); -} - -static void -finalize (GObject *object) -{ - _clear_private ((NMAuthSubject *) object); - - G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object); -} - -static void -nm_auth_subject_class_init (NMAuthSubjectClass *config_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (config_class); - - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->constructed = constructed; - object_class->finalize = finalize; - - g_object_class_install_property - (object_class, PROP_SUBJECT_TYPE, - g_param_spec_int (NM_AUTH_SUBJECT_SUBJECT_TYPE, "", "", - NM_AUTH_SUBJECT_TYPE_INVALID, - NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, - NM_AUTH_SUBJECT_TYPE_INVALID, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_UNIX_PROCESS_DBUS_SENDER, - g_param_spec_string (NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, "", "", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_UNIX_PROCESS_PID, - g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_PID, "", "", - 0, G_MAXULONG, G_MAXULONG, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_UNIX_PROCESS_UID, - g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_UID, "", "", - 0, G_MAXULONG, G_MAXULONG, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - -} diff --git a/src/nm-auth-subject.h b/src/nm-auth-subject.h deleted file mode 100644 index 7a75aca9..00000000 --- a/src/nm-auth-subject.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_AUTH_SUBJECT_H__ -#define __NETWORKMANAGER_AUTH_SUBJECT_H__ - -#define NM_TYPE_AUTH_SUBJECT (nm_auth_subject_get_type ()) -#define NM_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubject)) -#define NM_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass)) -#define NM_IS_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AUTH_SUBJECT)) -#define NM_IS_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUTH_SUBJECT)) -#define NM_AUTH_SUBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass)) - -typedef enum { - NM_AUTH_SUBJECT_TYPE_INVALID = 0, - NM_AUTH_SUBJECT_TYPE_INTERNAL = 1, - NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS = 2, -} NMAuthSubjectType; - -#define NM_AUTH_SUBJECT_SUBJECT_TYPE "subject-type" -#define NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER "unix-process-dbus-sender" -#define NM_AUTH_SUBJECT_UNIX_PROCESS_PID "unix-process-pid" -#define NM_AUTH_SUBJECT_UNIX_PROCESS_UID "unix-process-uid" - -typedef struct _NMAuthSubjectClass NMAuthSubjectClass; - -GType nm_auth_subject_get_type (void); - -NMAuthSubject *nm_auth_subject_new_internal (void); - -NMAuthSubject *nm_auth_subject_new_unix_process_from_context (GDBusMethodInvocation *context); - -NMAuthSubject *nm_auth_subject_new_unix_process_from_message (GDBusConnection *connection, GDBusMessage *message); - -NMAuthSubjectType nm_auth_subject_get_subject_type (NMAuthSubject *subject); - -gboolean nm_auth_subject_is_internal (NMAuthSubject *subject); - -gboolean nm_auth_subject_is_unix_process (NMAuthSubject *subject); - -gulong nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject); - -const char *nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject); - -gulong nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject); - -const char *nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len); - -GVariant * nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self); - -#endif /* __NETWORKMANAGER_AUTH_SUBJECT_H__ */ diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c index a5b951ab..ca2870db 100644 --- a/src/nm-auth-utils.c +++ b/src/nm-auth-utils.c @@ -9,13 +9,14 @@ #include "nm-glib-aux/nm-c-list.h" #include "nm-setting-connection.h" -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "nm-auth-manager.h" #include "nm-session-monitor.h" +#include "nm-dbus-manager.h" /*****************************************************************************/ -struct NMAuthChain { +struct _NMAuthChain { CList parent_lst; @@ -265,6 +266,14 @@ nm_auth_chain_get_subject (NMAuthChain *self) return self->subject; } +GDBusMethodInvocation * +nm_auth_chain_get_context (NMAuthChain *self) +{ + g_return_val_if_fail (self, NULL); + + return self->context; +} + /*****************************************************************************/ static void @@ -341,8 +350,10 @@ nm_auth_chain_add_call_unsafe (NMAuthChain *self, g_return_if_fail (!self->is_finishing); g_return_if_fail (!self->is_destroyed); g_return_if_fail (permission && *permission); - nm_assert ( nm_auth_subject_is_unix_process (self->subject) - || nm_auth_subject_is_internal (self->subject)); + nm_assert ( nm_auth_subject_get_subject_type (self->subject) + == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS + || nm_auth_subject_get_subject_type (self->subject) + == NM_AUTH_SUBJECT_TYPE_INTERNAL); /* duplicate permissions are not supported, also because nm_auth_chain_get_result() * can only return one-permission. */ @@ -395,7 +406,7 @@ nm_auth_chain_new_context (GDBusMethodInvocation *context, g_return_val_if_fail (context, NULL); nm_assert (done_func); - subject = nm_auth_subject_new_unix_process_from_context (context); + subject = nm_dbus_manager_new_auth_subject_from_context (context); if (!subject) return NULL; @@ -416,8 +427,10 @@ nm_auth_chain_new_subject (NMAuthSubject *subject, NMAuthChain *self; g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - nm_assert ( nm_auth_subject_is_unix_process (subject) - || nm_auth_subject_is_internal (subject)); + nm_assert ( nm_auth_subject_get_subject_type (subject) + == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS + || nm_auth_subject_get_subject_type (subject) + == NM_AUTH_SUBJECT_TYPE_INTERNAL); nm_assert (done_func); self = g_slice_new (NMAuthChain); @@ -504,10 +517,12 @@ nm_auth_is_subject_in_acl (NMConnection *connection, g_return_val_if_fail (connection, FALSE); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), FALSE); - nm_assert ( nm_auth_subject_is_internal (subject) - || nm_auth_subject_is_unix_process (subject)); + nm_assert ( nm_auth_subject_get_subject_type (subject) + == NM_AUTH_SUBJECT_TYPE_INTERNAL + || nm_auth_subject_get_subject_type (subject) + == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS); - if (nm_auth_subject_is_internal (subject)) + if (nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL) return TRUE; uid = nm_auth_subject_get_unix_process_uid (subject); diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h index 808d20fd..978d607a 100644 --- a/src/nm-auth-utils.h +++ b/src/nm-auth-utils.h @@ -12,7 +12,7 @@ /*****************************************************************************/ -typedef struct NMAuthChain NMAuthChain; +typedef struct _NMAuthChain NMAuthChain; typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain, GDBusMethodInvocation *context, @@ -53,6 +53,8 @@ void nm_auth_chain_destroy (NMAuthChain *chain); NMAuthSubject *nm_auth_chain_get_subject (NMAuthChain *self); +GDBusMethodInvocation *nm_auth_chain_get_context (NMAuthChain *self); + /*****************************************************************************/ struct CList; diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index 734a40e1..3a372667 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -9,7 +9,7 @@ #include "nm-active-connection.h" #include "nm-act-request.h" -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "nm-core-utils.h" #include "nm-dbus-interface.h" #include "devices/nm-device.h" @@ -585,7 +585,7 @@ nm_checkpoint_adjust_rollback_timeout (NMCheckpoint *self, guint32 add_timeout) if (add_timeout == 0) rollback_timeout_s = 0; else { - now_ms = nm_utils_get_monotonic_timestamp_ms (); + now_ms = nm_utils_get_monotonic_timestamp_msec (); add_timeout_ms = ((gint64) add_timeout) * 1000; rollback_timeout_ms = (now_ms - priv->created_at_ms) + add_timeout_ms; @@ -626,7 +626,7 @@ get_property (GObject *object, guint prop_id, case PROP_CREATED: g_value_set_int64 (value, nm_utils_monotonic_timestamp_as_boottime (priv->created_at_ms, - NM_UTILS_NS_PER_MSEC)); + NM_UTILS_NSEC_PER_MSEC)); break; case PROP_ROLLBACK_TIMEOUT: g_value_set_uint (value, priv->rollback_timeout_s); @@ -679,7 +679,7 @@ nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_time priv = NM_CHECKPOINT_GET_PRIVATE (self); priv->manager = g_object_ref (manager); priv->rollback_timeout_s = rollback_timeout_s; - priv->created_at_ms = nm_utils_get_monotonic_timestamp_ms (); + priv->created_at_ms = nm_utils_get_monotonic_timestamp_msec (); priv->flags = flags; if (rollback_timeout_s != 0) { @@ -723,8 +723,8 @@ dispose (GObject *object) nm_assert (c_list_is_empty (&self->checkpoints_lst)); - g_clear_pointer (&priv->devices, g_hash_table_unref); - g_clear_pointer (&priv->connection_uuids, g_hash_table_unref); + nm_clear_pointer (&priv->devices, g_hash_table_unref); + nm_clear_pointer (&priv->connection_uuids, g_hash_table_unref); nm_clear_pointer (&priv->removed_devices, g_ptr_array_unref); nm_clear_g_signal_handler (priv->manager, &priv->dev_removed_id); diff --git a/src/nm-config-data.c b/src/nm-config-data.c index c787aa98..29dafa14 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -11,7 +11,7 @@ #include "nm-config.h" #include "devices/nm-device.h" #include "nm-core-internal.h" -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" /*****************************************************************************/ @@ -1024,8 +1024,8 @@ load_global_dns (GKeyFile *keyfile, gboolean internal) if (strv) { _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); for (i = 0, j = 0; strv[i]; i++) { - if ( nm_utils_ipaddr_valid (AF_INET, strv[i]) - || nm_utils_ipaddr_valid (AF_INET6, strv[i])) + if ( nm_utils_ipaddr_is_valid (AF_INET, strv[i]) + || nm_utils_ipaddr_is_valid (AF_INET6, strv[i])) strv[j++] = strv[i]; else g_free (strv[i]); @@ -1147,8 +1147,8 @@ global_dns_domain_from_dbus (char *name, GVariant *variant) strv = g_variant_dup_strv (val, NULL); _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); for (i = 0, j = 0; strv && strv[i]; i++) { - if ( nm_utils_ipaddr_valid (AF_INET, strv[i]) - || nm_utils_ipaddr_valid (AF_INET6, strv[i])) + if ( nm_utils_ipaddr_is_valid (AF_INET, strv[i]) + || nm_utils_ipaddr_is_valid (AF_INET6, strv[i])) strv[j++] = strv[i]; else g_free (strv[i]); @@ -1875,7 +1875,7 @@ nm_config_data_new_update_no_auto_default (const NMConfigData *base, static void finalize (GObject *gobject) { - NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE ((NMConfigData *) gobject); + NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (gobject); g_free (priv->config_main_file); g_free (priv->config_description); diff --git a/src/nm-config.c b/src/nm-config.c index 4ea97657..63347db7 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -14,7 +14,7 @@ #include "devices/nm-device.h" #include "NetworkManagerUtils.h" #include "nm-core-internal.h" -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" #define DEFAULT_CONFIG_MAIN_FILE NMCONFDIR "/NetworkManager.conf" #define DEFAULT_CONFIG_DIR NMCONFDIR "/conf.d" @@ -274,7 +274,7 @@ nm_config_get_warnings (NMConfig *config) void nm_config_clear_warnings (NMConfig *config) { - g_clear_pointer (&NM_CONFIG_GET_PRIVATE (config)->warnings, g_strfreev); + nm_clear_pointer (&NM_CONFIG_GET_PRIVATE (config)->warnings, g_strfreev); } NMConfigData * @@ -481,17 +481,17 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device) static void _nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli) { - g_clear_pointer (&cli->config_main_file, g_free); - g_clear_pointer (&cli->config_dir, g_free); - g_clear_pointer (&cli->system_config_dir, g_free); - g_clear_pointer (&cli->no_auto_default_file, g_free); - g_clear_pointer (&cli->intern_config_file, g_free); - g_clear_pointer (&cli->state_file, g_free); - g_clear_pointer (&cli->plugins, g_free); + nm_clear_g_free (&cli->config_main_file); + nm_clear_g_free (&cli->config_dir); + nm_clear_g_free (&cli->system_config_dir); + nm_clear_g_free (&cli->no_auto_default_file); + nm_clear_g_free (&cli->intern_config_file); + nm_clear_g_free (&cli->state_file); + nm_clear_g_free (&cli->plugins); cli->configure_and_quit = NM_CONFIG_CONFIGURE_AND_QUIT_DISABLED; cli->is_debug = FALSE; - g_clear_pointer (&cli->connectivity_uri, g_free); - g_clear_pointer (&cli->connectivity_response, g_free); + nm_clear_g_free (&cli->connectivity_uri); + nm_clear_g_free (&cli->connectivity_response); cli->connectivity_interval = -1; cli->first_start = FALSE; } @@ -2193,7 +2193,8 @@ _nm_config_state_set (NMConfig *self, #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_ROOT_PATH "root-path" #define DEVICE_RUN_STATE_KEYFILE_KEY_DEVICE_NEXT_SERVER "next-server" -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_device_state_managed_type_to_str, NMConfigDeviceStateManagedType, +static +NM_UTILS_LOOKUP_STR_DEFINE (_device_state_managed_type_to_str, NMConfigDeviceStateManagedType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNKNOWN, "unknown"), NM_UTILS_LOOKUP_STR_ITEM (NM_CONFIG_DEVICE_STATE_MANAGED_TYPE_UNMANAGED, "unmanaged"), @@ -2898,7 +2899,7 @@ nm_config_new (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes static void finalize (GObject *gobject) { - NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE ((NMConfig *) gobject); + NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (gobject); state_free (priv->state); diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index e941fe7e..2d80fd90 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -26,7 +26,8 @@ /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_state_to_string, int /*NMConnectivityState*/, +static +NM_UTILS_LOOKUP_STR_DEFINE (_state_to_string, int /*NMConnectivityState*/, NM_UTILS_LOOKUP_DEFAULT_WARN ("???"), NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_UNKNOWN, "UNKNOWN"), NM_UTILS_LOOKUP_STR_ITEM (NM_CONNECTIVITY_NONE, "NONE"), @@ -415,13 +416,13 @@ _con_curl_timeout_cb (gpointer user_data) } static int -multi_timer_cb (CURLM *multi, long timeout_ms, void *userdata) +multi_timer_cb (CURLM *multi, long timeout_msec, void *userdata) { NMConnectivityCheckHandle *cb_data = userdata; nm_clear_g_source (&cb_data->concheck.curl_timer); - if (timeout_ms != -1) - cb_data->concheck.curl_timer = g_timeout_add (timeout_ms, _con_curl_timeout_cb, cb_data); + if (timeout_msec != -1) + cb_data->concheck.curl_timer = g_timeout_add (timeout_msec, _con_curl_timeout_cb, cb_data); return 0; } @@ -515,8 +516,12 @@ multi_socket_cb (CURL *e_handle, curl_socket_t fd, int what, void *userdata, voi condition = 0; if (condition) { - fdp->source = g_unix_fd_source_new (fd, condition); - g_source_set_callback (fdp->source, G_SOURCE_FUNC (_con_curl_socketevent_cb), fdp, NULL); + fdp->source = nm_g_unix_fd_source_new (fd, + condition, + G_PRIORITY_DEFAULT, + _con_curl_socketevent_cb, + fdp, + NULL); g_source_attach (fdp->source, NULL); } } diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index e059994a..a9f50a0f 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -436,7 +436,7 @@ static const char * _kc_waited_to_string (char *buf, gint64 wait_start_us) #define _kc_waited_to_string(buf, wait_start_us) ( G_STATIC_ASSERT_EXPR(sizeof (buf) == KC_WAITED_TO_STRING && sizeof ((buf)[0]) == 1), _kc_waited_to_string (buf, wait_start_us) ) { - g_snprintf (buf, KC_WAITED_TO_STRING, " (%ld usec elapsed)", (long) (nm_utils_get_monotonic_timestamp_us () - wait_start_us)); + g_snprintf (buf, KC_WAITED_TO_STRING, " (%ld usec elapsed)", (long) (nm_utils_get_monotonic_timestamp_usec () - wait_start_us)); return buf; } @@ -476,7 +476,7 @@ _kc_cb_timeout_grace_period (void *user_data) } } else { nm_log_dbg (data->log_domain, "%s: process not terminated after %ld usec. Sending SIGKILL signal", - data->log_name, (long) (nm_utils_get_monotonic_timestamp_us () - data->async.wait_start_us)); + data->log_name, (long) (nm_utils_get_monotonic_timestamp_usec () - data->async.wait_start_us)); } return G_SOURCE_REMOVE; @@ -591,7 +591,7 @@ nm_utils_kill_child_async (pid_t pid, int sig, NMLogDomain log_domain, } data = _kc_async_data_alloc (pid, log_domain, log_name, callback, user_data); - data->async.wait_start_us = nm_utils_get_monotonic_timestamp_us (); + data->async.wait_start_us = nm_utils_get_monotonic_timestamp_usec (); if (sig != SIGKILL && wait_before_kill_msec > 0) { data->async.source_timeout_kill_id = g_timeout_add (wait_before_kill_msec, _kc_cb_timeout_grace_period, data); @@ -694,7 +694,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char goto out; } - wait_start_us = nm_utils_get_monotonic_timestamp_us (); + wait_start_us = nm_utils_get_monotonic_timestamp_usec (); /* wait for the process to terminated... */ if (sig != SIGKILL) { @@ -728,7 +728,7 @@ nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char if (!wait_until) break; - now = nm_utils_get_monotonic_timestamp_us (); + now = nm_utils_get_monotonic_timestamp_usec (); if (now >= wait_until) break; @@ -871,7 +871,7 @@ nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain /* wait for the process to terminate... */ - wait_start_us = nm_utils_get_monotonic_timestamp_us (); + wait_start_us = nm_utils_get_monotonic_timestamp_usec (); sleep_duration_usec = _sleep_duration_convert_ms_to_us (sleep_duration_msec); if (sig != SIGKILL && wait_before_kill_msec) @@ -922,7 +922,7 @@ nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain } sleep_time = sleep_duration_usec; - now = nm_utils_get_monotonic_timestamp_us (); + now = nm_utils_get_monotonic_timestamp_usec (); if ( max_wait_until != 0 && now >= max_wait_until) { @@ -2434,7 +2434,7 @@ _host_id_read_timestamp (gboolean use_secret_key_file, && stat (SECRET_KEY_FILE, &st) == 0) { /* don't check for overflow or timestamps in the future. We get whatever * (bogus) date is on the file. */ - *out_timestamp_ns = nm_utils_timespec_to_ns (&st.st_mtim); + *out_timestamp_ns = nm_utils_timespec_to_nsec (&st.st_mtim); return TRUE; } @@ -2453,13 +2453,13 @@ _host_id_read_timestamp (gboolean use_secret_key_file, * is not stable across restarts, but apparently neither is the host-id * nor the secret_key itself. */ -#define EPOCH_TWO_YEARS (G_GINT64_CONSTANT (2 * 365 * 24 * 3600) * NM_UTILS_NS_PER_SECOND) +#define EPOCH_TWO_YEARS (G_GINT64_CONSTANT (2 * 365 * 24 * 3600) * NM_UTILS_NSEC_PER_SEC) v = nm_hash_siphash42 (1156657133u, host_id, host_id_len); now = time (NULL); *out_timestamp_ns = NM_MAX ((gint64) 1, - (now * NM_UTILS_NS_PER_SECOND) - ((gint64) (v % ((guint64) (EPOCH_TWO_YEARS))))); + (now * NM_UTILS_NSEC_PER_SEC) - ((gint64) (v % ((guint64) (EPOCH_TWO_YEARS))))); return FALSE; } @@ -2741,6 +2741,59 @@ nm_utils_boot_id_bin (void) /*****************************************************************************/ +const char * +nm_utils_proc_cmdline (void) +{ + static const char *volatile proc_cmdline_cached = NULL; + const char *proc_cmdline; + +again: + proc_cmdline = g_atomic_pointer_get (&proc_cmdline_cached); + if (G_UNLIKELY (!proc_cmdline)) { + gs_free char *str = NULL; + + g_file_get_contents ("/proc/cmdline", &str, NULL, NULL); + str = nm_str_realloc (str); + + proc_cmdline = str ?: ""; + if (!g_atomic_pointer_compare_and_exchange (&proc_cmdline_cached, NULL, proc_cmdline)) + goto again; + + g_steal_pointer (&str); + } + + return proc_cmdline; +} + +const char *const* +nm_utils_proc_cmdline_split (void) +{ + static const char *const*volatile proc_cmdline_cached = NULL; + const char *const*proc_cmdline; + +again: + proc_cmdline = g_atomic_pointer_get (&proc_cmdline_cached); + if (G_UNLIKELY (!proc_cmdline)) { + gs_free const char **split = NULL; + + /* TODO: support quotation, like systemd's proc_cmdline_extract_first(). + * For that, add a new NMUtilsStrsplitSetFlags flag. */ + split = nm_utils_strsplit_set_full (nm_utils_proc_cmdline (), + NM_ASCII_WHITESPACES, + NM_UTILS_STRSPLIT_SET_FLAGS_NONE); + proc_cmdline = split + ?: NM_PTRARRAY_EMPTY (const char *); + if (!g_atomic_pointer_compare_and_exchange (&proc_cmdline_cached, NULL, proc_cmdline)) + goto again; + + g_steal_pointer (&split); + } + + return proc_cmdline; +} + +/*****************************************************************************/ + /** * nm_utils_arp_type_detect_from_hwaddrlen: * @hwaddr_len: the length of the hardware address in bytes. @@ -2999,12 +3052,14 @@ nm_utils_ipv6_interface_identifier_get_from_token (NMUtilsIPv6IfaceId *iid, * Returns: the input buffer filled with the id as string. */ const char * -nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid, char *buf) +nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid, + char buf[static INET6_ADDRSTRLEN]) { struct in6_addr i6_token = { .s6_addr = { 0, } }; + nm_assert (buf); nm_utils_ipv6_addr_set_interface_identifier (&i6_token, iid); - return nm_utils_inet6_ntop (&i6_token, buf); + return _nm_utils_inet6_ntop (&i6_token, buf); } /*****************************************************************************/ @@ -3721,7 +3776,7 @@ nm_utils_lifetime_get (guint32 timestamp, } if (now <= 0) - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); t_lifetime = nm_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now); if (!t_lifetime) { @@ -4053,24 +4108,386 @@ GVariant * nm_utils_strdict_to_variant (GHashTable *options) { GVariantBuilder builder; - gs_free const char **keys = NULL; + gs_free NMUtilsNamedValue *values = NULL; guint i; - guint nkeys; + guint n; - keys = nm_utils_strdict_get_keys (options, TRUE, &nkeys); + values = nm_utils_named_values_from_str_dict (options, &n); g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - for (i = 0; i < nkeys; i++) { + for (i = 0; i < n; i++) { g_variant_builder_add (&builder, "{sv}", - keys[i], - g_variant_new_string (g_hash_table_lookup (options, keys[i]))); + values[i].name, + g_variant_new_string (values[i].value_str)); } return g_variant_builder_end (&builder); } /*****************************************************************************/ +static guint32 +get_max_rate_ht_20 (int mcs) +{ + switch (mcs) { + case 0: return 6500000; + case 1: + case 8: return 13000000; + case 2: + case 16: return 19500000; + case 3: + case 9: + case 24: return 26000000; + case 4: + case 10: + case 17: return 39000000; + case 5: + case 11: + case 25: return 52000000; + case 6: + case 18: return 58500000; + case 7: return 65000000; + case 12: + case 19: + case 26: return 78000000; + case 13: + case 27: return 104000000; + case 14: + case 20: return 117000000; + case 15: return 130000000; + case 21: + case 28: return 156000000; + case 22: return 175500000; + case 23: return 195000000; + case 29: return 208000000; + case 30: return 234000000; + case 31: return 260000000; + } + return 0; +} + +static guint32 +get_max_rate_ht_40 (int mcs) +{ + switch (mcs) { + case 0: return 13500000; + case 1: + case 8: return 27000000; + case 2: return 40500000; + case 3: + case 9: + case 24: return 54000000; + case 4: + case 10: + case 17: return 81000000; + case 5: + case 11: + case 25: return 108000000; + case 6: + case 18: return 121500000; + case 7: return 135000000; + case 12: + case 19: + case 26: return 162000000; + case 13: + case 27: return 216000000; + case 14: + case 20: return 243000000; + case 15: return 270000000; + case 16: return 40500000; + case 21: + case 28: return 324000000; + case 22: return 364500000; + case 23: return 405000000; + case 29: return 432000000; + case 30: return 486000000; + case 31: return 540000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_80_ss1 (int mcs) +{ + switch (mcs) { + case 0: return 29300000; + case 1: return 58500000; + case 2: return 87800000; + case 3: return 117000000; + case 4: return 175500000; + case 5: return 234000000; + case 6: return 263300000; + case 7: return 292500000; + case 8: return 351000000; + case 9: return 390000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_80_ss2 (int mcs) +{ + switch (mcs) { + case 0: return 58500000; + case 1: return 117000000; + case 2: return 175500000; + case 3: return 234000000; + case 4: return 351000000; + case 5: return 468000000; + case 6: return 526500000; + case 7: return 585000000; + case 8: return 702000000; + case 9: return 780000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_80_ss3 (int mcs) +{ + switch (mcs) { + case 0: return 87800000; + case 1: return 175500000; + case 2: return 263300000; + case 3: return 351000000; + case 4: return 526500000; + case 5: return 702000000; + case 6: return 0; + case 7: return 877500000; + case 8: return 105300000; + case 9: return 117000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_160_ss1 (int mcs) +{ + switch (mcs) { + case 0: return 58500000; + case 1: return 117000000; + case 2: return 175500000; + case 3: return 234000000; + case 4: return 351000000; + case 5: return 468000000; + case 6: return 526500000; + case 7: return 585000000; + case 8: return 702000000; + case 9: return 780000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_160_ss2 (int mcs) +{ + switch (mcs) { + case 0: return 117000000; + case 1: return 234000000; + case 2: return 351000000; + case 3: return 468000000; + case 4: return 702000000; + case 5: return 936000000; + case 6: return 1053000000; + case 7: return 1170000000; + case 8: return 1404000000; + case 9: return 1560000000; + } + return 0; +} + +static guint32 +get_max_rate_vht_160_ss3 (int mcs) +{ + switch (mcs) { + case 0: return 175500000; + case 1: return 351000000; + case 2: return 526500000; + case 3: return 702000000; + case 4: return 1053000000; + case 5: return 1404000000; + case 6: return 1579500000; + case 7: return 1755000000; + case 8: return 2106000000; + case 9: return 0; + } + return 0; +} + +static gboolean +get_max_rate_ht (const guint8 *bytes, guint len, guint32 *out_maxrate) +{ + guint32 i; + guint8 ht_cap_info; + const guint8 *supported_mcs_set; + guint32 rate; + + /* http://standards.ieee.org/getieee802/download/802.11-2012.pdf + * https://mrncciew.com/2014/10/19/cwap-ht-capabilities-ie/ + */ + + if (len != 26) + return FALSE; + + ht_cap_info = bytes[0]; + supported_mcs_set = &bytes[3]; + *out_maxrate = 0; + + /* Find the maximum supported mcs rate */ + for (i = 0; i <= 76; i++) { + const unsigned mcs_octet = i / 8; + const unsigned MCS_RATE_BIT = 1 << i % 8; + + if (supported_mcs_set[mcs_octet] & MCS_RATE_BIT) { + /* Check for 40Mhz wide channel support */ + if (ht_cap_info & (1 << 1)) + rate = get_max_rate_ht_40 (i); + else + rate = get_max_rate_ht_20 (i); + + if (rate > *out_maxrate) + *out_maxrate = rate; + } + } + + return TRUE; +} + +static gboolean +get_max_rate_vht (const guint8 *bytes, guint len, guint32 *out_maxrate) +{ + guint32 mcs, m; + guint8 vht_cap, tx_map; + + /* https://tda802dot11.blogspot.it/2014/10/vht-capabilities-element-vht.html + * http://chimera.labs.oreilly.com/books/1234000001739/ch03.html#management_frames */ + + if (len != 12) + return FALSE; + + vht_cap = bytes[0]; + tx_map = bytes[8]; + + /* Check for mcs rates 8 and 9 support */ + if (tx_map & 0x2a) + mcs = 9; + else if (tx_map & 0x15) + mcs = 8; + else + mcs = 7; + + /* Check for 160Mhz wide channel support and + * spatial stream support */ + if (vht_cap & (1 << 2)) { + if (tx_map & 0x30) + m = get_max_rate_vht_160_ss3 (mcs); + else if (tx_map & 0x0C) + m = get_max_rate_vht_160_ss2 (mcs); + else + m = get_max_rate_vht_160_ss1 (mcs); + } else { + if (tx_map & 0x30) + m = get_max_rate_vht_80_ss3 (mcs); + else if (tx_map & 0x0C) + m = get_max_rate_vht_80_ss2 (mcs); + else + m = get_max_rate_vht_80_ss1 (mcs); + } + + *out_maxrate = m; + return TRUE; +} + +/* Management Frame Information Element IDs, ieee80211_eid */ +#define WLAN_EID_HT_CAPABILITY 45 +#define WLAN_EID_VHT_CAPABILITY 191 +#define WLAN_EID_VENDOR_SPECIFIC 221 + +void +nm_wifi_utils_parse_ies (const guint8 *bytes, + gsize len, + guint32 *out_max_rate, + gboolean *out_metered, + gboolean *out_owe_transition_mode) +{ + guint8 id, elem_len; + guint32 m; + + NM_SET_OUT (out_max_rate, 0); + NM_SET_OUT (out_metered, FALSE); + NM_SET_OUT (out_owe_transition_mode, FALSE); + + while (len) { + if (len < 2) + break; + + id = *bytes++; + elem_len = *bytes++; + len -= 2; + + if (elem_len > len) + break; + + switch (id) { + case WLAN_EID_HT_CAPABILITY: + if (out_max_rate) { + if (get_max_rate_ht (bytes, elem_len, &m)) + *out_max_rate = NM_MAX (*out_max_rate, m); + } + break; + case WLAN_EID_VHT_CAPABILITY: + if (out_max_rate) { + if (get_max_rate_vht (bytes, elem_len, &m)) + *out_max_rate = NM_MAX (*out_max_rate, m); + } + break; + case WLAN_EID_VENDOR_SPECIFIC: + if (out_metered) { + if ( len == 8 + && bytes[0] == 0x00 /* OUI: Microsoft */ + && bytes[1] == 0x50 + && bytes[2] == 0xf2 + && bytes[3] == 0x11) /* OUI type: Network cost */ + *out_metered = (bytes[7] > 1); /* Cost level > 1 */ + } + if ( out_owe_transition_mode + && elem_len >= 10 + && bytes[0] == 0x50 /* OUI: WiFi Alliance */ + && bytes[1] == 0x6f + && bytes[2] == 0x9a + && bytes[3] == 0x1c) /* OUI type: OWE Transition Mode */ + *out_owe_transition_mode = TRUE; + break; + } + + len -= elem_len; + bytes += elem_len; + } +} + +/*****************************************************************************/ + +guint8 +nm_wifi_utils_level_to_quality (int val) +{ + if (val < 0) { + /* Assume dBm already; rough conversion: best = -40, worst = -100 */ + val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */ + val = 100 - (int) ((100.0 * (double) val) / 60.0); + } else if (val > 110 && val < 256) { + /* assume old-style WEXT 8-bit unsigned signal level */ + val -= 256; /* subtract 256 to convert to dBm */ + val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */ + val = 100 - (int) ((100.0 * (double) val) / 60.0); + } else { + /* Assume signal is a "quality" percentage */ + } + + return CLAMP (val, 0, 100); +} + +/*****************************************************************************/ + NM_UTILS_ENUM2STR_DEFINE (nm_icmpv6_router_pref_to_string, NMIcmpv6RouterPref, NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_LOW, "low"), NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_MEDIUM, "medium"), diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index 7d63d06a..e30d7b36 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -267,6 +267,8 @@ gboolean nm_utils_machine_id_is_fake (void); const char *nm_utils_boot_id_str (void); const struct _NMUuid *nm_utils_boot_id_bin (void); +const char *nm_utils_proc_cmdline (void); +const char *const*nm_utils_proc_cmdline_split (void); gboolean nm_utils_host_id_get (const guint8 **out_host_id, gsize *out_host_id_len); @@ -316,7 +318,7 @@ gboolean nm_utils_ipv6_interface_identifier_get_from_token (NMUtilsIPv6IfaceId * const char *token); const char *nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid, - char *buf); + char buf[static INET6_ADDRSTRLEN]); gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type, const guint8 *hwaddr, @@ -473,6 +475,16 @@ const char *nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing) /*****************************************************************************/ +void nm_wifi_utils_parse_ies (const guint8 *bytes, + gsize len, + guint32 *out_max_rate, + gboolean *out_metered, + gboolean *out_owe_transition_mode); + +guint8 nm_wifi_utils_level_to_quality (int val); + +/*****************************************************************************/ + #define NM_VPN_ROUTE_METRIC_DEFAULT 50 #define NM_UTILS_ERROR_MSG_REQ_AUTH_FAILED "Unable to authenticate the request" diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c index 3f6f8115..239e06e1 100644 --- a/src/nm-dbus-manager.c +++ b/src/nm-dbus-manager.c @@ -19,6 +19,7 @@ #include "nm-std-aux/nm-dbus-compat.h" #include "nm-dbus-object.h" #include "NetworkManagerUtils.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" /* The base path for our GDBusObjectManagerServers. They do not contain * "NetworkManager" because GDBusObjectManagerServer requires that all @@ -523,7 +524,7 @@ _get_caller_info_ensure (NMDBusManager *self, gint64 now_ns; gsize num; -#define CALLER_INFO_MAX_AGE (NM_UTILS_NS_PER_SECOND * 1) +#define CALLER_INFO_MAX_AGE (NM_UTILS_NSEC_PER_SEC * 1) /* Linear search the cache for the sender. * @@ -564,7 +565,7 @@ _get_caller_info_ensure (NMDBusManager *self, } } - now_ns = nm_utils_get_monotonic_timestamp_ns (); + now_ns = nm_utils_get_monotonic_timestamp_nsec (); if ( ensure_uid && (now_ns - caller_info->uid_checked_at) > CALLER_INFO_MAX_AGE) { @@ -1630,7 +1631,7 @@ dispose (GObject *object) nm_assert (!priv->objects_by_path || g_hash_table_size (priv->objects_by_path) == 0); nm_assert (c_list_is_empty (&priv->objects_lst_head)); - g_clear_pointer (&priv->objects_by_path, g_hash_table_destroy); + nm_clear_pointer (&priv->objects_by_path, g_hash_table_destroy); c_list_for_each_entry_safe (s, s_safe, &priv->private_servers_lst_head, private_servers_lst) private_server_free (s); @@ -1669,3 +1670,66 @@ nm_dbus_manager_class_init (NMDBusManagerClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER); } + +static NMAuthSubject * +_new_unix_process (GDBusMethodInvocation *context, + GDBusConnection *connection, + GDBusMessage *message) +{ + NMAuthSubject *self; + const char *dbus_sender = NULL; + gulong uid = 0; + gulong pid = 0; + gboolean success; + + g_return_val_if_fail (context || (connection && message), NULL); + + if (context) { + success = nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), + context, + &dbus_sender, + &uid, + &pid); + } else { + nm_assert (message); + success = nm_dbus_manager_get_caller_info_from_message (nm_dbus_manager_get (), + connection, + message, + &dbus_sender, + &uid, + &pid); + } + + if (!success) + return NULL; + + g_return_val_if_fail (dbus_sender && *dbus_sender, NULL); + /* polkit glib library stores uid and pid as int. There might be some + * pitfalls if the id ever happens to be larger then that. Just assert against + * it here. */ + g_return_val_if_fail (uid <= MIN (G_MAXINT, G_MAXINT32), NULL); + g_return_val_if_fail (pid > 0 && pid <= MIN (G_MAXINT, G_MAXINT32), NULL); + + self = nm_auth_subject_new_unix_process (dbus_sender, pid, uid); + + if (nm_auth_subject_get_subject_type (self) != NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) { + /* this most likely happened because the process is gone (start_time==0). + * Either that is not assert-worthy, or constructed() already asserted. + * Just return NULL. */ + g_clear_object (&self); + } + return self; +} + +NMAuthSubject * +nm_dbus_manager_new_auth_subject_from_context (GDBusMethodInvocation *context) +{ + return _new_unix_process (context, NULL, NULL); +} + +NMAuthSubject * +nm_dbus_manager_new_auth_subject_from_message (GDBusConnection *connection, + GDBusMessage *message) +{ + return _new_unix_process (NULL, connection, message); +} diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h index a6094938..28785874 100644 --- a/src/nm-dbus-manager.h +++ b/src/nm-dbus-manager.h @@ -88,4 +88,9 @@ void nm_dbus_manager_private_server_register (NMDBusManager *self, const char *path, const char *tag); +NMAuthSubject *nm_dbus_manager_new_auth_subject_from_context (GDBusMethodInvocation *context); + +NMAuthSubject *nm_dbus_manager_new_auth_subject_from_message (GDBusConnection *connection, + GDBusMessage *message); + #endif /* __NM_DBUS_MANAGER_H__ */ diff --git a/src/nm-dbus-object.c b/src/nm-dbus-object.c index a829417c..a1332686 100644 --- a/src/nm-dbus-object.c +++ b/src/nm-dbus-object.c @@ -138,7 +138,7 @@ nm_dbus_object_unexport (NMDBusObject *self) _nm_dbus_manager_obj_unexport (self); - g_clear_pointer (&self->internal.path, g_free); + nm_clear_g_free (&self->internal.path); self->internal.export_version_id = 0; self->internal.is_unexporting = FALSE; diff --git a/src/nm-dhcp-config.c b/src/nm-dhcp-config.c new file mode 100644 index 00000000..3b9211df --- /dev/null +++ b/src/nm-dhcp-config.c @@ -0,0 +1,251 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2008 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-dhcp-config.h" + +#include "nm-dbus-interface.h" +#include "nm-utils.h" +#include "nm-dbus-object.h" +#include "nm-core-utils.h" + +/*****************************************************************************/ + +#define NM_TYPE_DHCP4_CONFIG (nm_dhcp4_config_get_type ()) +#define NM_DHCP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP4_CONFIG, NMDhcp4Config)) +#define NM_DHCP4_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP4_CONFIG, NMDhcp4ConfigClass)) +#define NM_IS_DHCP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP4_CONFIG)) +#define NM_IS_DHCP4_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP4_CONFIG)) +#define NM_DHCP4_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP4_CONFIG, NMDhcp4ConfigClass)) + +typedef struct _NMDhcp4Config NMDhcp4Config; +typedef struct _NMDhcp4ConfigClass NMDhcp4ConfigClass; + +static GType nm_dhcp4_config_get_type (void); + +#define NM_TYPE_DHCP6_CONFIG (nm_dhcp6_config_get_type ()) +#define NM_DHCP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP6_CONFIG, NMDhcp6Config)) +#define NM_DHCP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP6_CONFIG, NMDhcp6ConfigClass)) +#define NM_IS_DHCP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP6_CONFIG)) +#define NM_IS_DHCP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP6_CONFIG)) +#define NM_DHCP6_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP6_CONFIG, NMDhcp6ConfigClass)) + +typedef struct _NMDhcp6Config NMDhcp6Config; +typedef struct _NMDhcp6ConfigClass NMDhcp6ConfigClass; + +static GType nm_dhcp6_config_get_type (void); + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMDhcpConfig, + PROP_OPTIONS, +); + +typedef struct { + GVariant *options; +} NMDhcpConfigPrivate; + +struct _NMDhcpConfig { + NMDBusObject parent; + NMDhcpConfigPrivate _priv; +}; + +struct _NMDhcpConfigClass { + NMDBusObjectClass parent; +}; + +G_DEFINE_ABSTRACT_TYPE (NMDhcpConfig, nm_dhcp_config, NM_TYPE_DBUS_OBJECT) + +#define NM_DHCP_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDhcpConfig, NM_IS_DHCP_CONFIG) + +/*****************************************************************************/ + +void +nm_dhcp_config_set_options (NMDhcpConfig *self, + GHashTable *options) +{ + NMDhcpConfigPrivate *priv; + + g_return_if_fail (NM_IS_DHCP_CONFIG (self)); + g_return_if_fail (options); + + priv = NM_DHCP_CONFIG_GET_PRIVATE (self); + + nm_g_variant_unref (priv->options); + priv->options = g_variant_ref_sink (nm_utils_strdict_to_variant (options)); + _notify (self, PROP_OPTIONS); +} + +const char * +nm_dhcp_config_get_option (NMDhcpConfig *self, const char *key) +{ + NMDhcpConfigPrivate *priv; + const char *value; + + g_return_val_if_fail (NM_IS_DHCP_CONFIG (self), NULL); + g_return_val_if_fail (key, NULL); + + priv = NM_DHCP_CONFIG_GET_PRIVATE (self); + + if ( priv->options + && g_variant_lookup (priv->options, key, "&s", &value)) + return value; + else + return NULL; +} + +GVariant * +nm_dhcp_config_get_options (NMDhcpConfig *self) +{ + g_return_val_if_fail (NM_IS_DHCP_CONFIG (self), NULL); + + return NM_DHCP_CONFIG_GET_PRIVATE (self)->options; +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDhcpConfigPrivate *priv = NM_DHCP_CONFIG_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_OPTIONS: + g_value_set_variant (value, priv->options + ?: g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_dhcp_config_init (NMDhcpConfig *self) +{ +} + +NMDhcpConfig * +nm_dhcp_config_new (int addr_family) +{ + nm_assert_addr_family (addr_family); + + return g_object_new ( addr_family != AF_INET + ? NM_TYPE_DHCP6_CONFIG + : NM_TYPE_DHCP4_CONFIG, + NULL); +} + +static void +finalize (GObject *object) +{ + NMDhcpConfigPrivate *priv = NM_DHCP_CONFIG_GET_PRIVATE (object); + + nm_g_variant_unref (priv->options); + + G_OBJECT_CLASS (nm_dhcp_config_parent_class)->finalize (object); +} + +static void +nm_dhcp_config_class_init (NMDhcpConfigClass *config_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (config_class); + + object_class->get_property = get_property; + object_class->finalize = finalize; + + obj_properties[PROP_OPTIONS] = + g_param_spec_variant (NM_DHCP_CONFIG_OPTIONS, "", "", + G_VARIANT_TYPE ("a{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); +} + +/*****************************************************************************/ + +struct _NMDhcp4Config { + NMDhcpConfig parent; +}; + +struct _NMDhcp4ConfigClass { + NMDhcpConfigClass parent; +}; + +G_DEFINE_TYPE (NMDhcp4Config, nm_dhcp4_config, NM_TYPE_DHCP_CONFIG) + +static void +nm_dhcp4_config_init (NMDhcp4Config *self) +{ +} + +static const NMDBusInterfaceInfoExtended interface_info_dhcp4_config = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( + NM_DBUS_INTERFACE_DHCP4_CONFIG, + .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 ("Options", "a{sv}", NM_DHCP_CONFIG_OPTIONS), + ), + ), + .legacy_property_changed = TRUE, +}; + +static void +nm_dhcp4_config_class_init (NMDhcp4ConfigClass *klass) +{ + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + + dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/DHCP4Config"); + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_dhcp4_config); + dbus_object_class->export_on_construction = TRUE; +} + +/*****************************************************************************/ + +struct _NMDhcp6Config { + NMDhcpConfig parent; +}; + +struct _NMDhcp6ConfigClass { + NMDhcpConfigClass parent; +}; + +G_DEFINE_TYPE (NMDhcp6Config, nm_dhcp6_config, NM_TYPE_DHCP_CONFIG) + +static void +nm_dhcp6_config_init (NMDhcp6Config *self) +{ +} + +static const NMDBusInterfaceInfoExtended interface_info_dhcp6_config = { + .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( + NM_DBUS_INTERFACE_DHCP6_CONFIG, + .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 ("Options", "a{sv}", NM_DHCP_CONFIG_OPTIONS), + ), + ), + .legacy_property_changed = TRUE, +}; + +static void +nm_dhcp6_config_class_init (NMDhcp6ConfigClass *klass) +{ + NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); + + dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/DHCP6Config"); + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_dhcp6_config); + dbus_object_class->export_on_construction = TRUE; +} diff --git a/src/nm-dhcp-config.h b/src/nm-dhcp-config.h new file mode 100644 index 00000000..da192e77 --- /dev/null +++ b/src/nm-dhcp-config.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2008 Red Hat, Inc. + */ + +#ifndef __NM_DHCP_CONFIG_H__ +#define __NM_DHCP_CONFIG_H__ + +/*****************************************************************************/ + +#define NM_TYPE_DHCP_CONFIG (nm_dhcp_config_get_type ()) +#define NM_DHCP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_CONFIG, NMDhcpConfig)) +#define NM_DHCP_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_CONFIG, NMDhcpConfigClass)) +#define NM_IS_DHCP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP_CONFIG)) +#define NM_IS_DHCP_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP_CONFIG)) +#define NM_DHCP_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP_CONFIG, NMDhcpConfigClass)) + +#define NM_DHCP_CONFIG_OPTIONS "options" + +typedef struct _NMDhcpConfigClass NMDhcpConfigClass; + +GType nm_dhcp_config_get_type (void); + +NMDhcpConfig *nm_dhcp_config_new (int addr_family); + +int nm_dhcp_config_get_addr_family (NMDhcpConfig *self); + +void nm_dhcp_config_set_options (NMDhcpConfig *self, + GHashTable *options); + +const char *nm_dhcp_config_get_option (NMDhcpConfig *self, const char *option); + +GVariant *nm_dhcp_config_get_options (NMDhcpConfig *self); + +#endif /* __NM_DHCP_CONFIG_H__ */ diff --git a/src/nm-dhcp4-config.c b/src/nm-dhcp4-config.c deleted file mode 100644 index cdbe2071..00000000 --- a/src/nm-dhcp4-config.c +++ /dev/null @@ -1,158 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2008 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-dhcp4-config.h" - -#include "nm-dbus-interface.h" -#include "nm-utils.h" -#include "nm-dbus-object.h" -#include "nm-core-utils.h" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE (NMDhcp4Config, - PROP_OPTIONS, -); - -typedef struct { - GVariant *options; -} NMDhcp4ConfigPrivate; - -struct _NMDhcp4Config { - NMDBusObject parent; - NMDhcp4ConfigPrivate _priv; -}; - -struct _NMDhcp4ConfigClass { - NMDBusObjectClass parent; -}; - -G_DEFINE_TYPE (NMDhcp4Config, nm_dhcp4_config, NM_TYPE_DBUS_OBJECT) - -#define NM_DHCP4_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDhcp4Config, NM_IS_DHCP4_CONFIG) - -/*****************************************************************************/ - -void -nm_dhcp4_config_set_options (NMDhcp4Config *self, - GHashTable *options) -{ - NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (self); - GVariant *val; - - g_return_if_fail (NM_IS_DHCP4_CONFIG (self)); - g_return_if_fail (options); - - val = nm_utils_strdict_to_variant (options); - g_variant_unref (priv->options); - priv->options = g_variant_ref_sink (val); - _notify (self, PROP_OPTIONS); -} - -const char * -nm_dhcp4_config_get_option (NMDhcp4Config *self, const char *key) -{ - NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (self); - const char *value; - - g_return_val_if_fail (NM_IS_DHCP4_CONFIG (self), NULL); - g_return_val_if_fail (key != NULL, NULL); - - if (g_variant_lookup (priv->options, key, "&s", &value)) - return value; - else - return NULL; -} - -GVariant * -nm_dhcp4_config_get_options (NMDhcp4Config *self) -{ - g_return_val_if_fail (NM_IS_DHCP4_CONFIG (self), NULL); - - return g_variant_ref (NM_DHCP4_CONFIG_GET_PRIVATE (self)->options); -} - -/*****************************************************************************/ - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE ((NMDhcp4Config *) object); - - switch (prop_id) { - case PROP_OPTIONS: - g_value_set_variant (value, priv->options); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_dhcp4_config_init (NMDhcp4Config *self) -{ - NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (self); - - priv->options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0); - g_variant_ref_sink (priv->options); -} - -NMDhcp4Config * -nm_dhcp4_config_new (void) -{ - return NM_DHCP4_CONFIG (g_object_new (NM_TYPE_DHCP4_CONFIG, NULL)); -} - -static void -finalize (GObject *object) -{ - NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE ((NMDhcp4Config *) object); - - g_variant_unref (priv->options); - - G_OBJECT_CLASS (nm_dhcp4_config_parent_class)->finalize (object); -} - -static const NMDBusInterfaceInfoExtended interface_info_dhcp4_config = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DHCP4_CONFIG, - .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 ("Options", "a{sv}", NM_DHCP4_CONFIG_OPTIONS), - ), - ), - .legacy_property_changed = TRUE, -}; - -static void -nm_dhcp4_config_class_init (NMDhcp4ConfigClass *config_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (config_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (config_class); - - object_class->get_property = get_property; - object_class->finalize = finalize; - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/DHCP4Config"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_dhcp4_config); - dbus_object_class->export_on_construction = TRUE; - - obj_properties[PROP_OPTIONS] = - g_param_spec_variant (NM_DHCP4_CONFIG_OPTIONS, "", "", - G_VARIANT_TYPE ("a{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/nm-dhcp4-config.h b/src/nm-dhcp4-config.h deleted file mode 100644 index 3cad1e82..00000000 --- a/src/nm-dhcp4-config.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2008 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP4_CONFIG_H__ -#define __NETWORKMANAGER_DHCP4_CONFIG_H__ - -#define NM_TYPE_DHCP4_CONFIG (nm_dhcp4_config_get_type ()) -#define NM_DHCP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP4_CONFIG, NMDhcp4Config)) -#define NM_DHCP4_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP4_CONFIG, NMDhcp4ConfigClass)) -#define NM_IS_DHCP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP4_CONFIG)) -#define NM_IS_DHCP4_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP4_CONFIG)) -#define NM_DHCP4_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP4_CONFIG, NMDhcp4ConfigClass)) - -#define NM_DHCP4_CONFIG_OPTIONS "options" - -typedef struct _NMDhcp4ConfigClass NMDhcp4ConfigClass; - -GType nm_dhcp4_config_get_type (void); - -NMDhcp4Config *nm_dhcp4_config_new (void); - -void nm_dhcp4_config_set_options (NMDhcp4Config *config, - GHashTable *options); - -const char *nm_dhcp4_config_get_option (NMDhcp4Config *config, const char *option); - -GVariant *nm_dhcp4_config_get_options (NMDhcp4Config *config); - -#endif /* __NETWORKMANAGER_DHCP4_CONFIG_H__ */ diff --git a/src/nm-dhcp6-config.c b/src/nm-dhcp6-config.c deleted file mode 100644 index 676caa6d..00000000 --- a/src/nm-dhcp6-config.c +++ /dev/null @@ -1,156 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2008 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-dhcp6-config.h" - -#include "nm-dbus-interface.h" -#include "nm-utils.h" -#include "nm-dbus-object.h" -#include "nm-core-utils.h" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE (NMDhcp6Config, - PROP_OPTIONS, -); - -typedef struct { - GVariant *options; -} NMDhcp6ConfigPrivate; - -struct _NMDhcp6Config { - NMDBusObject parent; - NMDhcp6ConfigPrivate _priv; -}; - -struct _NMDhcp6ConfigClass { - NMDBusObjectClass parent; -}; - -G_DEFINE_TYPE (NMDhcp6Config, nm_dhcp6_config, NM_TYPE_DBUS_OBJECT) - -#define NM_DHCP6_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDhcp6Config, NM_IS_DHCP6_CONFIG) - -/*****************************************************************************/ - -void -nm_dhcp6_config_set_options (NMDhcp6Config *self, - GHashTable *options) -{ - NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (self); - GVariant *val; - - g_return_if_fail (NM_IS_DHCP6_CONFIG (self)); - g_return_if_fail (options); - - val = nm_utils_strdict_to_variant (options); - g_variant_unref (priv->options); - priv->options = g_variant_ref_sink (val); - _notify (self, PROP_OPTIONS); -} - -const char * -nm_dhcp6_config_get_option (NMDhcp6Config *self, const char *key) -{ - NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (self); - const char *value; - - g_return_val_if_fail (NM_IS_DHCP6_CONFIG (self), NULL); - g_return_val_if_fail (key != NULL, NULL); - - if (g_variant_lookup (priv->options, key, "&s", &value)) - return value; - else - return NULL; -} - -GVariant * -nm_dhcp6_config_get_options (NMDhcp6Config *self) -{ - g_return_val_if_fail (NM_IS_DHCP6_CONFIG (self), NULL); - - return g_variant_ref (NM_DHCP6_CONFIG_GET_PRIVATE (self)->options); -} - -/*****************************************************************************/ - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE ((NMDhcp6Config *) object); - - switch (prop_id) { - case PROP_OPTIONS: - g_value_set_variant (value, priv->options); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -nm_dhcp6_config_init (NMDhcp6Config *self) -{ - NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (self); - - priv->options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0); - g_variant_ref_sink (priv->options); -} - -NMDhcp6Config * -nm_dhcp6_config_new (void) -{ - return NM_DHCP6_CONFIG (g_object_new (NM_TYPE_DHCP6_CONFIG, NULL)); -} - -static void -finalize (GObject *object) -{ - NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE ((NMDhcp6Config *) object); - - g_variant_unref (priv->options); - - G_OBJECT_CLASS (nm_dhcp6_config_parent_class)->finalize (object); -} - -static const NMDBusInterfaceInfoExtended interface_info_dhcp6_config = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DHCP6_CONFIG, - .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 ("Options", "a{sv}", NM_DHCP6_CONFIG_OPTIONS), - ), - ), - .legacy_property_changed = TRUE, -}; - -static void -nm_dhcp6_config_class_init (NMDhcp6ConfigClass *config_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (config_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (config_class); - - object_class->get_property = get_property; - object_class->finalize = finalize; - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED (NM_DBUS_PATH"/DHCP6Config"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_dhcp6_config); - dbus_object_class->export_on_construction = TRUE; - - obj_properties[PROP_OPTIONS] = - g_param_spec_variant (NM_DHCP6_CONFIG_OPTIONS, "", "", - G_VARIANT_TYPE ("a{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/nm-dhcp6-config.h b/src/nm-dhcp6-config.h deleted file mode 100644 index e5697e04..00000000 --- a/src/nm-dhcp6-config.h +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2008 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP6_CONFIG_H__ -#define __NETWORKMANAGER_DHCP6_CONFIG_H__ - -#define NM_TYPE_DHCP6_CONFIG (nm_dhcp6_config_get_type ()) -#define NM_DHCP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP6_CONFIG, NMDhcp6Config)) -#define NM_DHCP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP6_CONFIG, NMDhcp6ConfigClass)) -#define NM_IS_DHCP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DHCP6_CONFIG)) -#define NM_IS_DHCP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DHCP6_CONFIG)) -#define NM_DHCP6_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP6_CONFIG, NMDhcp6ConfigClass)) - -#define NM_DHCP6_CONFIG_OPTIONS "options" - -typedef struct _NMDhcp6ConfigClass NMDhcp6ConfigClass; - -GType nm_dhcp6_config_get_type (void); - -NMDhcp6Config *nm_dhcp6_config_new (void); - -void nm_dhcp6_config_set_options (NMDhcp6Config *config, - GHashTable *options); - -const char *nm_dhcp6_config_get_option (NMDhcp6Config *config, const char *option); - -GVariant *nm_dhcp6_config_get_options (NMDhcp6Config *self); - -#endif /* __NETWORKMANAGER_DHCP6_CONFIG_H__ */ diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 54b0567b..e5584cd6 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -14,8 +14,7 @@ #include "nm-connectivity.h" #include "nm-act-request.h" #include "devices/nm-device.h" -#include "nm-dhcp4-config.h" -#include "nm-dhcp6-config.h" +#include "nm-dhcp-config.h" #include "nm-proxy-config.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -331,8 +330,7 @@ fill_device_props (NMDevice *device, NMProxyConfig *proxy_config; NMIP4Config *ip4_config; NMIP6Config *ip6_config; - NMDhcp4Config *dhcp4_config; - NMDhcp6Config *dhcp6_config; + NMDhcpConfig *dhcp_config; /* If the action is for a VPN, send the VPN's IP interface instead of the device's */ g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_IP_INTERFACE, @@ -360,13 +358,13 @@ fill_device_props (NMDevice *device, if (ip6_config) dump_ip6_to_props (ip6_config, ip6_builder); - dhcp4_config = nm_device_get_dhcp4_config (device); - if (dhcp4_config) - *dhcp4_props = nm_dhcp4_config_get_options (dhcp4_config); + dhcp_config = nm_device_get_dhcp_config (device, AF_INET); + if (dhcp_config) + *dhcp4_props = nm_g_variant_ref (nm_dhcp_config_get_options (dhcp_config)); - dhcp6_config = nm_device_get_dhcp6_config (device); - if (dhcp6_config) - *dhcp6_props = nm_dhcp6_config_get_options (dhcp6_config); + dhcp_config = nm_device_get_dhcp_config (device, AF_INET6); + if (dhcp_config) + *dhcp6_props = nm_g_variant_ref (nm_dhcp_config_get_options (dhcp_config)); } static void diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c index cf6494bd..304b15f9 100644 --- a/src/nm-firewall-manager.c +++ b/src/nm-firewall-manager.c @@ -265,7 +265,7 @@ _handle_dbus_cb (GObject *source, ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if ( !ret - && nm_utils_error_is_cancelled (error, FALSE)) + && nm_utils_error_is_cancelled (error)) return; call_id = user_data; diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index df70c71b..fdc0d4a4 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -448,7 +448,7 @@ main (int argc, char *argv[]) fprintf (stderr, _("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"), bad_domains); - g_clear_pointer (&bad_domains, g_free); + nm_clear_g_free (&bad_domains); } if (global_opt.become_daemon && !global_opt.debug) { @@ -596,7 +596,7 @@ main (int argc, char *argv[]) _LOGI (LOGD_CORE, "exiting"); nm_clear_g_source (&sd_id); - g_clear_pointer (&gl.main_loop, g_main_loop_unref); + nm_clear_pointer (&gl.main_loop, g_main_loop_unref); return 0; } diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index cd14fb8f..ae637aee 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -1097,8 +1097,8 @@ nm_ip4_config_create_setting (const NMIP4Config *self) && nm_setting_ip_config_get_num_addresses (s_ip4) > 0) { g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, - nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (priv->best_default_route)->gateway, - sbuf), + _nm_utils_inet4_ntop (NMP_OBJECT_CAST_IP4_ROUTE (priv->best_default_route)->gateway, + sbuf), NULL); } @@ -1133,7 +1133,7 @@ nm_ip4_config_create_setting (const NMIP4Config *self) for (i = 0; i < nnameservers; i++) { guint32 nameserver = nm_ip4_config_get_nameserver (self, i); - nm_setting_ip_config_add_dns (s_ip4, nm_utils_inet4_ntop (nameserver, sbuf)); + nm_setting_ip_config_add_dns (s_ip4, _nm_utils_inet4_ntop (nameserver, sbuf)); } for (i = 0; i < nsearches; i++) { const char *search = nm_ip4_config_get_search (self, i); @@ -3096,14 +3096,14 @@ get_property (GObject *object, guint prop_id, g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&addr_builder, "{sv}", "address", - g_variant_new_string (nm_utils_inet4_ntop (address->address, addr_str))); + g_variant_new_string (_nm_utils_inet4_ntop (address->address, addr_str))); g_variant_builder_add (&addr_builder, "{sv}", "prefix", g_variant_new_uint32 (address->plen)); if (address->peer_address != address->address) { g_variant_builder_add (&addr_builder, "{sv}", "peer", - g_variant_new_string (nm_utils_inet4_ntop (address->peer_address, addr_str))); + g_variant_new_string (_nm_utils_inet4_ntop (address->peer_address, addr_str))); } if (*address->label) { @@ -3158,14 +3158,14 @@ out_addresses_cached: g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&route_builder, "{sv}", "dest", - g_variant_new_string (nm_utils_inet4_ntop (route->network, addr_str))); + g_variant_new_string (_nm_utils_inet4_ntop (route->network, addr_str))); g_variant_builder_add (&route_builder, "{sv}", "prefix", g_variant_new_uint32 (route->plen)); if (route->gateway) { g_variant_builder_add (&route_builder, "{sv}", "next-hop", - g_variant_new_string (nm_utils_inet4_ntop (route->gateway, addr_str))); + g_variant_new_string (_nm_utils_inet4_ntop (route->gateway, addr_str))); } g_variant_builder_add (&route_builder, "{sv}", "metric", @@ -3218,8 +3218,8 @@ out_routes_cached: for (i = 0; i < priv->nameservers->len; i++) { GVariantBuilder nested_builder; - nm_utils_inet4_ntop (g_array_index (priv->nameservers, in_addr_t, i), - addr_str); + _nm_utils_inet4_ntop (g_array_index (priv->nameservers, in_addr_t, i), + addr_str); g_variant_builder_init (&nested_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&nested_builder, "{sv}", @@ -3255,8 +3255,8 @@ out_routes_cached: for (i = 0; i < priv->wins->len; i++) { g_variant_builder_add (&builder_data, "s", - nm_utils_inet4_ntop (g_array_index (priv->wins, in_addr_t, i), - addr_str)); + _nm_utils_inet4_ntop (g_array_index (priv->wins, in_addr_t, i), + addr_str)); } g_value_take_variant (value, g_variant_builder_end (&builder_data)); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 12553657..5acb3932 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -764,8 +764,8 @@ nm_ip6_config_create_setting (const NMIP6Config *self) && nm_setting_ip_config_get_num_addresses (s_ip6) > 0) { g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, - nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway, - sbuf), + _nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway, + sbuf), NULL); } @@ -807,7 +807,7 @@ nm_ip6_config_create_setting (const NMIP6Config *self) for (i = 0; i < nnameservers; i++) { const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (self, i); - nm_setting_ip_config_add_dns (s_ip6, nm_utils_inet6_ntop (nameserver, sbuf)); + nm_setting_ip_config_add_dns (s_ip6, _nm_utils_inet6_ntop (nameserver, sbuf)); } for (i = 0; i < nsearches; i++) { const char *search = nm_ip6_config_get_search (self, i); @@ -2556,7 +2556,7 @@ get_property (GObject *object, guint prop_id, g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&addr_builder, "{sv}", "address", - g_variant_new_string (nm_utils_inet6_ntop (&address->address, sbuf))); + g_variant_new_string (_nm_utils_inet6_ntop (&address->address, sbuf))); g_variant_builder_add (&addr_builder, "{sv}", "prefix", g_variant_new_uint32 (address->plen)); @@ -2564,7 +2564,7 @@ get_property (GObject *object, guint prop_id, && !IN6_ARE_ADDR_EQUAL (&address->peer_address, &address->address)) { g_variant_builder_add (&addr_builder, "{sv}", "peer", - g_variant_new_string (nm_utils_inet6_ntop (&address->peer_address, sbuf))); + g_variant_new_string (_nm_utils_inet6_ntop (&address->peer_address, sbuf))); } g_variant_builder_add (&builder_data, "a{sv}", &addr_builder); @@ -2609,14 +2609,14 @@ out_addresses_cached: g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&route_builder, "{sv}", "dest", - g_variant_new_string (nm_utils_inet6_ntop (&route->network, sbuf))); + g_variant_new_string (_nm_utils_inet6_ntop (&route->network, sbuf))); g_variant_builder_add (&route_builder, "{sv}", "prefix", g_variant_new_uint32 (route->plen)); if (!IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) { g_variant_builder_add (&route_builder, "{sv}", "next-hop", - g_variant_new_string (nm_utils_inet6_ntop (&route->gateway, sbuf))); + g_variant_new_string (_nm_utils_inet6_ntop (&route->gateway, sbuf))); } g_variant_builder_add (&route_builder, "{sv}", diff --git a/src/nm-logging.c b/src/nm-logging.c index 9221a6c8..3368c5db 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -390,7 +390,7 @@ nm_logging_setup (const char *level, } } - g_clear_pointer (&gl_main.logging_domains_to_string, g_free); + nm_clear_g_free (&gl_main.logging_domains_to_string); had_platform_debug = _nm_logging_enabled_lockfree (LOGL_DEBUG, LOGD_PLATFORM); @@ -735,7 +735,7 @@ _nm_log_impl (const char *file, char *s_log_domains; gsize l_log_domains; - now = nm_utils_get_monotonic_timestamp_ns (); + now = nm_utils_get_monotonic_timestamp_nsec (); boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1); _iovec_set_format_a (iov++, 30, "PRIORITY=%d", level_desc[level].syslog_level); @@ -766,8 +766,8 @@ _nm_log_impl (const char *file, _iovec_set_format (iov++, iov_free++, "CODE_FUNC=%s", func); _iovec_set_format (iov++, iov_free++, "CODE_FILE=%s", file ?: ""); _iovec_set_format_a (iov++, 20, "CODE_LINE=%u", line); - _iovec_set_format_a (iov++, 60, "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NS_PER_SECOND), (long long) ((now % NM_UTILS_NS_PER_SECOND) / 1000)); - _iovec_set_format_a (iov++, 60, "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NS_PER_SECOND), (long long) ((boottime % NM_UTILS_NS_PER_SECOND) / 1000)); + _iovec_set_format_a (iov++, 60, "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NSEC_PER_SEC), (long long) ((now % NM_UTILS_NSEC_PER_SEC) / 1000)); + _iovec_set_format_a (iov++, 60, "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NSEC_PER_SEC), (long long) ((boottime % NM_UTILS_NSEC_PER_SEC) / 1000)); if (error != 0) _iovec_set_format_a (iov++, 30, "ERRNO=%d", error); if (ifname) @@ -868,7 +868,7 @@ nm_log_handler (const char *log_domain, { gint64 now, boottime; - now = nm_utils_get_monotonic_timestamp_ns (); + now = nm_utils_get_monotonic_timestamp_nsec (); boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1); sd_journal_send ("PRIORITY=%d", syslog_priority, @@ -878,8 +878,8 @@ nm_log_handler (const char *log_domain, "SYSLOG_FACILITY=3", "GLIB_DOMAIN=%s", log_domain ?: "", "GLIB_LEVEL=%d", (int) (level & G_LOG_LEVEL_MASK), - "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NS_PER_SECOND), (long long) ((now % NM_UTILS_NS_PER_SECOND) / 1000), - "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NS_PER_SECOND), (long long) ((boottime % NM_UTILS_NS_PER_SECOND) / 1000), + "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NSEC_PER_SEC), (long long) ((now % NM_UTILS_NSEC_PER_SEC) / 1000), + "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NSEC_PER_SEC), (long long) ((boottime % NM_UTILS_NSEC_PER_SEC) / 1000), NULL); } break; @@ -999,7 +999,7 @@ nm_logging_init (const char *logging_backend, gboolean debug) if (fetch_monotonic_timestamp) { /* ensure we read a monotonic timestamp. Reading the timestamp the first * time causes a logging message. We don't want to do that during _nm_log_impl. */ - nm_utils_get_monotonic_timestamp_ns (); + nm_utils_get_monotonic_timestamp_nsec (); } if (obsolete_debug_backend) diff --git a/src/nm-manager.c b/src/nm-manager.c index d7b2211e..1f3ba1f6 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -383,7 +383,8 @@ static void _activation_auth_done (NMManager *self, /*****************************************************************************/ -static NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark) +static +NM_CACHED_QUARK_FCN ("autoconnect-root", autoconnect_root_quark) /*****************************************************************************/ @@ -2426,7 +2427,7 @@ device_auth_request_cb (NMDevice *device, char *permission_dup; /* Validate the caller */ - subject = nm_auth_subject_new_unix_process_from_context (context); + subject = nm_dbus_manager_new_auth_subject_from_context (context); if (!subject) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -4503,7 +4504,7 @@ unmanaged_to_disconnected (NMDevice *device) static NMActivationStateFlags _activation_bind_lifetime_to_profile_visibility (NMAuthSubject *subject) { - if ( nm_auth_subject_is_internal (subject) + if ( nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL || nm_auth_subject_get_unix_process_uid (subject) == 0) { /* internal requests and requests from root are always unbound. */ return NM_ACTIVATION_STATE_FLAG_NONE; @@ -5087,8 +5088,10 @@ nm_manager_activate_connection (NMManager *self, if ( sett_conn == nm_active_connection_get_settings_connection (active) && nm_streq0 (nm_active_connection_get_specific_object (active), specific_object) && (!device || nm_active_connection_get_device (active) == device) - && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) - && nm_auth_subject_is_internal (subject) + && nm_auth_subject_get_subject_type (nm_active_connection_get_subject (active)) + == NM_AUTH_SUBJECT_TYPE_INTERNAL + && nm_auth_subject_get_subject_type (subject) + == NM_AUTH_SUBJECT_TYPE_INTERNAL && nm_active_connection_get_activation_reason (active) == activation_reason) return active; } @@ -5163,7 +5166,7 @@ validate_activation_request (NMManager *self, connection = nm_settings_connection_get_connection (sett_conn); /* Validate the caller */ - subject = nm_auth_subject_new_unix_process_from_context (context); + subject = nm_dbus_manager_new_auth_subject_from_context (context); if (!subject) { g_set_error_literal (error, NM_MANAGER_ERROR, @@ -5306,9 +5309,9 @@ impl_manager_activate_connection (NMDBusObject *obj, g_variant_get (parameters, "(&o&o&o)", &connection_path, &device_path, &specific_object_path); - connection_path = nm_utils_dbus_normalize_object_path (connection_path); - specific_object_path = nm_utils_dbus_normalize_object_path (specific_object_path); - device_path = nm_utils_dbus_normalize_object_path (device_path); + connection_path = nm_dbus_path_not_empty (connection_path); + specific_object_path = nm_dbus_path_not_empty (specific_object_path); + device_path = nm_dbus_path_not_empty (device_path); /* If the connection path is given and valid, that connection is activated. * Otherwise the "best" connection for the device is chosen and activated, @@ -5596,8 +5599,8 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj, } } - specific_object_path = nm_utils_dbus_normalize_object_path (specific_object_path); - device_path = nm_utils_dbus_normalize_object_path (device_path); + specific_object_path = nm_dbus_path_not_empty (specific_object_path); + device_path = nm_dbus_path_not_empty (device_path); /* Try to create a new connection with the given settings. * We allow empty settings for AddAndActivateConnection(). In that case, @@ -5813,7 +5816,7 @@ impl_manager_deactivate_connection (NMDBusObject *obj, } /* Validate the caller */ - subject = nm_auth_subject_new_unix_process_from_context (invocation); + subject = nm_dbus_manager_new_auth_subject_from_context (invocation); if (!subject) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, @@ -6097,7 +6100,7 @@ impl_manager_sleep (NMDBusObject *obj, g_variant_get (parameters, "(b)", &do_sleep); - subject = nm_auth_subject_new_unix_process_from_context (invocation); + subject = nm_dbus_manager_new_auth_subject_from_context (invocation); if (priv->sleeping == do_sleep) { error = g_error_new (NM_MANAGER_ERROR, @@ -6231,29 +6234,12 @@ done: /* Permissions */ static void -get_perm_add_result (NMManager *self, NMAuthChain *chain, GVariantBuilder *results, const char *permission) -{ - NMAuthCallResult result; - - result = nm_auth_chain_get_result (chain, permission); - if (result == NM_AUTH_CALL_RESULT_YES) - g_variant_builder_add (results, "{ss}", permission, "yes"); - else if (result == NM_AUTH_CALL_RESULT_NO) - g_variant_builder_add (results, "{ss}", permission, "no"); - else if (result == NM_AUTH_CALL_RESULT_AUTH) - g_variant_builder_add (results, "{ss}", permission, "auth"); - else { - _LOGD (LOGD_CORE, "unknown auth chain result %d", result); - } -} - -static void get_permissions_done_cb (NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data) { - NMManager *self = NM_MANAGER (user_data); GVariantBuilder results; + int i; nm_assert (G_IS_DBUS_METHOD_INVOCATION (context)); @@ -6261,22 +6247,15 @@ get_permissions_done_cb (NMAuthChain *chain, g_variant_builder_init (&results, G_VARIANT_TYPE ("a{ss}")); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SLEEP_WAKE); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_NETWORK_CONTROL); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_RELOAD); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS); - get_perm_add_result (self, chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK); + for (i = 0; i < (int) G_N_ELEMENTS (nm_auth_permission_sorted); i++) { + const char *permission = nm_auth_permission_names_by_idx[nm_auth_permission_sorted[i] - 1]; + NMAuthCallResult result; + const char *result_str; + + result = nm_auth_chain_get_result (chain, permission); + result_str = nm_client_permission_result_to_string (nm_auth_call_result_to_client (result)); + g_variant_builder_add (&results, "{ss}", permission, result_str); + } g_dbus_method_invocation_return_value (context, g_variant_new ("(a{ss})", &results)); @@ -6294,6 +6273,7 @@ impl_manager_get_permissions (NMDBusObject *obj, NMManager *self = NM_MANAGER (obj); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMAuthChain *chain; + int i; chain = nm_auth_chain_new_context (invocation, get_permissions_done_cb, self); if (!chain) { @@ -6305,22 +6285,12 @@ impl_manager_get_permissions (NMDBusObject *obj, } c_list_link_tail (&priv->auth_lst_head, nm_auth_chain_parent_lst_list (chain)); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_RELOAD, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_STATISTICS, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_CONNECTIVITY_CHECK, FALSE); + + for (i = 0; i < (int) G_N_ELEMENTS (nm_auth_permission_sorted); i++) { + const char *permission = nm_auth_permission_names_by_idx[nm_auth_permission_sorted[i] - 1]; + + nm_auth_chain_add_call_unsafe (chain, permission, FALSE); + } } static void @@ -6544,7 +6514,7 @@ nm_manager_write_device_state (NMManager *self, NMDevice *device, int *out_ifind guint32 route_metric_default_aspired; guint32 route_metric_default_effective; int nm_owned; - NMDhcp4Config *dhcp4_config; + NMDhcpConfig *dhcp_config; const char *next_server = NULL; const char *root_path = NULL; @@ -6584,10 +6554,10 @@ nm_manager_write_device_state (NMManager *self, NMDevice *device, int *out_ifind route_metric_default_effective = _device_route_metric_get (self, ifindex, NM_DEVICE_TYPE_UNKNOWN, TRUE, &route_metric_default_aspired); - dhcp4_config = nm_device_get_dhcp4_config (device); - if (dhcp4_config) { - root_path = nm_dhcp4_config_get_option (dhcp4_config, "root_path"); - next_server = nm_dhcp4_config_get_option (dhcp4_config, "next_server"); + dhcp_config = nm_device_get_dhcp_config (device, AF_INET); + if (dhcp_config) { + root_path = nm_dhcp_config_get_option (dhcp_config, "root_path"); + next_server = nm_dhcp_config_get_option (dhcp_config, "next_server"); } if (!nm_config_device_state_write (ifindex, @@ -6965,7 +6935,7 @@ nm_manager_dbus_set_property_handle (NMDBusObject *obj, gs_unref_object NMAuthSubject *subject = NULL; DBusSetPropertyHandle *handle_data; - subject = nm_auth_subject_new_unix_process_from_context (invocation); + subject = nm_dbus_manager_new_auth_subject_from_context (invocation); if (!subject) { error_message = NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN; goto err; @@ -7761,7 +7731,7 @@ dispose (GObject *object) nm_clear_g_source (&priv->devices_inited_id); - g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_free); + nm_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_free); if (priv->concheck_mgr) { g_signal_handlers_disconnect_by_func (priv->concheck_mgr, @@ -7816,7 +7786,7 @@ dispose (GObject *object) g_clear_object (&priv->vpn_manager); sleep_devices_clear (self); - g_clear_pointer (&priv->sleep_devices, g_hash_table_unref); + nm_clear_pointer (&priv->sleep_devices, g_hash_table_unref); if (priv->sleep_monitor) { g_signal_handlers_disconnect_by_func (priv->sleep_monitor, sleeping_cb, self); @@ -7846,7 +7816,7 @@ dispose (GObject *object) nm_clear_g_source (&priv->timestamp_update_id); - g_clear_pointer (&priv->device_route_metrics, g_hash_table_destroy); + nm_clear_pointer (&priv->device_route_metrics, g_hash_table_destroy); G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object); } @@ -7854,7 +7824,7 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE ((NMManager *) object); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (object); g_array_free (priv->capabilities, TRUE); diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index b5c7bc02..0324ccaa 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -145,7 +145,7 @@ get_ip_domains (GPtrArray *domains, NMIPConfig *ip_config) nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, (NMIP4Config *) ip_config, &address) { cidr = g_strdup_printf ("%s/%u", - nm_utils_inet4_ntop (address->address, sbuf), + _nm_utils_inet4_ntop (address->address, sbuf), address->plen); g_ptr_array_add (domains, cidr); } @@ -154,7 +154,7 @@ get_ip_domains (GPtrArray *domains, NMIPConfig *ip_config) nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, (NMIP6Config *) ip_config, &address) { cidr = g_strdup_printf ("%s/%u", - nm_utils_inet6_ntop (&address->address, sbuf), + _nm_utils_inet6_ntop (&address->address, sbuf), address->plen); g_ptr_array_add (domains, cidr); } @@ -167,7 +167,7 @@ get_ip_domains (GPtrArray *domains, NMIPConfig *ip_config) if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes)) continue; cidr = g_strdup_printf ("%s/%u", - nm_utils_inet4_ntop (routes->network, sbuf), + _nm_utils_inet4_ntop (routes->network, sbuf), routes->plen); g_ptr_array_add (domains, cidr); } @@ -178,7 +178,7 @@ get_ip_domains (GPtrArray *domains, NMIPConfig *ip_config) if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes)) continue; cidr = g_strdup_printf ("%s/%u", - nm_utils_inet6_ntop (&routes->network, sbuf), + _nm_utils_inet6_ntop (&routes->network, sbuf), routes->plen); g_ptr_array_add (domains, cidr); } @@ -610,7 +610,7 @@ nm_pacrunner_manager_init (NMPacrunnerManager *self) static void dispose (GObject *object) { - NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE ((NMPacrunnerManager *) object); + NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE (object); nm_assert (c_list_is_empty (&priv->conf_id_lst_head)); diff --git a/src/nm-policy.c b/src/nm-policy.c index d322b2ef..2a9f6c05 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -29,8 +29,7 @@ #include "settings/nm-settings.h" #include "settings/nm-settings-connection.h" #include "settings/nm-agent-manager.h" -#include "nm-dhcp4-config.h" -#include "nm-dhcp6-config.h" +#include "nm-dhcp-config.h" #include "nm-config.h" #include "nm-netns.h" #include "nm-hostname-manager.h" @@ -184,7 +183,7 @@ clear_ip6_prefix_delegation (gpointer data) char sbuf[NM_UTILS_INET_ADDRSTRLEN]; _LOGD (LOGD_IP6, "ipv6-pd: undelegating prefix %s/%d", - nm_utils_inet6_ntop (&delegation->prefix.address, sbuf), + _nm_utils_inet6_ntop (&delegation->prefix.address, sbuf), delegation->prefix.plen); g_hash_table_foreach (delegation->subnets, _clear_ip6_subnet, NULL); @@ -195,7 +194,7 @@ static void expire_ip6_delegations (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - guint32 now = nm_utils_get_monotonic_timestamp_s (); + guint32 now = nm_utils_get_monotonic_timestamp_sec (); IP6PrefixDelegation *delegation = NULL; guint i; @@ -225,7 +224,7 @@ ip6_subnet_from_delegation (IP6PrefixDelegation *delegation, NMDevice *device) /* Check for out-of-prefixes condition. */ if (delegation->next_subnet >= (1 << (64 - delegation->prefix.plen))) { _LOGD (LOGD_IP6, "ipv6-pd: no more prefixes in %s/%d", - nm_utils_inet6_ntop (&delegation->prefix.address, sbuf), + _nm_utils_inet6_ntop (&delegation->prefix.address, sbuf), delegation->prefix.plen); return FALSE; } @@ -253,7 +252,7 @@ ip6_subnet_from_delegation (IP6PrefixDelegation *delegation, NMDevice *device) subnet->preferred = delegation->prefix.preferred; _LOGD (LOGD_IP6, "ipv6-pd: %s allocated from a /%d prefix on %s", - nm_utils_inet6_ntop (&subnet->address, sbuf), + _nm_utils_inet6_ntop (&subnet->address, sbuf), delegation->prefix.plen, nm_device_get_iface (device)); @@ -327,7 +326,7 @@ device_ip6_prefix_delegated (NMDevice *device, char sbuf[NM_UTILS_INET_ADDRSTRLEN]; _LOGI (LOGD_IP6, "ipv6-pd: received a prefix %s/%d from %s", - nm_utils_inet6_ntop (&prefix->address, sbuf), + _nm_utils_inet6_ntop (&prefix->address, sbuf), prefix->plen, nm_device_get_iface (device)); @@ -692,6 +691,7 @@ update_system_hostname (NMPolicy *self, const char *msg) const NMPlatformIP4Address *addr4; const NMPlatformIP6Address *addr6; NMDevice *device; + NMDhcpConfig *dhcp_config; g_return_if_fail (self != NULL); @@ -745,12 +745,10 @@ update_system_hostname (NMPolicy *self, const char *msg) } if (priv->default_ac4) { - NMDhcp4Config *dhcp4_config; - /* Grab a hostname out of the device's DHCP4 config */ - dhcp4_config = nm_device_get_dhcp4_config (get_default_device (self, AF_INET)); - if (dhcp4_config) { - dhcp_hostname = nm_dhcp4_config_get_option (dhcp4_config, "host_name"); + dhcp_config = nm_device_get_dhcp_config (get_default_device (self, AF_INET), AF_INET); + if (dhcp_config) { + dhcp_hostname = nm_dhcp_config_get_option (dhcp_config, "host_name"); if (dhcp_hostname && dhcp_hostname[0]) { p = nm_str_skip_leading_spaces (dhcp_hostname); if (p[0]) { @@ -765,12 +763,10 @@ update_system_hostname (NMPolicy *self, const char *msg) } if (priv->default_ac6) { - NMDhcp6Config *dhcp6_config; - /* Grab a hostname out of the device's DHCP6 config */ - dhcp6_config = nm_device_get_dhcp6_config (get_default_device (self, AF_INET6)); - if (dhcp6_config) { - dhcp_hostname = nm_dhcp6_config_get_option (dhcp6_config, "host_name"); + dhcp_config = nm_device_get_dhcp_config (get_default_device (self, AF_INET6), AF_INET6); + if (dhcp_config) { + dhcp_hostname = nm_dhcp_config_get_option (dhcp_config, "host_name"); if (dhcp_hostname && dhcp_hostname[0]) { p = nm_str_skip_leading_spaces (dhcp_hostname); if (p[0]) { @@ -1007,21 +1003,6 @@ update_ip4_routing (NMPolicy *self, gboolean force_update) } static void -update_ip6_dns_delegation (NMPolicy *self) -{ - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - NMDevice *device; - NMActiveConnection *ac; - const CList *tmp_list; - - nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { - device = nm_active_connection_get_device (ac); - if (device && nm_device_needs_ip6_subnet (device)) - nm_device_copy_ip6_dns_config (device, get_default_device (self, AF_INET6)); - } -} - -static void update_ip6_prefix_delegation (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); @@ -1089,8 +1070,9 @@ update_ip6_routing (NMPolicy *self, gboolean force_update) } static void -update_ip_dns (NMPolicy *self, int addr_family) +update_ip_dns (NMPolicy *self, int addr_family, NMDevice *changed_device) { + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); gpointer ip_config; const char *ip_iface = NULL; NMVpnConnection *vpn = NULL; @@ -1105,25 +1087,39 @@ update_ip_dns (NMPolicy *self, int addr_family) */ _dns_manager_set_ip_config (NM_POLICY_GET_PRIVATE (self)->dns_manager, ip_config, - vpn + ( vpn + || (device && nm_device_is_vpn (device))) ? NM_DNS_IP_CONFIG_TYPE_VPN : NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE, device); } - if (addr_family == AF_INET6) - update_ip6_dns_delegation (self); + if (addr_family == AF_INET6) { + NMActiveConnection *ac; + const CList *tmp_list; + + /* Tell devices needing a subnet about the new DNS configuration */ + nm_manager_for_each_active_connection (priv->manager, ac, tmp_list) { + device = nm_active_connection_get_device (ac); + if ( device + && device != changed_device + && nm_device_needs_ip6_subnet (device)) + nm_device_copy_ip6_dns_config (device, get_default_device (self, AF_INET6)); + } + } } static void -update_routing_and_dns (NMPolicy *self, gboolean force_update) +update_routing_and_dns (NMPolicy *self, + gboolean force_update, + NMDevice *changed_device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); nm_dns_manager_begin_updates (priv->dns_manager, __func__); - update_ip_dns (self, AF_INET); - update_ip_dns (self, AF_INET6); + update_ip_dns (self, AF_INET, changed_device); + update_ip_dns (self, AF_INET6, changed_device); update_ip4_routing (self, force_update); update_ip6_routing (self, force_update); @@ -1549,7 +1545,7 @@ reset_connections_retries (gpointer user_data) priv->reset_retries_id = 0; min_stamp = 0; - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); connections = nm_settings_get_connections (priv->settings, NULL); for (i = 0; connections[i]; i++) { NMSettingsConnection *connection = connections[i]; @@ -1594,7 +1590,7 @@ _connection_autoconnect_retries_set (NMPolicy *self, gint32 retry_time = nm_settings_connection_autoconnect_retries_blocked_until (connection); g_warn_if_fail (retry_time != 0); - priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_s ()), reset_connections_retries, self); + priv->reset_retries_id = g_timeout_add_seconds (MAX (0, retry_time - nm_utils_get_monotonic_timestamp_sec ()), reset_connections_retries, self); } } } @@ -1633,7 +1629,8 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) } subject = nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)); - internal_activation = subject && nm_auth_subject_is_internal (subject); + internal_activation = subject + && (nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL); } changed = FALSE; @@ -1857,14 +1854,14 @@ device_state_changed (NMDevice *device, if (ip6_config) _dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_DEFAULT, device); - update_routing_and_dns (self, FALSE); + update_routing_and_dns (self, FALSE, device); nm_dns_manager_end_updates (priv->dns_manager, __func__); break; case NM_DEVICE_STATE_UNMANAGED: case NM_DEVICE_STATE_UNAVAILABLE: if (old_state > NM_DEVICE_STATE_DISCONNECTED) - update_routing_and_dns (self, FALSE); + update_routing_and_dns (self, FALSE, device); break; case NM_DEVICE_STATE_DEACTIVATING: if (sett_conn) { @@ -1899,7 +1896,7 @@ device_state_changed (NMDevice *device, reset_autoconnect_all (self, device, FALSE); if (old_state > NM_DEVICE_STATE_DISCONNECTED) - update_routing_and_dns (self, FALSE); + update_routing_and_dns (self, FALSE, device); /* Device is now available for auto-activation */ schedule_activate_check (self, device); @@ -1930,7 +1927,7 @@ device_state_changed (NMDevice *device, if ( s_con && nm_setting_connection_get_num_secondaries (s_con) > 0) { /* Make routes and DNS up-to-date before activating dependent connections */ - update_routing_and_dns (self, FALSE); + update_routing_and_dns (self, FALSE, device); /* Activate secondary (VPN) connections */ if (!activate_secondary_connections (self, @@ -1986,7 +1983,7 @@ device_ip_config_changed (NMDevice *device, if (old_config) nm_dns_manager_set_ip_config (priv->dns_manager, old_config, NM_DNS_IP_CONFIG_TYPE_REMOVED); } - update_ip_dns (self, addr_family); + update_ip_dns (self, addr_family, device); if (addr_family == AF_INET) update_ip4_routing (self, TRUE); else @@ -2108,7 +2105,7 @@ vpn_connection_activated (NMPolicy *self, NMVpnConnection *vpn) if (ip6_config) nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_VPN); - update_routing_and_dns (self, TRUE); + update_routing_and_dns (self, TRUE, NULL); nm_dns_manager_end_updates (priv->dns_manager, __func__); } @@ -2130,7 +2127,7 @@ vpn_connection_deactivated (NMPolicy *self, NMVpnConnection *vpn) if (ip6_config) nm_dns_manager_set_ip_config (priv->dns_manager, NM_IP_CONFIG_CAST (ip6_config), NM_DNS_IP_CONFIG_TYPE_REMOVED); - update_routing_and_dns (self, TRUE); + update_routing_and_dns (self, TRUE, NULL); nm_dns_manager_end_updates (priv->dns_manager, __func__); } @@ -2498,7 +2495,8 @@ nm_policy_get_activating_ip6_ac (NMPolicy *self) /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_hostname_mode_to_string, NMPolicyHostnameMode, +static +NM_UTILS_LOOKUP_STR_DEFINE (_hostname_mode_to_string, NMPolicyHostnameMode, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), NM_UTILS_LOOKUP_STR_ITEM (NM_POLICY_HOSTNAME_MODE_NONE, "none"), NM_UTILS_LOOKUP_STR_ITEM (NM_POLICY_HOSTNAME_MODE_DHCP, "dhcp"), @@ -2670,7 +2668,7 @@ dispose (GObject *object) nm_clear_g_object (&priv->default_ac6); nm_clear_g_object (&priv->activating_ac4); nm_clear_g_object (&priv->activating_ac6); - g_clear_pointer (&priv->pending_active_connections, g_hash_table_unref); + nm_clear_pointer (&priv->pending_active_connections, g_hash_table_unref); c_list_for_each_entry_safe (data, data_safe, &priv->pending_activation_checks, pending_lst) activate_data_free (data); @@ -2708,9 +2706,9 @@ dispose (GObject *object) nm_clear_g_source (&priv->reset_retries_id); nm_clear_g_source (&priv->schedule_activate_all_id); - g_clear_pointer (&priv->orig_hostname, g_free); - g_clear_pointer (&priv->cur_hostname, g_free); - g_clear_pointer (&priv->last_hostname, g_free); + nm_clear_g_free (&priv->orig_hostname); + nm_clear_g_free (&priv->cur_hostname); + nm_clear_g_free (&priv->last_hostname); if (priv->hostname_manager) { g_signal_handlers_disconnect_by_data (priv->hostname_manager, priv); diff --git a/src/nm-proxy-config.c b/src/nm-proxy-config.c index feee4afe..06bb89ba 100644 --- a/src/nm-proxy-config.c +++ b/src/nm-proxy-config.c @@ -65,7 +65,7 @@ nm_proxy_config_merge_setting (NMProxyConfig *config, NMSettingProxy *setting) priv = NM_PROXY_CONFIG_GET_PRIVATE (config); - g_clear_pointer (&priv->pac_script, g_free); + nm_clear_g_free (&priv->pac_script); method = nm_setting_proxy_get_method (setting); switch (method) { diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c index 5d5fe4c9..6fdc57eb 100644 --- a/src/nm-session-monitor.c +++ b/src/nm-session-monitor.c @@ -48,7 +48,7 @@ struct _NMSessionMonitor { #if SESSION_TRACKING_XLOGIND struct { sd_login_monitor *monitor; - guint watch; + GSource *watch; } sd; #endif @@ -90,7 +90,9 @@ st_sd_session_exists (NMSessionMonitor *monitor, uid_t uid, gboolean active) } static gboolean -st_sd_changed (GIOChannel *stream, GIOCondition condition, gpointer user_data) +st_sd_changed (int fd, + GIOCondition condition, + gpointer user_data) { NMSessionMonitor *monitor = user_data; @@ -98,14 +100,13 @@ st_sd_changed (GIOChannel *stream, GIOCondition condition, gpointer user_data) sd_login_monitor_flush (monitor->sd.monitor); - return TRUE; + return G_SOURCE_CONTINUE; } static void st_sd_init (NMSessionMonitor *monitor) { int status; - GIOChannel *stream; if (!g_file_test ("/run/systemd/seats/", G_FILE_TEST_EXISTS)) return; @@ -115,10 +116,13 @@ st_sd_init (NMSessionMonitor *monitor) return; } - stream = g_io_channel_unix_new (sd_login_monitor_get_fd (monitor->sd.monitor)); - monitor->sd.watch = g_io_add_watch (stream, G_IO_IN, st_sd_changed, monitor); - - g_io_channel_unref (stream); + monitor->sd.watch = nm_g_unix_fd_source_new (sd_login_monitor_get_fd (monitor->sd.monitor), + G_IO_IN, + G_PRIORITY_DEFAULT, + st_sd_changed, + monitor, + NULL); + g_source_attach (monitor->sd.watch, NULL); } static void @@ -128,7 +132,7 @@ st_sd_finalize (NMSessionMonitor *monitor) sd_login_monitor_unref (monitor->sd.monitor); monitor->sd.monitor = NULL; } - nm_clear_g_source (&monitor->sd.watch); + nm_clear_g_source_inst (&monitor->sd.watch); } #endif /* SESSION_TRACKING_XLOGIND */ @@ -181,8 +185,8 @@ out: if (error) _LOGE ("failed to load ConsoleKit database: %s", error->message); g_clear_error (&error); - g_clear_pointer (&groups, g_strfreev); - g_clear_pointer (&keyfile, g_key_file_free); + nm_clear_pointer (&groups, g_strfreev); + nm_clear_pointer (&keyfile, g_key_file_free); return finished; } @@ -267,7 +271,7 @@ ck_init (NMSessionMonitor *monitor) static void ck_finalize (NMSessionMonitor *monitor) { - g_clear_pointer (&monitor->ck.cache, g_hash_table_unref); + nm_clear_pointer (&monitor->ck.cache, g_hash_table_unref); g_clear_object (&monitor->ck.monitor); } #endif /* SESSION_TRACKING_CONSOLEKIT */ diff --git a/src/nm-test-utils-core.h b/src/nm-test-utils-core.h index e1d250dd..d984c6c0 100644 --- a/src/nm-test-utils-core.h +++ b/src/nm-test-utils-core.h @@ -7,7 +7,7 @@ #define __NM_TEST_UTILS_CORE_H__ #include "NetworkManagerUtils.h" -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" #define _NMTST_INSIDE_CORE 1 diff --git a/src/nm-types.h b/src/nm-types.h index 2f1ac2dc..4db9a19b 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -24,8 +24,7 @@ typedef struct _NMConfig NMConfig; typedef struct _NMConfigData NMConfigData; typedef struct _NMConnectivity NMConnectivity; typedef struct _NMDevice NMDevice; -typedef struct _NMDhcp4Config NMDhcp4Config; -typedef struct _NMDhcp6Config NMDhcp6Config; +typedef struct _NMDhcpConfig NMDhcpConfig; typedef struct _NMProxyConfig NMProxyConfig; typedef struct _NMIPConfig NMIPConfig; typedef struct _NMIP4Config NMIP4Config; @@ -43,6 +42,8 @@ typedef struct _NMConfigDeviceStateData NMConfigDeviceStateData; struct _NMDedupMultiIndex; +typedef struct _NMRefString NMRefString; + /*****************************************************************************/ typedef enum { @@ -116,20 +117,18 @@ typedef struct _NMPNetns NMPNetns; typedef struct _NMPObject NMPObject; typedef enum { - /* Please don't interpret type numbers outside nm-platform and use functions - * like nm_platform_link_is_software() and nm_platform_supports_slaves(). - * - * type & 0x10000 -> Software device type - * type & 0x20000 -> Type supports slaves - */ /* No type, used as error value */ NM_LINK_TYPE_NONE, - /* Unknown type */ NM_LINK_TYPE_UNKNOWN, + NM_LINK_TYPE_ANY, + +#define _NM_LINK_TYPE_REAL_FIRST NM_LINK_TYPE_ETHERNET + /* Hardware types */ +#define _NM_LINK_TYPE_HW_FIRST NM_LINK_TYPE_ETHERNET NM_LINK_TYPE_ETHERNET, NM_LINK_TYPE_INFINIBAND, NM_LINK_TYPE_OLPC_MESH, @@ -139,9 +138,11 @@ typedef enum { NM_LINK_TYPE_WPAN, NM_LINK_TYPE_6LOWPAN, NM_LINK_TYPE_WIFI_P2P, +#define _NM_LINK_TYPE_HW_LAST NM_LINK_TYPE_WIFI_P2P /* Software types */ - NM_LINK_TYPE_BNEP = 0x10000, /* Bluetooth Ethernet emulation */ +#define _NM_LINK_TYPE_SW_FIRST NM_LINK_TYPE_BNEP + NM_LINK_TYPE_BNEP, /* Bluetooth Ethernet emulation */ NM_LINK_TYPE_DUMMY, NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP, @@ -160,17 +161,40 @@ typedef enum { NM_LINK_TYPE_TUN, NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, + NM_LINK_TYPE_VRF, NM_LINK_TYPE_VXLAN, NM_LINK_TYPE_WIREGUARD, +#define _NM_LINK_TYPE_SW_LAST NM_LINK_TYPE_WIREGUARD /* Software types with slaves */ - NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000, +#define _NM_LINK_TYPE_SW_MASTER_FIRST NM_LINK_TYPE_BRIDGE + NM_LINK_TYPE_BRIDGE, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM, +#define _NM_LINK_TYPE_SW_MASTER_LAST NM_LINK_TYPE_TEAM + +#define _NM_LINK_TYPE_REAL_LAST NM_LINK_TYPE_TEAM + +#define _NM_LINK_TYPE_REAL_NUM ((int) (_NM_LINK_TYPE_REAL_LAST - _NM_LINK_TYPE_REAL_FIRST + 1)) - NM_LINK_TYPE_ANY = G_MAXUINT32, } NMLinkType; +static inline gboolean +nm_link_type_is_software (NMLinkType link_type) +{ + G_STATIC_ASSERT (_NM_LINK_TYPE_SW_LAST + 1 == _NM_LINK_TYPE_SW_MASTER_FIRST); + + return link_type >= _NM_LINK_TYPE_SW_FIRST + && link_type <= _NM_LINK_TYPE_SW_MASTER_LAST; +} + +static inline gboolean +nm_link_type_supports_slaves (NMLinkType link_type) +{ + return link_type >= _NM_LINK_TYPE_SW_MASTER_FIRST + && link_type <= _NM_LINK_TYPE_SW_MASTER_LAST; +} + typedef enum { NMP_OBJECT_TYPE_UNKNOWN, NMP_OBJECT_TYPE_LINK, @@ -197,6 +221,7 @@ typedef enum { NMP_OBJECT_TYPE_LNK_SIT, NMP_OBJECT_TYPE_LNK_TUN, NMP_OBJECT_TYPE_LNK_VLAN, + NMP_OBJECT_TYPE_LNK_VRF, NMP_OBJECT_TYPE_LNK_VXLAN, NMP_OBJECT_TYPE_LNK_WIREGUARD, diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 6aae808a..4a81dc49 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -46,7 +46,7 @@ struct _NMFakePlatformClass { G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM) -#define NM_FAKE_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMFakePlatform, NM_IS_FAKE_PLATFORM) +#define NM_FAKE_PLATFORM_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMFakePlatform, NM_IS_FAKE_PLATFORM, NMPlatform) /*****************************************************************************/ @@ -126,7 +126,7 @@ static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in static gboolean sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value) { - NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); ASSERT_SYSCTL_ARGS (pathid, dirfd, path); @@ -138,7 +138,7 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat static char * sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *path) { - NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); const char *v; ASSERT_SYSCTL_ARGS (pathid, dirfd, path); @@ -155,7 +155,7 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat static NMFakePlatformLink * link_get (NMPlatform *platform, int ifindex) { - NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink *device; int idx; @@ -223,7 +223,7 @@ link_add_pre (NMPlatform *platform, const void *address, size_t address_len) { - NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink *device; int ifindex; NMPObject *o; @@ -276,11 +276,12 @@ link_add_pre (NMPlatform *platform, static int link_add (NMPlatform *platform, - const char *name, NMLinkType type, - const char *veth_peer, + const char *name, + int parent, const void *address, size_t address_len, + gconstpointer extra_data, const NMPlatformLink **out_link) { NMFakePlatformLink *device; @@ -291,14 +292,52 @@ link_add (NMPlatform *platform, nm_auto_nmpobj const NMPObject *obj_new_veth = NULL; NMPCacheOpsType cache_op; NMPCacheOpsType cache_op_veth = NMP_CACHE_OPS_UNCHANGED; + const char *veth_peer = NULL; + NMPObject *dev_obj; + NMPObject *dev_lnk = NULL; device = link_add_pre (platform, name, type, address, address_len); - if (veth_peer) { - g_assert (type == NM_LINK_TYPE_VETH); + g_assert (device); + + dev_obj = (NMPObject *) device->obj; + + if (parent > 0) + dev_obj->link.parent = parent; + else + g_assert (parent == 0); + + g_assert ((parent != 0) == NM_IN_SET (type, NM_LINK_TYPE_VLAN)); + + switch (type) { + case NM_LINK_TYPE_VETH: + veth_peer = extra_data; + g_assert (veth_peer); device_veth = link_add_pre (platform, veth_peer, type, NULL, 0); - } else - g_assert (type != NM_LINK_TYPE_VETH); + break; + case NM_LINK_TYPE_VLAN: { + const NMPlatformLnkVlan *props = extra_data; + + g_assert (props); + + dev_lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, props); + break; + } + case NM_LINK_TYPE_VXLAN: { + const NMPlatformLnkVxlan *props = extra_data; + + g_assert (props); + + dev_lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, props); + break; + } + default: + g_assert (!extra_data); + break; + } + + if (dev_lnk) + dev_obj->_link.netlink.lnk = dev_lnk; link_add_prepare (platform, device, (NMPObject *) device->obj); cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform), @@ -381,7 +420,7 @@ link_delete (NMPlatform *platform, int ifindex) return FALSE; obj_old = g_steal_pointer (&device->obj); - g_clear_pointer (&device->udi, g_free); + nm_clear_g_free (&device->udi); cache_op = nmp_cache_remove (nm_platform_get_cache (platform), obj_old, @@ -710,45 +749,6 @@ link_release (NMPlatform *platform, int master_idx, int slave_idx) return TRUE; } -struct vlan_add_data { - guint32 vlan_flags; - int parent; - int vlan_id; -}; - -static void -_vlan_add_prepare (NMPlatform *platform, - NMFakePlatformLink *device, - gconstpointer user_data) -{ - const struct vlan_add_data *d = user_data; - NMPObject *obj_tmp; - NMPObject *lnk; - - obj_tmp = (NMPObject *) device->obj; - - lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL); - lnk->lnk_vlan.id = d->vlan_id; - lnk->lnk_vlan.flags = d->vlan_flags; - - obj_tmp->link.parent = d->parent; - obj_tmp->_link.netlink.lnk = lnk; -} - -static gboolean -vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, const NMPlatformLink **out_link) -{ - const struct vlan_add_data d = { - .parent = parent, - .vlan_id = vlan_id, - .vlan_flags = vlan_flags, - }; - - link_add_one (platform, name, NM_LINK_TYPE_VLAN, - _vlan_add_prepare, &d, out_link); - return TRUE; -} - static gboolean link_vlan_change (NMPlatform *platform, int ifindex, @@ -764,35 +764,6 @@ link_vlan_change (NMPlatform *platform, return FALSE; } -static void -_vxlan_add_prepare (NMPlatform *platform, - NMFakePlatformLink *device, - gconstpointer user_data) -{ - const NMPlatformLnkVxlan *props = user_data; - NMPObject *obj_tmp; - NMPObject *lnk; - - obj_tmp = (NMPObject *) device->obj; - - lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL); - lnk->lnk_vxlan = *props; - - obj_tmp->link.parent = props->parent_ifindex; - obj_tmp->_link.netlink.lnk = lnk; -} - -static gboolean -link_vxlan_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkVxlan *props, - const NMPlatformLink **out_link) -{ - link_add_one (platform, name, NM_LINK_TYPE_VXLAN, - _vxlan_add_prepare, props, out_link); - return TRUE; -} - struct infiniband_add_data { int parent; int p_key; @@ -967,6 +938,7 @@ ip4_address_add (NMPlatform *platform, in_addr_t addr, guint8 plen, in_addr_t peer_addr, + in_addr_t broadcast_address, guint32 lifetime, guint32 preferred, guint32 flags, @@ -974,16 +946,19 @@ ip4_address_add (NMPlatform *platform, { NMPlatformIP4Address address; - memset (&address, 0, sizeof (address)); - address.addr_source = NM_IP_CONFIG_SOURCE_KERNEL; - address.ifindex = ifindex; - address.address = addr; - address.peer_address = peer_addr; - address.plen = plen; - address.timestamp = nm_utils_get_monotonic_timestamp_s (); - address.lifetime = lifetime; - address.preferred = preferred; - address.n_ifa_flags = flags; + address = (NMPlatformIP4Address) { + .addr_source = NM_IP_CONFIG_SOURCE_KERNEL, + .ifindex = ifindex, + .address = addr, + .plen = plen, + .peer_address = peer_addr, + .broadcast_address = broadcast_address, + .use_ip4_broadcast_address = TRUE, + .timestamp = nm_utils_get_monotonic_timestamp_sec (), + .lifetime = lifetime, + .preferred = preferred, + .n_ifa_flags = flags, + }; if (label) g_strlcpy (address.label, label, sizeof (address.label)); @@ -1008,7 +983,7 @@ ip6_address_add (NMPlatform *platform, address.address = addr; address.peer_address = (IN6_IS_ADDR_UNSPECIFIED (&peer_addr) || IN6_ARE_ADDR_EQUAL (&addr, &peer_addr)) ? in6addr_any : peer_addr; address.plen = plen; - address.timestamp = nm_utils_get_monotonic_timestamp_s (); + address.timestamp = nm_utils_get_monotonic_timestamp_sec (); address.lifetime = lifetime; address.preferred = preferred; address.n_ifa_flags = flags; @@ -1262,10 +1237,10 @@ ip_route_add (NMPlatform *platform, if (addr_family == AF_INET) { nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable", - r->ifindex, nm_utils_inet4_ntop (r4->network, sbuf), r->plen, r->metric); + r->ifindex, _nm_utils_inet4_ntop (r4->network, sbuf), r->plen, r->metric); } else { nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable", - r->ifindex, nm_utils_inet6_ntop (&r6->network, sbuf), r->plen, r->metric); + r->ifindex, _nm_utils_inet6_ntop (&r6->network, sbuf), r->plen, r->metric); } return -NME_UNSPEC; } @@ -1354,19 +1329,16 @@ nm_fake_platform_setup (void) nm_platform_setup (platform); - /* add loopback interface */ - link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, NULL, 0, NULL); - - /* add some ethernets */ - link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, NULL, 0, NULL); - link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, NULL, 0, NULL); - link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, NULL, 0, NULL); + link_add (platform, NM_LINK_TYPE_LOOPBACK, "lo", 0, NULL, 0, NULL, NULL); + link_add (platform, NM_LINK_TYPE_ETHERNET, "eth0", 0, NULL, 0, NULL, NULL); + link_add (platform, NM_LINK_TYPE_ETHERNET, "eth1", 0, NULL, 0, NULL, NULL); + link_add (platform, NM_LINK_TYPE_ETHERNET, "eth2", 0, NULL, 0, NULL, NULL); } static void finalize (GObject *object) { - NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) object); + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (object); int i; g_hash_table_unref (priv->options); @@ -1374,7 +1346,7 @@ finalize (GObject *object) NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); g_free (device->udi); - g_clear_pointer (&device->obj, nmp_object_unref); + nm_clear_pointer (&device->obj, nmp_object_unref); } g_array_unref (priv->links); @@ -1418,9 +1390,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; - platform_class->vlan_add = vlan_add; platform_class->link_vlan_change = link_vlan_change; - platform_class->link_vxlan_add = link_vxlan_add; platform_class->infiniband_partition_add = infiniband_partition_add; platform_class->infiniband_partition_delete = infiniband_partition_delete; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 7abe4dfc..f7249bb7 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -418,13 +418,14 @@ typedef struct { struct nl_sock *genl; struct nl_sock *nlh; + + GSource *event_source; + guint32 nlh_seq_next; #if NM_MORE_LOGGING guint32 nlh_seq_last_handled; #endif guint32 nlh_seq_last_seen; - GIOChannel *event_channel; - guint event_id; guint32 pruning[_REFRESH_ALL_TYPE_NUM]; @@ -603,7 +604,7 @@ _vlan_qos_mapping_cmp_from_ptr (gconstpointer a, gconstpointer b, gpointer user_ ******************************************************************/ typedef struct { - const NMLinkType nm_type; + const char *type_string; /* IFLA_INFO_KIND / rtnl_link_get_type() where applicable; the rtnl type @@ -623,68 +624,202 @@ typedef struct { const char *devtype; } LinkDesc; -static const LinkDesc linktypes[] = { - { NM_LINK_TYPE_NONE, "none", NULL, NULL }, - { NM_LINK_TYPE_UNKNOWN, "unknown", NULL, NULL }, - - { NM_LINK_TYPE_ETHERNET, "ethernet", NULL, NULL }, - { NM_LINK_TYPE_INFINIBAND, "infiniband", NULL, NULL }, - { NM_LINK_TYPE_OLPC_MESH, "olpc-mesh", NULL, NULL }, - { NM_LINK_TYPE_WIFI, "wifi", NULL, "wlan" }, - { NM_LINK_TYPE_WWAN_NET, "wwan", NULL, "wwan" }, - { NM_LINK_TYPE_WIMAX, "wimax", "wimax", "wimax" }, - { NM_LINK_TYPE_WPAN, "wpan", NULL, NULL }, - { NM_LINK_TYPE_6LOWPAN, "6lowpan", NULL, NULL }, - - { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" }, - { NM_LINK_TYPE_DUMMY, "dummy", "dummy", NULL }, - { NM_LINK_TYPE_GRE, "gre", "gre", NULL }, - { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL }, - { NM_LINK_TYPE_IFB, "ifb", "ifb", NULL }, - { NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL }, - { NM_LINK_TYPE_IP6GRE, "ip6gre", "ip6gre", NULL }, - { NM_LINK_TYPE_IP6GRETAP, "ip6gretap", "ip6gretap", NULL }, - { NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL }, - { NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL }, - { NM_LINK_TYPE_MACSEC, "macsec", "macsec", NULL }, - { NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL }, - { NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL }, - { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL }, - { NM_LINK_TYPE_PPP, "ppp", NULL, "ppp" }, - { NM_LINK_TYPE_SIT, "sit", "sit", NULL }, - { NM_LINK_TYPE_TUN, "tun", "tun", NULL }, - { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, - { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, - { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, - { NM_LINK_TYPE_WIREGUARD, "wireguard", "wireguard", "wireguard" }, - - { NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" }, - { NM_LINK_TYPE_BOND, "bond", "bond", "bond" }, - { NM_LINK_TYPE_TEAM, "team", "team", NULL }, +static const LinkDesc link_descs[] = { + [NM_LINK_TYPE_NONE] = { "none", NULL, NULL }, + [NM_LINK_TYPE_UNKNOWN] = { "unknown", NULL, NULL }, + [NM_LINK_TYPE_ANY] = { "any", NULL, NULL }, + + [NM_LINK_TYPE_ETHERNET] = { "ethernet", NULL, NULL }, + [NM_LINK_TYPE_INFINIBAND] = { "infiniband", NULL, NULL }, + [NM_LINK_TYPE_OLPC_MESH] = { "olpc-mesh", NULL, NULL }, + [NM_LINK_TYPE_WIFI] = { "wifi", NULL, "wlan" }, + [NM_LINK_TYPE_WWAN_NET] = { "wwan", NULL, "wwan" }, + [NM_LINK_TYPE_WIMAX] = { "wimax", "wimax", "wimax" }, + [NM_LINK_TYPE_WPAN] = { "wpan", NULL, NULL }, + [NM_LINK_TYPE_6LOWPAN] = { "6lowpan", NULL, NULL }, + + [NM_LINK_TYPE_BNEP] = { "bluetooth", NULL, "bluetooth" }, + [NM_LINK_TYPE_DUMMY] = { "dummy", "dummy", NULL }, + [NM_LINK_TYPE_GRE] = { "gre", "gre", NULL }, + [NM_LINK_TYPE_GRETAP] = { "gretap", "gretap", NULL }, + [NM_LINK_TYPE_IFB] = { "ifb", "ifb", NULL }, + [NM_LINK_TYPE_IP6TNL] = { "ip6tnl", "ip6tnl", NULL }, + [NM_LINK_TYPE_IP6GRE] = { "ip6gre", "ip6gre", NULL }, + [NM_LINK_TYPE_IP6GRETAP] = { "ip6gretap", "ip6gretap", NULL }, + [NM_LINK_TYPE_IPIP] = { "ipip", "ipip", NULL }, + [NM_LINK_TYPE_LOOPBACK] = { "loopback", NULL, NULL }, + [NM_LINK_TYPE_MACSEC] = { "macsec", "macsec", NULL }, + [NM_LINK_TYPE_MACVLAN] = { "macvlan", "macvlan", NULL }, + [NM_LINK_TYPE_MACVTAP] = { "macvtap", "macvtap", NULL }, + [NM_LINK_TYPE_OPENVSWITCH] = { "openvswitch", "openvswitch", NULL }, + [NM_LINK_TYPE_PPP] = { "ppp", NULL, "ppp" }, + [NM_LINK_TYPE_SIT] = { "sit", "sit", NULL }, + [NM_LINK_TYPE_TUN] = { "tun", "tun", NULL }, + [NM_LINK_TYPE_VETH] = { "veth", "veth", NULL }, + [NM_LINK_TYPE_VLAN] = { "vlan", "vlan", "vlan" }, + [NM_LINK_TYPE_VRF] = { "vrf", "vrf", "vrf" }, + [NM_LINK_TYPE_VXLAN] = { "vxlan", "vxlan", "vxlan" }, + [NM_LINK_TYPE_WIREGUARD] = { "wireguard", "wireguard", "wireguard" }, + + [NM_LINK_TYPE_BRIDGE] = { "bridge", "bridge", "bridge" }, + [NM_LINK_TYPE_BOND] = { "bond", "bond", "bond" }, + [NM_LINK_TYPE_TEAM] = { "team", "team", NULL }, }; -static const char * -nm_link_type_to_rtnl_type_string (NMLinkType type) +static const LinkDesc * +_link_desc_from_link_type (NMLinkType link_type) { - int i; + nm_assert (_NM_INT_NOT_NEGATIVE (link_type)); + nm_assert (link_type < G_N_ELEMENTS (link_descs)); + nm_assert (link_descs[link_type].type_string); - for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (type == linktypes[i].nm_type) - return linktypes[i].rtnl_type; + return &link_descs[link_type]; +} + +static NMLinkType +_link_type_from_rtnl_type (const char *name) \ +{ + static const NMLinkType LIST[] = { + NM_LINK_TYPE_BOND, /* "bond" */ + NM_LINK_TYPE_BRIDGE, /* "bridge" */ + NM_LINK_TYPE_DUMMY, /* "dummy" */ + NM_LINK_TYPE_GRE, /* "gre" */ + NM_LINK_TYPE_GRETAP, /* "gretap" */ + NM_LINK_TYPE_IFB, /* "ifb" */ + NM_LINK_TYPE_IP6GRE, /* "ip6gre" */ + NM_LINK_TYPE_IP6GRETAP, /* "ip6gretap" */ + NM_LINK_TYPE_IP6TNL, /* "ip6tnl" */ + NM_LINK_TYPE_IPIP, /* "ipip" */ + NM_LINK_TYPE_MACSEC, /* "macsec" */ + NM_LINK_TYPE_MACVLAN, /* "macvlan" */ + NM_LINK_TYPE_MACVTAP, /* "macvtap" */ + NM_LINK_TYPE_OPENVSWITCH, /* "openvswitch" */ + NM_LINK_TYPE_SIT, /* "sit" */ + NM_LINK_TYPE_TEAM, /* "team" */ + NM_LINK_TYPE_TUN, /* "tun" */ + NM_LINK_TYPE_VETH, /* "veth" */ + NM_LINK_TYPE_VLAN, /* "vlan" */ + NM_LINK_TYPE_VRF, /* "vrf" */ + NM_LINK_TYPE_VXLAN, /* "vxlan" */ + NM_LINK_TYPE_WIMAX, /* "wimax" */ + NM_LINK_TYPE_WIREGUARD, /* "wireguard" */ + }; + + nm_assert (name); + + if (NM_MORE_ASSERT_ONCE (5)) { + int i, j, k; + + for (i = 0; i < G_N_ELEMENTS (LIST); i++) { + nm_assert (_link_desc_from_link_type (LIST[i]) == &link_descs[LIST[i]]); + nm_assert (link_descs[LIST[i]].rtnl_type); + if (i > 0) + nm_assert (strcmp (link_descs[LIST[i - 1]].rtnl_type, link_descs[LIST[i]].rtnl_type) < 0); + } + for (i = 0; i < G_N_ELEMENTS (link_descs); i++) { + if (!link_descs[i].rtnl_type) + continue; + for (j = 0, k = 0; j < G_N_ELEMENTS (LIST); j++) + k += (LIST[j] == i); + nm_assert (k == 1); + } + } + + { + unsigned imin = 0; + unsigned imax = (G_N_ELEMENTS (LIST) - 1); + unsigned imid = (G_N_ELEMENTS (LIST) - 1) / 2; + + for (;;) { + const int cmp = strcmp (link_descs[LIST[imid]].rtnl_type, name); + + if (G_UNLIKELY (cmp == 0)) + return LIST[imid]; + + if (cmp < 0) + imin = imid + 1u; + else + imax = imid - 1u; + + if (G_UNLIKELY (imin > imax)) + return NM_LINK_TYPE_NONE; + + imid = (imin + imax) / 2u; + } } - g_return_val_if_reached (NULL); } -const char * -nm_link_type_to_string (NMLinkType type) -{ - int i; +static NMLinkType +_link_type_from_devtype (const char *name) \ +{ + static const NMLinkType LIST[] = { + NM_LINK_TYPE_BNEP, /* "bluetooth" */ + NM_LINK_TYPE_BOND, /* "bond" */ + NM_LINK_TYPE_BRIDGE, /* "bridge" */ + NM_LINK_TYPE_PPP, /* "ppp" */ + NM_LINK_TYPE_VLAN, /* "vlan" */ + NM_LINK_TYPE_VRF, /* "vrf" */ + NM_LINK_TYPE_VXLAN, /* "vxlan" */ + NM_LINK_TYPE_WIMAX, /* "wimax" */ + NM_LINK_TYPE_WIREGUARD, /* "wireguard" */ + NM_LINK_TYPE_WIFI, /* "wlan" */ + NM_LINK_TYPE_WWAN_NET, /* "wwan" */ + }; + + nm_assert (name); - for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (type == linktypes[i].nm_type) - return linktypes[i].type_string; + if (NM_MORE_ASSERT_ONCE (5)) { + int i, j, k; + + for (i = 0; i < G_N_ELEMENTS (LIST); i++) { + nm_assert (_link_desc_from_link_type (LIST[i]) == &link_descs[LIST[i]]); + nm_assert (link_descs[LIST[i]].devtype); + if (i > 0) + nm_assert (strcmp (link_descs[LIST[i - 1]].devtype, link_descs[LIST[i]].devtype) < 0); + } + for (i = 0; i < G_N_ELEMENTS (link_descs); i++) { + if (!link_descs[i].devtype) + continue; + for (j = 0, k = 0; j < G_N_ELEMENTS (LIST); j++) + k += (LIST[j] == i); + nm_assert (k == 1); + } } - g_return_val_if_reached (NULL); + + { + unsigned imin = 0; + unsigned imax = (G_N_ELEMENTS (LIST) - 1); + unsigned imid = (G_N_ELEMENTS (LIST) - 1) / 2; + + for (;;) { + const int cmp = strcmp (link_descs[LIST[imid]].devtype, name); + + if (G_UNLIKELY (cmp == 0)) + return LIST[imid]; + + if (cmp < 0) + imin = imid + 1u; + else + imax = imid - 1u; + + if (G_UNLIKELY (imin > imax)) + return NM_LINK_TYPE_NONE; + + imid = (imin + imax) / 2u; + } + } +} + +static const char * +nm_link_type_to_rtnl_type_string (NMLinkType link_type) +{ + return _link_desc_from_link_type (link_type)->rtnl_type; +} + +const char * +nm_link_type_to_string (NMLinkType link_type) +{ + return _link_desc_from_link_type (link_type)->type_string; } /****************************************************************** @@ -738,8 +873,8 @@ _addrtime_timestamp_to_nm (guint32 timestamp, gint32 *out_now_nm) /* do all the calculations in milliseconds scale */ - now_nm = nm_utils_get_monotonic_timestamp_ms (); - now_nl = nm_utils_clock_gettime_ms (CLOCK_MONOTONIC); + now_nm = nm_utils_get_monotonic_timestamp_msec (); + now_nl = nm_utils_clock_gettime_msec (CLOCK_MONOTONIC); nm_assert (now_nm >= 1000); nm_assert (now_nl >= 0); @@ -748,13 +883,13 @@ _addrtime_timestamp_to_nm (guint32 timestamp, gint32 *out_now_nm) NM_SET_OUT (out_now_nm, now_nm / 1000); - /* converting the timestamp into nm_utils_get_monotonic_timestamp_ms() scale is + /* converting the timestamp into nm_utils_get_monotonic_timestamp_msec() scale is * a good guess but fails in the following situations: * * - If the address existed before start of the process, the timestamp in nm scale would * be negative or zero. In this case we default to 1. * - during hibernation, the CLOCK_MONOTONIC/timestamp drifts from - * nm_utils_get_monotonic_timestamp_ms() scale. + * nm_utils_get_monotonic_timestamp_msec() scale. */ if (result <= 1000) return 1; @@ -809,7 +944,7 @@ _addrtime_get_lifetimes (guint32 timestamp, if (now == 0) { /* strange. failed to detect the last-update time and assumed that timestamp is 1. */ nm_assert (timestamp == 1); - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); } if (timestamp < now) { guint32 diff = now - timestamp; @@ -894,10 +1029,12 @@ _linktype_get_type (NMPlatform *platform, const NMPObject **link_cached, const char **out_kind) { - guint i; + NMLinkType link_type; NMTST_ASSERT_PLATFORM_NETNS_CURRENT (platform); nm_assert (ifname); + nm_assert (_link_type_from_devtype ("wlan") == NM_LINK_TYPE_WIFI); + nm_assert (_link_type_from_rtnl_type ("bond") == NM_LINK_TYPE_BOND); if (completed_from_cache) { const NMPObject *obj; @@ -905,7 +1042,7 @@ _linktype_get_type (NMPlatform *platform, obj = _lookup_cached_link (cache, ifindex, completed_from_cache, link_cached); /* If we detected the link type before, we stick to that - * decision unless the "kind" no "name" changed. If "name" changed, + * decision unless the "kind" or "name" changed. If "name" changed, * it means that their type may not have been determined correctly * due to race conditions while accessing sysfs. * @@ -936,11 +1073,9 @@ _linktype_get_type (NMPlatform *platform, *out_kind = g_intern_string (kind); if (kind) { - for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (nm_streq0 (kind, linktypes[i].rtnl_type)) { - return linktypes[i].nm_type; - } - } + link_type = _link_type_from_rtnl_type (kind); + if (link_type != NM_LINK_TYPE_NONE) + return link_type; } if (arptype == ARPHRD_LOOPBACK) @@ -987,16 +1122,16 @@ _linktype_get_type (NMPlatform *platform, return NM_LINK_TYPE_OLPC_MESH; devtype = _linktype_read_devtype (dirfd); - for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) { - if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) { - if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) { + if (devtype) { + link_type = _link_type_from_devtype (devtype); + if (link_type != NM_LINK_TYPE_NONE) { + if ( link_type == NM_LINK_TYPE_BNEP + && arptype != ARPHRD_ETHER) { /* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must * use arptype to distinguish between them. */ - if (arptype != ARPHRD_ETHER) - continue; - } - return linktypes[i].nm_type; + } else + return link_type; } } @@ -1022,13 +1157,14 @@ _linktype_get_type (NMPlatform *platform, */ if (!kind && !devtype) return NM_LINK_TYPE_ETHERNET; + /* The USB gadget interfaces behave and look like ordinary ethernet devices * aside from the DEVTYPE. */ - if (!g_strcmp0 (devtype, "gadget")) + if (nm_streq0 (devtype, "gadget")) return NM_LINK_TYPE_ETHERNET; /* Distributed Switch Architecture switch chips */ - if (!g_strcmp0 (devtype, "dsa")) + if (nm_streq0 (devtype, "dsa")) return NM_LINK_TYPE_ETHERNET; } } @@ -1753,6 +1889,8 @@ _parse_lnk_vlan (const char *kind, struct nlattr *info_data) #undef IFLA_VXLAN_MAX #define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6 +#define IFLA_VRF_TABLE 1 + /* older kernel header might not contain 'struct ifla_vxlan_port_range'. * Redefine it. */ struct nm_ifla_vxlan_port_range { @@ -1847,6 +1985,33 @@ _parse_lnk_vxlan (const char *kind, struct nlattr *info_data) return obj; } +static NMPObject * +_parse_lnk_vrf (const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[] = { + [IFLA_VRF_TABLE] = { .type = NLA_U32 }, + }; + NMPlatformLnkVrf *props; + struct nlattr *tb[G_N_ELEMENTS (policy)]; + NMPObject *obj; + + if ( !info_data + || !nm_streq0 (kind, "vrf")) + return NULL; + + if (nla_parse_nested_arr (tb, info_data, policy) < 0) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VRF, NULL); + + props = &obj->lnk_vrf; + + if (tb[IFLA_VRF_TABLE]) + props->table = nla_get_u32 (tb[IFLA_VRF_TABLE]); + + return obj; +} + /*****************************************************************************/ static gboolean @@ -2797,6 +2962,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_VLAN: lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_VRF: + lnk_data = _parse_lnk_vrf (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_VXLAN: lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data); break; @@ -2978,6 +3146,12 @@ _new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) memcpy (&obj->ip4_address.address, nla_data (tb[IFA_LOCAL]), addr_len); if (tb[IFA_ADDRESS]) memcpy (&obj->ip4_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len); + + _check_addr_or_return_null (tb, IFA_BROADCAST, addr_len); + obj->ip4_address.broadcast_address = tb[IFA_BROADCAST] + ? nla_get_u32 (tb[IFA_BROADCAST]) + : 0u; + obj->ip4_address.use_ip4_broadcast_address = TRUE; } else { /* For IPv6, IFA_ADDRESS is always present. * @@ -3689,13 +3863,13 @@ nla_put_failure: static gboolean _nl_msg_new_link_set_linkinfo (struct nl_msg *msg, NMLinkType link_type, - const char *veth_peer) + gconstpointer extra_data) { struct nlattr *info; + struct nlattr *data = NULL; const char *kind; nm_assert (msg); - nm_assert (!!veth_peer == (link_type == NM_LINK_TYPE_VETH)); kind = nm_link_type_to_rtnl_type_string (link_type); if (!kind) @@ -3706,9 +3880,89 @@ _nl_msg_new_link_set_linkinfo (struct nl_msg *msg, NLA_PUT_STRING (msg, IFLA_INFO_KIND, kind); - if (veth_peer) { + switch (link_type) { + case NM_LINK_TYPE_VLAN: { + const NMPlatformLnkVlan *props = extra_data; + + nm_assert (extra_data); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + NLA_PUT_U16 (msg, IFLA_VLAN_ID, props->id); + + { + struct ifla_vlan_flags flags = { + .flags = props->flags & NM_VLAN_FLAGS_ALL, + .mask = NM_VLAN_FLAGS_ALL, + }; + + NLA_PUT (msg, IFLA_VLAN_FLAGS, sizeof (flags), &flags); + } + break; + } + case NM_LINK_TYPE_VRF: { + const NMPlatformLnkVrf *props = extra_data; + + nm_assert (extra_data); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + NLA_PUT_U32 (msg, IFLA_VRF_TABLE, props->table); + break; + } + case NM_LINK_TYPE_VXLAN: { + const NMPlatformLnkVxlan *props = extra_data; + + nm_assert (extra_data); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + NLA_PUT_U32 (msg, IFLA_VXLAN_ID, props->id); + + if (props->group) + NLA_PUT (msg, IFLA_VXLAN_GROUP, sizeof (props->group), &props->group); + else if (!IN6_IS_ADDR_UNSPECIFIED (&props->group6)) + NLA_PUT (msg, IFLA_VXLAN_GROUP6, sizeof (props->group6), &props->group6); + + if (props->local) + NLA_PUT (msg, IFLA_VXLAN_LOCAL, sizeof (props->local), &props->local); + else if (!IN6_IS_ADDR_UNSPECIFIED (&props->local6)) + NLA_PUT (msg, IFLA_VXLAN_LOCAL6, sizeof (props->local6), &props->local6); + + if (props->parent_ifindex >= 0) + NLA_PUT_U32 (msg, IFLA_VXLAN_LINK, props->parent_ifindex); + + if ( props->src_port_min + || props->src_port_max) { + struct nm_ifla_vxlan_port_range port_range = { + .low = htons (props->src_port_min), + .high = htons (props->src_port_max), + }; + + NLA_PUT (msg, IFLA_VXLAN_PORT_RANGE, sizeof (port_range), &port_range); + } + + NLA_PUT_U16 (msg, IFLA_VXLAN_PORT, htons (props->dst_port)); + NLA_PUT_U8 (msg, IFLA_VXLAN_TOS, props->tos); + NLA_PUT_U8 (msg, IFLA_VXLAN_TTL, props->ttl); + NLA_PUT_U32 (msg, IFLA_VXLAN_AGEING, props->ageing); + NLA_PUT_U32 (msg, IFLA_VXLAN_LIMIT, props->limit); + NLA_PUT_U8 (msg, IFLA_VXLAN_LEARNING, !!props->learning); + NLA_PUT_U8 (msg, IFLA_VXLAN_PROXY, !!props->proxy); + NLA_PUT_U8 (msg, IFLA_VXLAN_RSC, !!props->rsc); + NLA_PUT_U8 (msg, IFLA_VXLAN_L2MISS, !!props->l2miss); + NLA_PUT_U8 (msg, IFLA_VXLAN_L3MISS, !!props->l3miss); + break; + } + case NM_LINK_TYPE_VETH: { + const char *veth_peer = extra_data; const struct ifinfomsg ifi = { }; - struct nlattr *data, *info_peer; + struct nlattr *info_peer; + + nm_assert (veth_peer); if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) goto nla_put_failure; @@ -3718,8 +3972,174 @@ _nl_msg_new_link_set_linkinfo (struct nl_msg *msg, goto nla_put_failure; NLA_PUT_STRING (msg, IFLA_IFNAME, veth_peer); nla_nest_end (msg, info_peer); - nla_nest_end (msg, data); + break; + } + case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_GRETAP: { + const NMPlatformLnkGre *props = extra_data; + + nm_assert (props); + nm_assert (props->is_tap == (link_type == NM_LINK_TYPE_GRETAP)); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (msg, IFLA_GRE_LINK, props->parent_ifindex); + NLA_PUT_U32 (msg, IFLA_GRE_LOCAL, props->local); + NLA_PUT_U32 (msg, IFLA_GRE_REMOTE, props->remote); + NLA_PUT_U8 (msg, IFLA_GRE_TTL, props->ttl); + NLA_PUT_U8 (msg, IFLA_GRE_TOS, props->tos); + NLA_PUT_U8 (msg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery); + NLA_PUT_U32 (msg, IFLA_GRE_IKEY, htonl (props->input_key)); + NLA_PUT_U32 (msg, IFLA_GRE_OKEY, htonl (props->output_key)); + NLA_PUT_U16 (msg, IFLA_GRE_IFLAGS, htons (props->input_flags)); + NLA_PUT_U16 (msg, IFLA_GRE_OFLAGS, htons (props->output_flags)); + break; + } + case NM_LINK_TYPE_SIT: { + const NMPlatformLnkSit *props = extra_data; + + nm_assert (props); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (msg, IFLA_IPTUN_LINK, props->parent_ifindex); + NLA_PUT_U32 (msg, IFLA_IPTUN_LOCAL, props->local); + NLA_PUT_U32 (msg, IFLA_IPTUN_REMOTE, props->remote); + NLA_PUT_U8 (msg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (msg, IFLA_IPTUN_TOS, props->tos); + NLA_PUT_U8 (msg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); + break; + } + case NM_LINK_TYPE_IP6TNL: { + const NMPlatformLnkIp6Tnl *props = extra_data; + guint32 flowinfo; + + nm_assert (props); + nm_assert (!props->is_gre); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (msg, IFLA_IPTUN_LINK, props->parent_ifindex); + + if (!IN6_IS_ADDR_UNSPECIFIED (&props->local)) + NLA_PUT (msg, IFLA_IPTUN_LOCAL, sizeof (props->local), &props->local); + if (!IN6_IS_ADDR_UNSPECIFIED (&props->remote)) + NLA_PUT (msg, IFLA_IPTUN_REMOTE, sizeof (props->remote), &props->remote); + + NLA_PUT_U8 (msg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (msg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit); + + flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; + flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) + & IP6_FLOWINFO_TCLASS_MASK; + NLA_PUT_U32 (msg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo)); + NLA_PUT_U8 (msg, IFLA_IPTUN_PROTO, props->proto); + NLA_PUT_U32 (msg, IFLA_IPTUN_FLAGS, props->flags); + break; + } + case NM_LINK_TYPE_IP6GRE: + case NM_LINK_TYPE_IP6GRETAP: { + const NMPlatformLnkIp6Tnl *props = extra_data; + guint32 flowinfo; + + nm_assert (props); + nm_assert (props->is_gre); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (msg, IFLA_GRE_LINK, props->parent_ifindex); + + NLA_PUT_U32 (msg, IFLA_GRE_IKEY, htonl (props->input_key)); + NLA_PUT_U32 (msg, IFLA_GRE_OKEY, htonl (props->output_key)); + NLA_PUT_U16 (msg, IFLA_GRE_IFLAGS, htons (props->input_flags)); + NLA_PUT_U16 (msg, IFLA_GRE_OFLAGS, htons (props->output_flags)); + + if (!IN6_IS_ADDR_UNSPECIFIED (&props->local)) + NLA_PUT (msg, IFLA_GRE_LOCAL, sizeof (props->local), &props->local); + if (!IN6_IS_ADDR_UNSPECIFIED (&props->local)) + NLA_PUT (msg, IFLA_GRE_REMOTE, sizeof (props->remote), &props->remote); + + NLA_PUT_U8 (msg, IFLA_GRE_TTL, props->ttl); + NLA_PUT_U8 (msg, IFLA_GRE_ENCAP_LIMIT, props->encap_limit); + + flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; + flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) + & IP6_FLOWINFO_TCLASS_MASK; + NLA_PUT_U32 (msg, IFLA_GRE_FLOWINFO, htonl (flowinfo)); + NLA_PUT_U32 (msg, IFLA_GRE_FLAGS, props->flags); + break; + } + case NM_LINK_TYPE_IPIP: { + const NMPlatformLnkIpIp *props = extra_data; + + nm_assert (props); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (msg, IFLA_IPTUN_LINK, props->parent_ifindex); + NLA_PUT_U32 (msg, IFLA_IPTUN_LOCAL, props->local); + NLA_PUT_U32 (msg, IFLA_IPTUN_REMOTE, props->remote); + NLA_PUT_U8 (msg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (msg, IFLA_IPTUN_TOS, props->tos); + NLA_PUT_U8 (msg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); + break; + } + case NM_LINK_TYPE_MACSEC: { + const NMPlatformLnkMacsec *props = extra_data; + + nm_assert (props); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->icv_length) + NLA_PUT_U8 (msg, IFLA_MACSEC_ICV_LEN, 16); + if (props->cipher_suite) + NLA_PUT_U64 (msg, IFLA_MACSEC_CIPHER_SUITE, props->cipher_suite); + if (props->replay_protect) + NLA_PUT_U32 (msg, IFLA_MACSEC_WINDOW, props->window); + + NLA_PUT_U64 (msg, IFLA_MACSEC_SCI, htobe64 (props->sci)); + NLA_PUT_U8 (msg, IFLA_MACSEC_ENCODING_SA, props->encoding_sa); + NLA_PUT_U8 (msg, IFLA_MACSEC_ENCRYPT, props->encrypt); + NLA_PUT_U8 (msg, IFLA_MACSEC_PROTECT, props->protect); + NLA_PUT_U8 (msg, IFLA_MACSEC_INC_SCI, props->include_sci); + NLA_PUT_U8 (msg, IFLA_MACSEC_ES, props->es); + NLA_PUT_U8 (msg, IFLA_MACSEC_SCB, props->scb); + NLA_PUT_U8 (msg, IFLA_MACSEC_REPLAY_PROTECT, props->replay_protect); + NLA_PUT_U8 (msg, IFLA_MACSEC_VALIDATION, props->validation); + break; + }; + case NM_LINK_TYPE_MACVTAP: + case NM_LINK_TYPE_MACVLAN: { + const NMPlatformLnkMacvlan *props = extra_data; + + nm_assert (props); + + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + NLA_PUT_U32 (msg, IFLA_MACVLAN_MODE, props->mode); + NLA_PUT_U16 (msg, IFLA_MACVLAN_FLAGS, props->no_promisc ? MACVLAN_FLAG_NOPROMISC : 0); + break; } + default: + nm_assert (!extra_data); + break; + } + + if (data) + nla_nest_end (msg, data); nla_nest_end (msg, info); @@ -3743,6 +4163,11 @@ _nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, guint i; gboolean has_any_vlan_properties = FALSE; + G_STATIC_ASSERT (NM_VLAN_FLAG_REORDER_HEADERS == (guint32) VLAN_FLAG_REORDER_HDR); + G_STATIC_ASSERT (NM_VLAN_FLAG_GVRP == (guint32) VLAN_FLAG_GVRP); + G_STATIC_ASSERT (NM_VLAN_FLAG_LOOSE_BINDING == (guint32) VLAN_FLAG_LOOSE_BINDING); + G_STATIC_ASSERT (NM_VLAN_FLAG_MVRP == (guint32) VLAN_FLAG_MVRP); + #define VLAN_XGRESS_PRIO_VALID(from) (((from) & ~(guint32) 0x07) == 0) nm_assert (msg); @@ -3892,6 +4317,7 @@ _nl_msg_new_address (int nlmsg_type, int scope, guint32 lifetime, guint32 preferred, + in_addr_t ip4_broadcast_address, const char *label) { nm_auto_nlmsg struct nl_msg *msg = NULL; @@ -3935,16 +4361,8 @@ _nl_msg_new_address (int nlmsg_type, if (label && label[0]) NLA_PUT_STRING (msg, IFA_LABEL, label); - if ( family == AF_INET - && nlmsg_type != RTM_DELADDR - && plen < 31 /* RFC 3021 */ - && address - && *((in_addr_t *) address) != 0) { - in_addr_t broadcast; - - broadcast = *((in_addr_t *) address) | ~_nm_utils_ip4_prefix_to_netmask (plen); - NLA_PUT (msg, IFA_BROADCAST, addr_len, &broadcast); - } + if (ip4_broadcast_address != 0) + NLA_PUT (msg, IFA_BROADCAST, sizeof (in_addr_t), &ip4_broadcast_address); if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT || preferred != NM_PLATFORM_LIFETIME_PERMANENT) { @@ -4236,7 +4654,7 @@ _nl_msg_new_qdisc (int nlmsg_type, if (!(tc_options = nla_nest_start (msg, TCA_OPTIONS))) goto nla_put_failure; - if (strcmp (qdisc->kind, "fq_codel") == 0) { + if (nm_streq (qdisc->kind, "fq_codel")) { if (qdisc->fq_codel.limit) NLA_PUT_U32 (msg, TCA_FQ_CODEL_LIMIT, qdisc->fq_codel.limit); if (qdisc->fq_codel.flows) @@ -4909,7 +5327,8 @@ refresh_all_type_get_info (RefreshAllType refresh_all_type) return &infos[refresh_all_type]; } -_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_type_to_refresh_all_type, DelayedActionType, RefreshAllType, +static +NM_UTILS_LOOKUP_DEFINE (delayed_action_type_to_refresh_all_type, DelayedActionType, RefreshAllType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (0), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, REFRESH_ALL_TYPE_LINKS), NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, REFRESH_ALL_TYPE_IP4_ADDRESSES), @@ -4992,7 +5411,8 @@ delayed_action_refresh_from_needle_object (const NMPObject *obj_needle) return delayed_action_type_from_refresh_all_type (refresh_all_type_from_needle_object (obj_needle)); } -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (delayed_action_to_string, DelayedActionType, +static +NM_UTILS_LOOKUP_STR_DEFINE (delayed_action_to_string, DelayedActionType, NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, "refresh-all-links"), NM_UTILS_LOOKUP_STR_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, "refresh-all-ip4-addresses"), @@ -5031,14 +5451,14 @@ delayed_action_to_string_full (DelayedActionType action_type, gpointer user_data data = user_data; if (data) { - gint64 timeout = data->timeout_abs_ns - nm_utils_get_monotonic_timestamp_ns (); + gint64 timeout = data->timeout_abs_ns - nm_utils_get_monotonic_timestamp_nsec (); char b[255]; nm_utils_strbuf_append (&buf, &buf_size, " (seq %u, timeout in %s%"G_GINT64_FORMAT".%09"G_GINT64_FORMAT", response-type %d%s%s)", data->seq_number, timeout < 0 ? "-" : "", - (timeout < 0 ? -timeout : timeout) / NM_UTILS_NS_PER_SECOND, - (timeout < 0 ? -timeout : timeout) % NM_UTILS_NS_PER_SECOND, + (timeout < 0 ? -timeout : timeout) / NM_UTILS_NSEC_PER_SEC, + (timeout < 0 ? -timeout : timeout) % NM_UTILS_NSEC_PER_SEC, (int) data->response_type, data->seq_result ? ", " : "", data->seq_result ? wait_for_nl_response_to_string (data->seq_result, NULL, b, sizeof (b)) : ""); @@ -5140,7 +5560,7 @@ delayed_action_wait_for_nl_response_complete_check (NMPlatform *platform, if (data->seq_result) delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result); else if ( p_now_ns - && ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) >= data->timeout_abs_ns)) { + && ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_nsec ())) >= data->timeout_abs_ns)) { /* the caller can optionally check for timeout by providing a p_now_ns argument. */ delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); } else if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) @@ -5360,7 +5780,7 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, { DelayedActionWaitForNlResponseData data = { .seq_number = seq_number, - .timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)), + .timeout_abs_ns = nm_utils_get_monotonic_timestamp_nsec () + (200 * (NM_UTILS_NSEC_PER_SEC / 1000)), .out_seq_result = out_seq_result, .out_errmsg = out_errmsg, .response_type = response_type, @@ -6491,11 +6911,12 @@ out: static int link_add (NMPlatform *platform, - const char *name, NMLinkType type, - const char *veth_peer, + const char *name, + int parent, const void *address, size_t address_len, + gconstpointer extra_data, const NMPlatformLink **out_link) { nm_auto_nlmsg struct nl_msg *nlmsg = NULL; @@ -6519,10 +6940,13 @@ link_add (NMPlatform *platform, if (!nlmsg) return -NME_UNSPEC; + if (parent > 0) + NLA_PUT_U32 (nlmsg, IFLA_LINK, parent); + if (address && address_len) NLA_PUT (nlmsg, IFLA_ADDRESS, address_len, address); - if (!_nl_msg_new_link_set_linkinfo (nlmsg, type, veth_peer)) + if (!_nl_msg_new_link_set_linkinfo (nlmsg, type, extra_data)) return -NME_UNSPEC; return do_add_link_with_lookup (platform, type, name, nlmsg, out_link); @@ -7158,385 +7582,6 @@ link_get_dev_id (NMPlatform *platform, int ifindex) } static gboolean -vlan_add (NMPlatform *platform, - const char *name, - int parent, - int vlan_id, - guint32 vlan_flags, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - - G_STATIC_ASSERT (NM_VLAN_FLAG_REORDER_HEADERS == (guint32) VLAN_FLAG_REORDER_HDR); - G_STATIC_ASSERT (NM_VLAN_FLAG_GVRP == (guint32) VLAN_FLAG_GVRP); - G_STATIC_ASSERT (NM_VLAN_FLAG_LOOSE_BINDING == (guint32) VLAN_FLAG_LOOSE_BINDING); - G_STATIC_ASSERT (NM_VLAN_FLAG_MVRP == (guint32) VLAN_FLAG_MVRP); - - vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL; - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - NLA_PUT_U32 (nlmsg, IFLA_LINK, parent); - - if (!_nl_msg_new_link_set_linkinfo_vlan (nlmsg, - vlan_id, - NM_VLAN_FLAGS_ALL, - vlan_flags, - NULL, - 0, - NULL, - 0)) - return FALSE; - - return (do_add_link_with_lookup (platform, NM_LINK_TYPE_VLAN, name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean -link_gre_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkGre *props, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - struct nlattr *data; - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->is_tap ? "gretap" : "gre"); - - if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex); - NLA_PUT_U32 (nlmsg, IFLA_GRE_LOCAL, props->local); - NLA_PUT_U32 (nlmsg, IFLA_GRE_REMOTE, props->remote); - NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl); - NLA_PUT_U8 (nlmsg, IFLA_GRE_TOS, props->tos); - NLA_PUT_U8 (nlmsg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery); - NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key)); - NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key)); - NLA_PUT_U16 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags)); - NLA_PUT_U16 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags)); - - nla_nest_end (nlmsg, data); - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, - props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, - name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean -link_ip6tnl_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - struct nlattr *data; - guint32 flowinfo; - - g_return_val_if_fail (!props->is_gre, FALSE); - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ip6tnl"); - - if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); - - if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any))) - NLA_PUT (nlmsg, IFLA_IPTUN_LOCAL, sizeof (props->local), &props->local); - if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any))) - NLA_PUT (nlmsg, IFLA_IPTUN_REMOTE, sizeof (props->remote), &props->remote); - - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit); - - flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; - flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) - & IP6_FLOWINFO_TCLASS_MASK; - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo)); - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto); - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLAGS, props->flags); - - nla_nest_end (nlmsg, data); - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean -link_ip6gre_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - struct nlattr *data; - guint32 flowinfo; - - g_return_val_if_fail (props->is_gre, FALSE); - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->is_tap ? "ip6gretap" : "ip6gre"); - - if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex); - - NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key)); - NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key)); - NLA_PUT_U16 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags)); - NLA_PUT_U16 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags)); - - if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any))) - NLA_PUT (nlmsg, IFLA_GRE_LOCAL, sizeof (props->local), &props->local); - if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any))) - NLA_PUT (nlmsg, IFLA_GRE_REMOTE, sizeof (props->remote), &props->remote); - - NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl); - NLA_PUT_U8 (nlmsg, IFLA_GRE_ENCAP_LIMIT, props->encap_limit); - - flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; - flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) - & IP6_FLOWINFO_TCLASS_MASK; - NLA_PUT_U32 (nlmsg, IFLA_GRE_FLOWINFO, htonl (flowinfo)); - NLA_PUT_U32 (nlmsg, IFLA_GRE_FLAGS, props->flags); - - nla_nest_end (nlmsg, data); - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, - props->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, - name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean -link_ipip_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkIpIp *props, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - struct nlattr *data; - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ipip"); - - if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local); - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote); - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos); - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); - - nla_nest_end (nlmsg, data); - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, NM_LINK_TYPE_IPIP, name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean -link_macsec_add (NMPlatform *platform, - const char *name, - int parent, - const NMPlatformLnkMacsec *props, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - struct nlattr *data; - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - NLA_PUT_U32 (nlmsg, IFLA_LINK, parent); - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "macsec"); - - if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->icv_length) - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_ICV_LEN, 16); - if (props->cipher_suite) - NLA_PUT_U64 (nlmsg, IFLA_MACSEC_CIPHER_SUITE, props->cipher_suite); - if (props->replay_protect) - NLA_PUT_U32 (nlmsg, IFLA_MACSEC_WINDOW, props->window); - - NLA_PUT_U64 (nlmsg, IFLA_MACSEC_SCI, htobe64 (props->sci)); - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_ENCODING_SA, props->encoding_sa); - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_ENCRYPT, props->encrypt); - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_PROTECT, props->protect); - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_INC_SCI, props->include_sci); - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_ES, props->es); - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_SCB, props->scb); - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_REPLAY_PROTECT, props->replay_protect); - NLA_PUT_U8 (nlmsg, IFLA_MACSEC_VALIDATION, props->validation); - - nla_nest_end (nlmsg, data); - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, - NM_LINK_TYPE_MACSEC, - name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean -link_macvlan_add (NMPlatform *platform, - const char *name, - int parent, - const NMPlatformLnkMacvlan *props, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - struct nlattr *data; - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - NLA_PUT_U32 (nlmsg, IFLA_LINK, parent); - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->tap ? "macvtap" : "macvlan"); - - if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) - goto nla_put_failure; - - NLA_PUT_U32 (nlmsg, IFLA_MACVLAN_MODE, props->mode); - NLA_PUT_U16 (nlmsg, IFLA_MACVLAN_FLAGS, props->no_promisc ? MACVLAN_FLAG_NOPROMISC : 0); - - nla_nest_end (nlmsg, data); - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, - props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN, - name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean -link_sit_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkSit *props, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - struct nlattr *data; - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "sit"); - - if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) - goto nla_put_failure; - - if (props->parent_ifindex) - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local); - NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote); - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos); - NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); - - nla_nest_end (nlmsg, data); - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, NM_LINK_TYPE_SIT, name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean link_tun_add (NMPlatform *platform, const char *name, const NMPlatformLnkTun *props, @@ -7592,107 +7637,6 @@ link_tun_add (NMPlatform *platform, return TRUE; } -static gboolean -link_vxlan_add (NMPlatform *platform, - const char *name, - const NMPlatformLnkVxlan *props, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - struct nlattr *data; - struct nm_ifla_vxlan_port_range port_range; - - g_return_val_if_fail (props, FALSE); - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "vxlan"); - - if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) - goto nla_put_failure; - - NLA_PUT_U32 (nlmsg, IFLA_VXLAN_ID, props->id); - - if (props->group) - NLA_PUT (nlmsg, IFLA_VXLAN_GROUP, sizeof (props->group), &props->group); - else if (memcmp (&props->group6, &in6addr_any, sizeof (in6addr_any))) - NLA_PUT (nlmsg, IFLA_VXLAN_GROUP6, sizeof (props->group6), &props->group6); - - if (props->local) - NLA_PUT (nlmsg, IFLA_VXLAN_LOCAL, sizeof (props->local), &props->local); - else if (memcmp (&props->local6, &in6addr_any, sizeof (in6addr_any))) - NLA_PUT (nlmsg, IFLA_VXLAN_LOCAL6, sizeof (props->local6), &props->local6); - - if (props->parent_ifindex >= 0) - NLA_PUT_U32 (nlmsg, IFLA_VXLAN_LINK, props->parent_ifindex); - - if (props->src_port_min || props->src_port_max) { - port_range.low = htons (props->src_port_min); - port_range.high = htons (props->src_port_max); - NLA_PUT (nlmsg, IFLA_VXLAN_PORT_RANGE, sizeof (port_range), &port_range); - } - - NLA_PUT_U16 (nlmsg, IFLA_VXLAN_PORT, htons (props->dst_port)); - NLA_PUT_U8 (nlmsg, IFLA_VXLAN_TOS, props->tos); - NLA_PUT_U8 (nlmsg, IFLA_VXLAN_TTL, props->ttl); - NLA_PUT_U32 (nlmsg, IFLA_VXLAN_AGEING, props->ageing); - NLA_PUT_U32 (nlmsg, IFLA_VXLAN_LIMIT, props->limit); - NLA_PUT_U8 (nlmsg, IFLA_VXLAN_LEARNING, !!props->learning); - NLA_PUT_U8 (nlmsg, IFLA_VXLAN_PROXY, !!props->proxy); - NLA_PUT_U8 (nlmsg, IFLA_VXLAN_RSC, !!props->rsc); - NLA_PUT_U8 (nlmsg, IFLA_VXLAN_L2MISS, !!props->l2miss); - NLA_PUT_U8 (nlmsg, IFLA_VXLAN_L3MISS, !!props->l3miss); - - nla_nest_end (nlmsg, data); - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, NM_LINK_TYPE_VXLAN, name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - -static gboolean -link_6lowpan_add (NMPlatform *platform, - const char *name, - int parent, - const NMPlatformLink **out_link) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct nlattr *info; - - nlmsg = _nl_msg_new_link (RTM_NEWLINK, - NLM_F_CREATE | NLM_F_EXCL, - 0, - name); - if (!nlmsg) - return FALSE; - - NLA_PUT_U32 (nlmsg, IFLA_LINK, parent); - - if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) - goto nla_put_failure; - - NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "lowpan"); - - nla_nest_end (nlmsg, info); - - return (do_add_link_with_lookup (platform, - NM_LINK_TYPE_6LOWPAN, - name, nlmsg, out_link) >= 0); -nla_put_failure: - g_return_val_if_reached (FALSE); -} - - static void _vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map, gboolean reset_all, @@ -8196,6 +8140,7 @@ ip4_address_add (NMPlatform *platform, in_addr_t addr, guint8 plen, in_addr_t peer_addr, + in_addr_t broadcast_address, guint32 lifetime, guint32 preferred, guint32 flags, @@ -8215,6 +8160,7 @@ ip4_address_add (NMPlatform *platform, nm_utils_ip4_address_is_link_local (addr) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE, lifetime, preferred, + broadcast_address, label); nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_addr); @@ -8245,6 +8191,7 @@ ip6_address_add (NMPlatform *platform, RT_SCOPE_UNIVERSE, lifetime, preferred, + 0, NULL); nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr); @@ -8268,6 +8215,7 @@ ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, guint8 pl RT_SCOPE_NOWHERE, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, + 0, NULL); if (!nlmsg) g_return_val_if_reached (FALSE); @@ -8293,6 +8241,7 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, gui RT_SCOPE_NOWHERE, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, + 0, NULL); if (!nlmsg) g_return_val_if_reached (FALSE); @@ -8402,7 +8351,7 @@ ip_route_get (NMPlatform *platform, .r.rtm_flags = 0x1000 /* RTM_F_LOOKUP_TABLE */, }; - g_clear_pointer (&route, nmp_object_unref); + nm_clear_pointer (&route, nmp_object_unref); if (!_nl_addattr_l (&req.n, sizeof (req), RTA_DST, address, addr_len)) nm_assert_not_reached (); @@ -8576,12 +8525,8 @@ tfilter_add (NMPlatform *platform, /*****************************************************************************/ -#define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) -#define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL)) -#define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP)) - static gboolean -event_handler (GIOChannel *channel, +event_handler (int fd, GIOCondition io_condition, gpointer user_data) { @@ -8609,7 +8554,7 @@ event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events) nm_auto_free unsigned char *buf = NULL; continue_reading: - g_clear_pointer (&buf, free); + nm_clear_pointer (&buf, free); n = nl_recv (sk, &nla, &buf, &creds, &creds_has); if (n <= 0) { @@ -8800,7 +8745,7 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) int r; struct pollfd pfd; gboolean any = FALSE; - int timeout_ms; + int timeout_msec; struct { guint32 seq_number; gint64 timeout_abs_ns; @@ -8881,12 +8826,12 @@ after_read: _LOGT ("netlink: read: wait for ACK for sequence number %u...", next.seq_number); - timeout_ms = (next.timeout_abs_ns - next.now_ns) / (NM_UTILS_NS_PER_SECOND / 1000); + timeout_msec = (next.timeout_abs_ns - next.now_ns) / (NM_UTILS_NSEC_PER_SEC / 1000); memset (&pfd, 0, sizeof (pfd)); pfd.fd = nl_socket_get_fd (priv->nlh); pfd.events = POLLIN; - r = poll (&pfd, 1, MAX (1, timeout_ms)); + r = poll (&pfd, 1, MAX (1, timeout_msec)); if (r == 0) { /* timeout and there is nothing to read. */ @@ -9052,14 +8997,13 @@ constructed (GObject *_object) { NMPlatform *platform = NM_PLATFORM (_object); NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int channel_flags; - gboolean status; int nle; + int fd; nm_assert (!platform->_netns || platform->_netns == nmp_netns_get_current ()); if (nm_platform_get_use_udev (platform)) { - priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL }, + priv->udev_client = nm_udev_client_new (NM_MAKE_STRV ("net"), handle_udev_event, platform); } @@ -9123,18 +9067,18 @@ constructed (GObject *_object) RTNLGRP_TC, 0); g_assert (!nle); - _LOGD ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), nl_socket_get_fd (priv->nlh)); - priv->event_channel = g_io_channel_unix_new (nl_socket_get_fd (priv->nlh)); - g_io_channel_set_encoding (priv->event_channel, NULL, NULL); + fd = nl_socket_get_fd (priv->nlh); + + _LOGD ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), fd); - channel_flags = g_io_channel_get_flags (priv->event_channel); - status = g_io_channel_set_flags (priv->event_channel, - channel_flags | G_IO_FLAG_NONBLOCK, NULL); - g_assert (status); - priv->event_id = g_io_add_watch (priv->event_channel, - (EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS), - event_handler, platform); + priv->event_source = nm_g_unix_fd_source_new (fd, + G_IO_IN | G_IO_NVAL | G_IO_PRI | G_IO_ERR | G_IO_HUP, + G_PRIORITY_DEFAULT, + event_handler, + platform, + NULL); + g_source_attach (priv->event_source, NULL); /* complete construction of the GObject instance before populating the cache. */ G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object); @@ -9227,8 +9171,8 @@ finalize (GObject *object) nl_socket_free (priv->genl); - g_source_remove (priv->event_id); - g_io_channel_unref (priv->event_channel); + nm_clear_g_source_inst (&priv->event_source); + nl_socket_free (priv->nlh); if (priv->sysctl_get_prev_values) { @@ -9294,10 +9238,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_can_assume = link_can_assume; - platform_class->vlan_add = vlan_add; platform_class->link_vlan_change = link_vlan_change; platform_class->link_wireguard_change = link_wireguard_change; - platform_class->link_vxlan_add = link_vxlan_add; platform_class->infiniband_partition_add = infiniband_partition_add; platform_class->infiniband_partition_delete = infiniband_partition_delete; @@ -9325,15 +9267,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->wpan_set_short_addr = wpan_set_short_addr; platform_class->wpan_set_channel = wpan_set_channel; - platform_class->link_gre_add = link_gre_add; - platform_class->link_ip6tnl_add = link_ip6tnl_add; - platform_class->link_ip6gre_add = link_ip6gre_add; - platform_class->link_macsec_add = link_macsec_add; - platform_class->link_macvlan_add = link_macvlan_add; - platform_class->link_ipip_add = link_ipip_add; - platform_class->link_sit_add = link_sit_add; platform_class->link_tun_add = link_tun_add; - platform_class->link_6lowpan_add = link_6lowpan_add; platform_class->object_delete = object_delete; platform_class->ip4_address_add = ip4_address_add; diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index b55fbd66..98884cd7 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -262,7 +262,8 @@ out: * ethtool *****************************************************************************/ -NM_UTILS_ENUM2STR_DEFINE_STATIC (_ethtool_cmd_to_string, guint32, +static +NM_UTILS_ENUM2STR_DEFINE (_ethtool_cmd_to_string, guint32, NM_UTILS_ENUM2STR (ETHTOOL_GDRVINFO, "ETHTOOL_GDRVINFO"), NM_UTILS_ENUM2STR (ETHTOOL_GFEATURES, "ETHTOOL_GFEATURES"), NM_UTILS_ENUM2STR (ETHTOOL_GLINK, "ETHTOOL_GLINK"), diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 6795dde7..9bbc3745 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -298,7 +298,8 @@ nm_platform_get_multi_idx (NMPlatform *self) /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_nmp_nlm_flag_to_string_lookup, NMPNlmFlags, +static +NM_UTILS_LOOKUP_STR_DEFINE (_nmp_nlm_flag_to_string_lookup, NMPNlmFlags, NM_UTILS_LOOKUP_DEFAULT (NULL), NM_UTILS_LOOKUP_ITEM (NMP_NLM_FLAG_ADD, "add"), NM_UTILS_LOOKUP_ITEM (NMP_NLM_FLAG_CHANGE, "change"), @@ -1150,11 +1151,12 @@ _link_add_check_existing (NMPlatform *self, const char *name, NMLinkType type, c /** * nm_platform_link_add: * @self: platform instance - * @name: Interface name * @type: Interface type - * @veth_peer: For veths, the peer name + * @name: Interface name + * @parent: the IFLA_LINK parameter or 0. * @address: (allow-none): set the mac address of the link * @address_len: the length of the @address + * @extra_data: depending on @type, additional data. * @out_link: on success, the link object * * Add a software interface. If the interface already exists and is of type @@ -1167,66 +1169,104 @@ _link_add_check_existing (NMPlatform *self, const char *name, NMLinkType type, c * * Returns: the negative nm-error on failure. */ -static int +int nm_platform_link_add (NMPlatform *self, - const char *name, NMLinkType type, - const char *veth_peer, + const char *name, + int parent, const void *address, size_t address_len, + gconstpointer extra_data, const NMPlatformLink **out_link) { int r; char addr_buf[NM_UTILS_HWADDR_LEN_MAX * 3]; + char parent_buf[64]; + char buf[512]; _CHECK_SELF (self, klass, -NME_BUG); g_return_val_if_fail (name, -NME_BUG); g_return_val_if_fail ((address != NULL) ^ (address_len == 0) , -NME_BUG); g_return_val_if_fail (address_len <= NM_UTILS_HWADDR_LEN_MAX, -NME_BUG); - g_return_val_if_fail ((!!veth_peer) == (type == NM_LINK_TYPE_VETH), -NME_BUG); + g_return_val_if_fail (parent >= 0, -NME_BUG); r = _link_add_check_existing (self, name, type, out_link); if (r < 0) return r; - _LOG2D ("link: adding link: %s (%d)" - "%s%s" /* address */ - "%s%s" /* veth peer */ + _LOG2D ("link: adding link: " + "%s " /* type */ + "\"%s\"" /* name */ + "%s%s" /* parent */ + "%s%s" /* address */ + "%s" /* extra_data */ "", nm_link_type_to_string (type), - (int) type, + name, + parent > 0 ? ", parent " : "", + parent > 0 ? nm_sprintf_buf (parent_buf, "%d", parent) : "", address ? ", address: " : "", address ? nm_utils_hwaddr_ntoa_buf (address, address_len, FALSE, addr_buf, sizeof (addr_buf)) : "", - veth_peer ? ", veth-peer: " : "", - veth_peer ?: ""); - - return klass->link_add (self, name, type, veth_peer, address, address_len, out_link); -} - -int -nm_platform_link_veth_add (NMPlatform *self, - const char *name, - const char *peer, - const NMPlatformLink **out_link) -{ - return nm_platform_link_add (self, name, NM_LINK_TYPE_VETH, peer, NULL, 0, out_link); -} - -/** - * nm_platform_link_dummy_add: - * @self: platform instance - * @name: New interface name - * @out_link: on success, the link object - * - * Create a software ethernet-like interface - */ -int -nm_platform_link_dummy_add (NMPlatform *self, - const char *name, - const NMPlatformLink **out_link) -{ - return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, NULL, 0, out_link); + ({ + char *buf_p = buf; + gsize buf_len = sizeof (buf); + + buf[0] = '\0'; + + switch (type) { + case NM_LINK_TYPE_VLAN: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_vlan_to_string ((const NMPlatformLnkVlan *) extra_data, buf_p, buf_len); + break; + case NM_LINK_TYPE_VRF: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_vrf_to_string ((const NMPlatformLnkVrf *) extra_data, buf_p, buf_len); + break; + case NM_LINK_TYPE_VXLAN: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_vxlan_to_string ((const NMPlatformLnkVxlan *) extra_data, buf_p, buf_len); + break; + case NM_LINK_TYPE_VETH: + nm_sprintf_buf (buf, ", veth-peer \"%s\"", (const char *) extra_data); + break; + case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_GRETAP: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_gre_to_string ((const NMPlatformLnkGre *) extra_data, buf_p, buf_len); + break; + case NM_LINK_TYPE_SIT: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_sit_to_string ((const NMPlatformLnkSit *) extra_data, buf_p, buf_len); + break; + case NM_LINK_TYPE_IP6TNL: + case NM_LINK_TYPE_IP6GRE: + case NM_LINK_TYPE_IP6GRETAP: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_ip6tnl_to_string ((const NMPlatformLnkIp6Tnl *) extra_data, buf_p, buf_len); + break; + case NM_LINK_TYPE_IPIP: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_ipip_to_string ((const NMPlatformLnkIpIp *) extra_data, buf_p, buf_len); + break; + case NM_LINK_TYPE_MACSEC: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_macsec_to_string ((const NMPlatformLnkMacsec *) extra_data, buf_p, buf_len); + break; + case NM_LINK_TYPE_MACVLAN: + case NM_LINK_TYPE_MACVTAP: + nm_utils_strbuf_append_str (&buf_p, &buf_len, ", "); + nm_platform_lnk_macvlan_to_string ((const NMPlatformLnkMacvlan *) extra_data, buf_p, buf_len); + break; + default: + nm_assert (!extra_data); + break; + } + + buf; + })); + + return klass->link_add (self, type, name, parent, address, address_len, extra_data, out_link); } /** @@ -1283,7 +1323,7 @@ nm_platform_link_get_ifindex (NMPlatform *self, const char *name) } const char * -nm_platform_if_indextoname (NMPlatform *self, int ifindex, char *out_ifname/* of size IFNAMSIZ */) +nm_platform_if_indextoname (NMPlatform *self, int ifindex, char out_ifname[static 16 /* IFNAMSIZ */]) { _CHECK_SELF_NETNS (self, klass, netns, FALSE); @@ -1408,7 +1448,7 @@ nm_platform_link_get_unmanaged (NMPlatform *self, int ifindex, gboolean *unmanag gboolean nm_platform_link_is_software (NMPlatform *self, int ifindex) { - return (nm_platform_link_get_type (self, ifindex) & 0x10000); + return nm_link_type_is_software (nm_platform_link_get_type (self, ifindex)); } /** @@ -1422,7 +1462,7 @@ nm_platform_link_is_software (NMPlatform *self, int ifindex) gboolean nm_platform_link_supports_slaves (NMPlatform *self, int ifindex) { - return (nm_platform_link_get_type (self, ifindex) & 0x20000); + return nm_link_type_supports_slaves (nm_platform_link_get_type (self, ifindex)); } /** @@ -2193,7 +2233,7 @@ nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatfor return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVLAN, out_link); } -const NMPlatformLnkMacvtap * +const NMPlatformLnkMacvlan * nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVTAP, out_link); @@ -2217,6 +2257,12 @@ nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLi return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VLAN, out_link); } +const NMPlatformLnkVrf * +nm_platform_link_get_lnk_vrf (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VRF, out_link); +} + const NMPlatformLnkVxlan * nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -2231,7 +2277,8 @@ nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatf /*****************************************************************************/ -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_flags_to_string, NMPlatformWireGuardChangeFlags, +static +NM_UTILS_FLAGS2STR_DEFINE (_wireguard_change_flags_to_string, NMPlatformWireGuardChangeFlags, NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_NONE, "none"), NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_REPLACE_PEERS, "replace-peers"), NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_PRIVATE_KEY, "has-private-key"), @@ -2239,7 +2286,8 @@ NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_flags_to_string, NMPlatformW NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_FLAG_HAS_FWMARK, "has-fwmark"), ); -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_peer_flags_to_string, NMPlatformWireGuardChangePeerFlags, +static +NM_UTILS_FLAGS2STR_DEFINE (_wireguard_change_peer_flags_to_string, NMPlatformWireGuardChangePeerFlags, NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_NONE, "none"), NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REMOVE_ME, "remove"), NM_UTILS_FLAGS2STR (NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_HAS_PRESHARED_KEY, "psk"), @@ -2250,14 +2298,6 @@ NM_UTILS_FLAGS2STR_DEFINE_STATIC (_wireguard_change_peer_flags_to_string, NMPlat ); int -nm_platform_link_wireguard_add (NMPlatform *self, - const char *name, - const NMPlatformLink **out_link) -{ - return nm_platform_link_add (self, name, NM_LINK_TYPE_WIREGUARD, NULL, NULL, 0, out_link); -} - -int nm_platform_link_wireguard_change (NMPlatform *self, int ifindex, const NMPlatformLnkWireGuard *lnk_wireguard, @@ -2316,128 +2356,6 @@ nm_platform_link_wireguard_change (NMPlatform *self, /*****************************************************************************/ /** - * nm_platform_link_bridge_add: - * @self: platform instance - * @name: New interface name - * @address: (allow-none): set the mac address of the new bridge - * @address_len: the length of the @address - * @out_link: on success, the link object - * - * Create a software bridge. - */ -int -nm_platform_link_bridge_add (NMPlatform *self, - const char *name, - const void *address, - size_t address_len, - const NMPlatformLink **out_link) -{ - return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, NULL, address, address_len, out_link); -} - -/** - * nm_platform_link_bond_add: - * @self: platform instance - * @name: New interface name - * @out_link: on success, the link object - * - * Create a software bonding device. - */ -int -nm_platform_link_bond_add (NMPlatform *self, - const char *name, - const NMPlatformLink **out_link) -{ - return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, NULL, 0, out_link); -} - -/** - * nm_platform_link_team_add: - * @self: platform instance - * @name: New interface name - * @out_link: on success, the link object - * - * Create a software teaming device. - */ -int -nm_platform_link_team_add (NMPlatform *self, - const char *name, - const NMPlatformLink **out_link) -{ - return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, NULL, 0, out_link); -} - -/** - * nm_platform_link_vlan_add: - * @self: platform instance - * @name: New interface name - * @vlanid: VLAN identifier - * @vlanflags: VLAN flags from libnm - * @out_link: on success, the link object - * - * Create a software VLAN device. - */ -int -nm_platform_link_vlan_add (NMPlatform *self, - const char *name, - int parent, - int vlanid, - guint32 vlanflags, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (parent >= 0, -NME_BUG); - g_return_val_if_fail (vlanid >= 0, -NME_BUG); - g_return_val_if_fail (name, -NME_BUG); - - r = _link_add_check_existing (self, name, NM_LINK_TYPE_VLAN, out_link); - if (r < 0) - return r; - - _LOG2D ("link: adding link vlan parent %d vlanid %d vlanflags %x", - parent, vlanid, vlanflags); - - if (!klass->vlan_add (self, name, parent, vlanid, vlanflags, out_link)) - return -NME_UNSPEC; - return 0; -} - -/** - * nm_platform_link_vxlan_add: - * @self: platform instance - * @name: New interface name - * @props: properties of the new link - * @out_link: on success, the link object - * - * Create a VXLAN device. - */ -int -nm_platform_link_vxlan_add (NMPlatform *self, - const char *name, - const NMPlatformLnkVxlan *props, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (props, -NME_BUG); - - r = _link_add_check_existing (self, name, NM_LINK_TYPE_VXLAN, out_link); - if (r < 0) - return r; - - _LOG2D ("link: adding link %s", nm_platform_lnk_vxlan_to_string (props, NULL, 0)); - - if (!klass->link_vxlan_add (self, name, props, out_link)) - return -NME_UNSPEC; - return 0; -} - -/** * nm_platform_link_tun_add: * @self: platform instance * @name: new interface name @@ -2489,38 +2407,6 @@ nm_platform_link_tun_add (NMPlatform *self, return 0; } -/** - * nm_platform_6lowpan_add: - * @self: platform instance - * @parent: parent link - * @name: name of the new interface - * @out_link: on success, the link object - * - * Create a 6LoWPAN interface. - */ -int -nm_platform_link_6lowpan_add (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (name, -NME_BUG); - - r = _link_add_check_existing (self, name, NM_LINK_TYPE_6LOWPAN, out_link); - if (r < 0) - return r; - - _LOG2D ("adding link 6lowpan parent %u", parent); - - if (!klass->link_6lowpan_add (self, name, parent, out_link)) - return -NME_UNSPEC; - return 0; -} - gboolean nm_platform_link_6lowpan_get_properties (NMPlatform *self, int ifindex, int *out_parent) { @@ -2761,39 +2647,6 @@ nm_platform_link_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, i return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, NULL, 0, FALSE, &map, 1); } -/** - * nm_platform_link_gre_add: - * @self: platform instance - * @name: name of the new interface - * @props: interface properties - * @out_link: on success, the link object - * - * Create a software GRE device. - */ -int -nm_platform_link_gre_add (NMPlatform *self, - const char *name, - const NMPlatformLnkGre *props, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (props, -NME_BUG); - g_return_val_if_fail (name, -NME_BUG); - - r = _link_add_check_existing (self, name, props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, out_link); - if (r < 0) - return r; - - _LOG2D ("adding link %s", nm_platform_lnk_gre_to_string (props, NULL, 0)); - - if (!klass->link_gre_add (self, name, props, out_link)) - return -NME_UNSPEC; - return 0; -} - static int _infiniband_add_add_or_delete (NMPlatform *self, int ifindex, @@ -2918,217 +2771,6 @@ nm_platform_link_infiniband_get_properties (NMPlatform *self, return TRUE; } -/** - * nm_platform_ip6tnl_add: - * @self: platform instance - * @name: name of the new interface - * @props: interface properties - * @out_link: on success, the link object - * - * Create an IPv6 tunnel. - */ -int -nm_platform_link_ip6tnl_add (NMPlatform *self, - const char *name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (props, -NME_BUG); - g_return_val_if_fail (name, -NME_BUG); - g_return_val_if_fail (!props->is_gre, -NME_BUG); - - r = _link_add_check_existing (self, name, NM_LINK_TYPE_IP6TNL, out_link); - if (r < 0) - return r; - - _LOG2D ("adding link %s", nm_platform_lnk_ip6tnl_to_string (props, NULL, 0)); - - if (!klass->link_ip6tnl_add (self, name, props, out_link)) - return -NME_UNSPEC; - return 0; -} - -/** - * nm_platform_ip6gre_add: - * @self: platform instance - * @name: name of the new interface - * @props: interface properties - * @out_link: on success, the link object - * - * Create an IPv6 GRE/GRETAP tunnel. - */ -int -nm_platform_link_ip6gre_add (NMPlatform *self, - const char *name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (props, -NME_BUG); - g_return_val_if_fail (name, -NME_BUG); - g_return_val_if_fail (props->is_gre, -NME_BUG); - - r = _link_add_check_existing (self, - name, - props->is_tap - ? NM_LINK_TYPE_IP6GRETAP - : NM_LINK_TYPE_IP6GRE, - out_link); - if (r < 0) - return r; - - _LOG2D ("adding link %s", nm_platform_lnk_ip6tnl_to_string (props, NULL, 0)); - - if (!klass->link_ip6gre_add (self, name, props, out_link)) - return -NME_UNSPEC; - return 0; -} - -/** - * nm_platform_ipip_add: - * @self: platform instance - * @name: name of the new interface - * @props: interface properties - * @out_link: on success, the link object - * - * Create an IPIP tunnel. - */ -int -nm_platform_link_ipip_add (NMPlatform *self, - const char *name, - const NMPlatformLnkIpIp *props, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (props, -NME_BUG); - g_return_val_if_fail (name, -NME_BUG); - - r = _link_add_check_existing (self, name, NM_LINK_TYPE_IPIP, out_link); - if (r < 0) - return r; - - _LOG2D ("adding link %s", nm_platform_lnk_ipip_to_string (props, NULL, 0)); - - if (!klass->link_ipip_add (self, name, props, out_link)) - return -NME_UNSPEC; - return 0; -} - -/** - * nm_platform_macsec_add: - * @self: platform instance - * @name: name of the new interface - * @parent: parent link - * @props: interface properties - * @out_link: on success, the link object - * - * Create a MACsec interface. - */ -int -nm_platform_link_macsec_add (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLnkMacsec *props, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (props, -NME_BUG); - g_return_val_if_fail (name, -NME_BUG); - - r = _link_add_check_existing (self, name, NM_LINK_TYPE_MACSEC, out_link); - if (r < 0) - return r; - - _LOG2D ("adding link %s", nm_platform_lnk_macsec_to_string (props, NULL, 0)); - - if (!klass->link_macsec_add (self, name, parent, props, out_link)) - return -NME_UNSPEC; - return 0; -} - -/** - * nm_platform_macvlan_add: - * @self: platform instance - * @name: name of the new interface - * @props: interface properties - * @out_link: on success, the link object - * - * Create a MACVLAN or MACVTAP device. - */ -int -nm_platform_link_macvlan_add (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLnkMacvlan *props, - const NMPlatformLink **out_link) -{ - int r; - NMLinkType type; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (props, -NME_BUG); - g_return_val_if_fail (name, -NME_BUG); - - type = props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN; - - r = _link_add_check_existing (self, name, type, out_link); - if (r < 0) - return r; - - _LOG2D ("adding link %s", nm_platform_lnk_macvlan_to_string (props, NULL, 0)); - - if (!klass->link_macvlan_add (self, name, parent, props, out_link)) - return -NME_UNSPEC; - return 0; -} - -/** - * nm_platform_sit_add: - * @self: platform instance - * @name: name of the new interface - * @props: interface properties - * @out_link: on success, the link object - * - * Create a software SIT device. - */ -int -nm_platform_link_sit_add (NMPlatform *self, - const char *name, - const NMPlatformLnkSit *props, - const NMPlatformLink **out_link) -{ - int r; - - _CHECK_SELF (self, klass, -NME_BUG); - - g_return_val_if_fail (props, -NME_BUG); - g_return_val_if_fail (name, -NME_BUG); - - r = _link_add_check_existing (self, name, NM_LINK_TYPE_SIT, out_link); - if (r < 0) - return r; - - _LOG2D ("adding link %s", nm_platform_lnk_sit_to_string (props, NULL, 0)); - - if (!klass->link_sit_add (self, name, props, out_link)) - return -NME_UNSPEC; - return 0; -} - gboolean nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex) { @@ -3675,6 +3317,7 @@ nm_platform_ip4_address_add (NMPlatform *self, in_addr_t address, guint8 plen, in_addr_t peer_address, + in_addr_t broadcast_address, guint32 lifetime, guint32 preferred, guint32 flags, @@ -3689,22 +3332,26 @@ nm_platform_ip4_address_add (NMPlatform *self, g_return_val_if_fail (!label || strlen (label) < sizeof (((NMPlatformIP4Address *) NULL)->label), FALSE); if (_LOGD_ENABLED ()) { - NMPlatformIP4Address addr = { 0 }; - - addr.ifindex = ifindex; - addr.address = address; - addr.peer_address = peer_address; - addr.plen = plen; - addr.timestamp = 0; /* set it at zero, which to_string will treat as *now* */ - addr.lifetime = lifetime; - addr.preferred = preferred; - addr.n_ifa_flags = flags; + NMPlatformIP4Address addr; + + addr = (NMPlatformIP4Address) { + .ifindex = ifindex, + .address = address, + .peer_address = peer_address, + .plen = plen, + .timestamp = 0, /* set it at zero, which to_string will treat as *now* */ + .lifetime = lifetime, + .preferred = preferred, + .n_ifa_flags = flags, + .broadcast_address = broadcast_address, + .use_ip4_broadcast_address = TRUE, + }; if (label) g_strlcpy (addr.label, label, sizeof (addr.label)); _LOG3D ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr, NULL, 0)); } - return klass->ip4_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, flags, label); + return klass->ip4_address_add (self, ifindex, address, plen, peer_address, broadcast_address, lifetime, preferred, flags, label); } gboolean @@ -3755,12 +3402,12 @@ nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address g_return_val_if_fail (plen <= 32, FALSE); _LOG3D ("address: deleting IPv4 address %s/%d, %s%s", - nm_utils_inet4_ntop (address, b1), + _nm_utils_inet4_ntop (address, b1), plen, peer_address != address ? nm_sprintf_buf (str_peer, "peer %s, ", - nm_utils_inet4_ntop (peer_address, b2)) + _nm_utils_inet4_ntop (peer_address, b2)) : "", _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); return klass->ip4_address_delete (self, ifindex, address, plen, peer_address); @@ -3778,7 +3425,7 @@ nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr a g_return_val_if_fail (plen <= 128, FALSE); _LOG3D ("address: deleting IPv6 address %s/%d, %s", - nm_utils_inet6_ntop (&address, sbuf), plen, + _nm_utils_inet6_ntop (&address, sbuf), plen, _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); return klass->ip6_address_delete (self, ifindex, address, plen); } @@ -4048,7 +3695,7 @@ nm_platform_ip4_address_sync (NMPlatform *self, { gs_unref_ptrarray GPtrArray *plat_addresses = NULL; const NMPlatformIP4Address *known_address; - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); GHashTable *plat_subnets = NULL; GHashTable *known_subnets = NULL; gs_unref_hashtable GHashTable *known_addresses_idx = NULL; @@ -4163,8 +3810,14 @@ nm_platform_ip4_address_sync (NMPlatform *self, if (!lifetime) goto delete_and_next2; - if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, - known_address->peer_address, lifetime, preferred, + if (!nm_platform_ip4_address_add (self, + ifindex, + known_address->address, + known_address->plen, + known_address->peer_address, + nm_platform_ip4_broadcast_address_from_addr (known_address), + lifetime, + preferred, ifa_flags, known_address->label)) goto delete_and_next2; @@ -4178,23 +3831,39 @@ delete_and_next2: return TRUE; } -static guint -ip6_address_scope_priority (const struct in6_addr *addr) +typedef enum { + IP6_ADDR_SCOPE_LOOPBACK, + IP6_ADDR_SCOPE_LINKLOCAL, + IP6_ADDR_SCOPE_SITELOCAL, + IP6_ADDR_SCOPE_OTHER, +} IP6AddrScope; + +static IP6AddrScope +ip6_address_scope (const NMPlatformIP6Address *a) { - if (IN6_IS_ADDR_LINKLOCAL (addr)) - return 1; - if (IN6_IS_ADDR_SITELOCAL (addr)) - return 2; - return 3; + if (IN6_IS_ADDR_LOOPBACK (&a->address)) + return IP6_ADDR_SCOPE_LOOPBACK; + if (IN6_IS_ADDR_LINKLOCAL (&a->address)) + return IP6_ADDR_SCOPE_LINKLOCAL; + if (IN6_IS_ADDR_SITELOCAL (&a->address)) + return IP6_ADDR_SCOPE_SITELOCAL; + return IP6_ADDR_SCOPE_OTHER; } static int -ip6_address_scope_cmp (gconstpointer a, gconstpointer b) +ip6_address_scope_cmp (gconstpointer p_a, gconstpointer p_b, gpointer increasing) { - const NMPlatformIP6Address *x = NMP_OBJECT_CAST_IP6_ADDRESS (*(const void **) a); - const NMPlatformIP6Address *y = NMP_OBJECT_CAST_IP6_ADDRESS (*(const void **) b); + const NMPlatformIP6Address *a; + const NMPlatformIP6Address *b; - return ip6_address_scope_priority (&x->address) - ip6_address_scope_priority (&y->address); + if (!increasing) + NM_SWAP (p_a, p_b); + + a = NMP_OBJECT_CAST_IP6_ADDRESS (*(const NMPObject *const*) p_a); + b = NMP_OBJECT_CAST_IP6_ADDRESS (*(const NMPObject *const*) p_b); + + NM_CMP_DIRECT (ip6_address_scope (a), ip6_address_scope (b)); + return 0; } /** @@ -4224,7 +3893,7 @@ nm_platform_ip6_address_sync (NMPlatform *self, gboolean full_sync) { gs_unref_ptrarray GPtrArray *plat_addresses = NULL; - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); guint i_plat, i_know; gs_unref_hashtable GHashTable *known_addresses_idx = NULL; NMPLookup lookup; @@ -4235,7 +3904,7 @@ nm_platform_ip6_address_sync (NMPlatform *self, * apply the same sorting to known addresses, so that we don't try to * unnecessary change the order of addresses with different scopes. */ if (known_addresses) - g_ptr_array_sort (known_addresses, ip6_address_scope_cmp); + g_ptr_array_sort_with_data (known_addresses, ip6_address_scope_cmp, GINT_TO_POINTER (TRUE)); if (!_addr_array_clean_expired (AF_INET6, ifindex, known_addresses, now, &known_addresses_idx)) known_addresses = NULL; @@ -4250,6 +3919,10 @@ nm_platform_ip6_address_sync (NMPlatform *self, if (plat_addresses) { guint known_addresses_len; + IP6AddrScope cur_scope; + gboolean delete_remaining_addrs; + + g_ptr_array_sort_with_data (plat_addresses, ip6_address_scope_cmp, GINT_TO_POINTER (FALSE)); known_addresses_len = known_addresses ? known_addresses->len : 0; @@ -4301,38 +3974,54 @@ clear_and_next: * selection will choose addresses in the order as they are reported by kernel. * Note that the order in @plat_addresses of the remaining matches is highest * priority first. - * We need to compare this to the order in @known_addresses (which has lowest - * priority first). + * We need to compare this to the order of addresses with same scope in + * @known_addresses (which has lowest priority first). * * If we find a first discrepancy, we need to delete all remaining addresses - * from that point on, because below we must re-add all the addresses in the - * right order to get their priority right. */ + * with same scope from that point on, because below we must re-add all the + * addresses in the right order to get their priority right. */ + cur_scope = IP6_ADDR_SCOPE_LOOPBACK; + delete_remaining_addrs = FALSE; i_plat = plat_addresses->len; i_know = 0; while (i_plat > 0) { const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[--i_plat]); + IP6AddrScope plat_scope; if (!plat_addr) continue; - for (; i_know < known_addresses_len; i_know++) { - const NMPlatformIP6Address *know_addr = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i_know]); + plat_scope = ip6_address_scope (plat_addr); + if (cur_scope != plat_scope) { + nm_assert (cur_scope < plat_scope); + delete_remaining_addrs = FALSE; + cur_scope = plat_scope; + } - if (!know_addr) - continue; + if (!delete_remaining_addrs) { + delete_remaining_addrs = TRUE; + for (; i_know < known_addresses_len; i_know++) { + const NMPlatformIP6Address *know_addr = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i_know]); + IP6AddrScope know_scope; - if (IN6_ARE_ADDR_EQUAL (&plat_addr->address, &know_addr->address)) { - /* we have a match. Mark address as handled. */ - i_know++; - goto next_plat; - } + if (!know_addr) + continue; - /* all remainging addresses need to be removed as well, so that we can - * re-add them in the correct order. Signal that, by setting @i_know - * so that the next @i_plat iteration, we won't enter the loop and - * delete the address right away */ - i_know = known_addresses_len; - break; + know_scope = ip6_address_scope (know_addr); + if (know_scope < plat_scope) + continue; + + if (IN6_ARE_ADDR_EQUAL (&plat_addr->address, &know_addr->address)) { + /* we have a match. Mark address as handled. */ + i_know++; + delete_remaining_addrs = FALSE; + goto next_plat; + } + + /* plat_address has no match. Now delete_remaining_addrs is TRUE and we will + * delete all the remaining addresses with cur_scope. */ + break; + } } nm_platform_ip6_address_delete (self, ifindex, plat_addr->address, plat_addr->plen); @@ -4965,15 +4654,15 @@ nm_platform_ip_route_get (NMPlatform *self, #define IP4_DEV_ROUTE_BLACKLIST_GC_TIMEOUT_S ((int) (((IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS + 999) * 3) / 1000)) static gint64 -_ip4_dev_route_blacklist_timeout_ms_get (gint64 timeout_ms) +_ip4_dev_route_blacklist_timeout_ms_get (gint64 timeout_msec) { - return timeout_ms >> 1; + return timeout_msec >> 1; } static gint64 -_ip4_dev_route_blacklist_timeout_ms_marked (gint64 timeout_ms) +_ip4_dev_route_blacklist_timeout_ms_marked (gint64 timeout_msec) { - return !!(timeout_ms & ((gint64) 1)); + return !!(timeout_msec & ((gint64) 1)); } static gboolean @@ -4992,7 +4681,7 @@ again: if (!priv->ip4_dev_route_blacklist_hash) goto out; - now_ms = nm_utils_get_monotonic_timestamp_ms (); + now_ms = nm_utils_get_monotonic_timestamp_msec (); g_hash_table_iter_init (&iter, priv->ip4_dev_route_blacklist_hash); while (g_hash_table_iter_next (&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) { @@ -5055,7 +4744,7 @@ _ip4_dev_route_blacklist_notify_route (NMPlatform *self, (gpointer *) &p_timeout_ms)) return; - now_ms = nm_utils_get_monotonic_timestamp_ms (); + now_ms = nm_utils_get_monotonic_timestamp_msec (); if (now_ms > _ip4_dev_route_blacklist_timeout_ms_get (*p_timeout_ms)) { /* already expired. Wait for gc. */ return; @@ -5086,7 +4775,7 @@ _ip4_dev_route_blacklist_gc_timeout_handle (gpointer user_data) nm_assert (priv->ip4_dev_route_blacklist_gc_timeout_id); - now_ms = nm_utils_get_monotonic_timestamp_ms (); + now_ms = nm_utils_get_monotonic_timestamp_msec (); g_hash_table_iter_init (&iter, priv->ip4_dev_route_blacklist_hash); while (g_hash_table_iter_next (&iter, (gpointer *) &p_obj, (gpointer *) &p_timeout_ms)) { @@ -5108,7 +4797,7 @@ _ip4_dev_route_blacklist_schedule (NMPlatform *self) if ( !priv->ip4_dev_route_blacklist_hash || g_hash_table_size (priv->ip4_dev_route_blacklist_hash) == 0) { - g_clear_pointer (&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref); + nm_clear_pointer (&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref); nm_clear_g_source (&priv->ip4_dev_route_blacklist_gc_timeout_id); } else { if (!priv->ip4_dev_route_blacklist_gc_timeout_id) { @@ -5155,8 +4844,8 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, GHashTableIter iter; const NMPObject *p_obj; guint i; - gint64 timeout_ms; - gint64 timeout_ms_val; + gint64 timeout_msec; + gint64 timeout_msec_val; gint64 *p_timeout_ms; gboolean needs_check = FALSE; @@ -5191,8 +4880,8 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, nm_g_slice_free_fcn_gint64); } - timeout_ms = nm_utils_get_monotonic_timestamp_ms () + IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS; - timeout_ms_val = (timeout_ms << 1) | ((gint64) 1); + timeout_msec = nm_utils_get_monotonic_timestamp_msec () + IP4_DEV_ROUTE_BLACKLIST_TIMEOUT_MS; + timeout_msec_val = (timeout_msec << 1) | ((gint64) 1); for (i = 0; i < ip4_dev_route_blacklist->len; i++) { const NMPObject *o; @@ -5206,7 +4895,7 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, /* un-expire and reuse the entry. */ _LOGT ("ip4-dev-route: register %s (update)", nmp_object_to_string (p_obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - *p_timeout_ms = timeout_ms_val; + *p_timeout_ms = timeout_msec_val; continue; } } @@ -5214,7 +4903,7 @@ nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self, _LOGT ("ip4-dev-route: register %s", nmp_object_to_string (o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); p_timeout_ms = g_slice_new (gint64); - *p_timeout_ms = timeout_ms_val; + *p_timeout_ms = timeout_msec_val; g_hash_table_replace (priv->ip4_dev_route_blacklist_hash, (gpointer) nmp_object_ref (o), p_timeout_ms); @@ -5605,16 +5294,16 @@ nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len "%s" /* okey */ "", lnk->is_tap ? "tap" : "", - lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", - lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "", + lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", _nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", + lnk->local ? nm_sprintf_buf (str_local, " local %s", _nm_utils_inet4_ntop (lnk->local, str_local1)) : "", lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "", lnk->path_mtu_discovery ? "" : " nopmtudisc", lnk->input_flags ? nm_sprintf_buf (str_input_flags, " iflags 0x%x", lnk->input_flags) : "", lnk->output_flags ? nm_sprintf_buf (str_output_flags, " oflags 0x%x", lnk->output_flags) : "", - NM_FLAGS_HAS (lnk->input_flags, GRE_KEY) || lnk->input_key ? nm_sprintf_buf (str_input_key, " ikey %s", nm_utils_inet4_ntop (lnk->input_key, str_input_key1)) : "", - NM_FLAGS_HAS (lnk->output_flags, GRE_KEY) || lnk->output_key ? nm_sprintf_buf (str_output_key, " okey %s", nm_utils_inet4_ntop (lnk->output_key, str_output_key1)) : ""); + NM_FLAGS_HAS (lnk->input_flags, GRE_KEY) || lnk->input_key ? nm_sprintf_buf (str_input_key, " ikey %s", _nm_utils_inet4_ntop (lnk->input_key, str_input_key1)) : "", + NM_FLAGS_HAS (lnk->output_flags, GRE_KEY) || lnk->output_key ? nm_sprintf_buf (str_output_key, " okey %s", _nm_utils_inet4_ntop (lnk->output_key, str_output_key1)) : ""); return buf; } @@ -5673,8 +5362,8 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi " flags 0x%x" "", str_type, - nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)), - nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)), + nm_sprintf_buf (str_remote, " remote %s", _nm_utils_inet6_ntop (&lnk->remote, str_remote1)), + nm_sprintf_buf (str_local, " local %s", _nm_utils_inet6_ntop (&lnk->local, str_local1)), lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", lnk->tclass == 1 ? " tclass inherit" : nm_sprintf_buf (str_tclass, " tclass 0x%x", lnk->tclass), @@ -5708,8 +5397,8 @@ nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize l "%s" /* tos */ "%s" /* path_mtu_discovery */ "", - lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", - lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "", + lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", _nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", + lnk->local ? nm_sprintf_buf (str_local, " local %s", _nm_utils_inet4_ntop (lnk->local, str_local1)) : "", lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "", @@ -5791,8 +5480,8 @@ nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len "%s" /* flags */ "%s" /* proto */ "", - lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", - lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "", + lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", _nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", + lnk->local ? nm_sprintf_buf (str_local, " local %s", _nm_utils_inet4_ntop (lnk->local, str_local1)) : "", lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "", @@ -5856,6 +5545,20 @@ nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize l } const char * +nm_platform_lnk_vrf_to_string (const NMPlatformLnkVrf *lnk, char *buf, gsize len) +{ + char *b; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + b = buf; + + nm_utils_strbuf_append (&b, &len, "table %u", lnk->table); + return buf; +} + +const char * nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len) { char str_group[100]; @@ -5879,7 +5582,7 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize g_snprintf (str_group, sizeof (str_group), " %s %s", IN_MULTICAST (ntohl (lnk->group)) ? "group" : "remote", - nm_utils_inet4_ntop (lnk->group, sbuf)); + _nm_utils_inet4_ntop (lnk->group, sbuf)); } if (IN6_IS_ADDR_UNSPECIFIED (&lnk->group6)) str_group6[0] = '\0'; @@ -5888,7 +5591,7 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize " %s%s %s", IN6_IS_ADDR_MULTICAST (&lnk->group6) ? "group" : "remote", str_group[0] ? "6" : "", /* usually, a vxlan has either v4 or v6 only. */ - nm_utils_inet6_ntop (&lnk->group6, sbuf)); + _nm_utils_inet6_ntop (&lnk->group6, sbuf)); } if (lnk->local == 0) @@ -5896,7 +5599,7 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize else { g_snprintf (str_local, sizeof (str_local), " local %s", - nm_utils_inet4_ntop (lnk->local, sbuf)); + _nm_utils_inet4_ntop (lnk->local, sbuf)); } if (IN6_IS_ADDR_UNSPECIFIED (&lnk->local6)) str_local6[0] = '\0'; @@ -5904,7 +5607,7 @@ nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize g_snprintf (str_local6, sizeof (str_local6), " local%s %s", str_local[0] ? "6" : "", /* usually, a vxlan has either v4 or v6 only. */ - nm_utils_inet6_ntop (&lnk->local6, sbuf)); + _nm_utils_inet6_ntop (&lnk->local6, sbuf)); } g_snprintf (buf, len, @@ -6054,7 +5757,9 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *bu char str_lft[30], str_pref[30], str_time[50], s_source[50]; char *str_peer = NULL; const char *str_lft_p, *str_pref_p, *str_time_p; - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); + in_addr_t broadcast_address; + char str_broadcast[INET_ADDRSTRLEN]; if (!nm_utils_to_string_buffer_init_null (address, &buf, &len)) return buf; @@ -6083,9 +5788,27 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *bu now, str_pref, sizeof (str_pref)) ); str_time_p = _lifetime_summary_to_string (now, address->timestamp, address->preferred, address->lifetime, str_time, sizeof (str_time)); + broadcast_address = nm_platform_ip4_broadcast_address_from_addr (address); + g_snprintf (buf, len, - "%s/%d lft %s pref %s%s%s%s%s%s src %s%s", - s_address, address->plen, str_lft_p, str_pref_p, str_time_p, + "%s/%d" + "%s%s" /* broadcast */ + " lft %s" + " pref %s" + "%s" /* time */ + "%s" /* peer */ + "%s" /* dev */ + "%s" /* flags */ + "%s" /* label */ + " src %s" + "%s" /* external */ + "", + s_address, address->plen, + broadcast_address ? " brd " : "", + broadcast_address ? nm_utils_inet4_ntop (broadcast_address, str_broadcast) : "", + str_lft_p, + str_pref_p, + str_time_p, str_peer ?: "", str_dev, _to_string_ifa_flags (address->n_ifa_flags, s_flags, sizeof (s_flags)), @@ -6167,7 +5890,7 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *bu char str_dev[TO_STRING_DEV_BUF_SIZE]; char *str_peer = NULL; const char *str_lft_p, *str_pref_p, *str_time_p; - gint32 now = nm_utils_get_monotonic_timestamp_s (); + gint32 now = nm_utils_get_monotonic_timestamp_sec (); if (!nm_utils_to_string_buffer_init_null (address, &buf, &len)) return buf; @@ -6203,7 +5926,8 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *bu return buf; } -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_rtm_flags_to_string, unsigned, +static +NM_UTILS_FLAGS2STR_DEFINE (_rtm_flags_to_string, unsigned, NM_UTILS_FLAGS2STR (RTNH_F_DEAD, "dead"), NM_UTILS_FLAGS2STR (RTNH_F_PERVASIVE, "pervasive"), NM_UTILS_FLAGS2STR (RTNH_F_ONLINK, "onlink"), @@ -6380,7 +6104,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi route->mss, nmp_utils_ip_config_source_to_string (route->rt_source, s_source, sizeof (s_source)), route->src_plen || !IN6_IS_ADDR_UNSPECIFIED (&route->src) - ? nm_sprintf_buf (s_src_all, " src %s/%u", nm_utils_inet6_ntop (&route->src, s_src), (unsigned) route->src_plen) + ? nm_sprintf_buf (s_src_all, " src %s/%u", _nm_utils_inet6_ntop (&route->src, s_src), (unsigned) route->src_plen) : "", _rtm_flags_to_string_full (str_rtm_flags, sizeof (str_rtm_flags), route->r_rtm_flags), s_pref_src[0] ? " pref-src " : "", @@ -7222,6 +6946,21 @@ nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b } void +nm_platform_lnk_vrf_hash_update (const NMPlatformLnkVrf *obj, NMHashState *h) +{ + nm_hash_update_vals (h, + obj->table); +} + +int +nm_platform_lnk_vrf_cmp (const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, table); + return 0; +} + +void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h) { nm_hash_update_vals (h, @@ -7298,6 +7037,7 @@ nm_platform_ip4_address_hash_update (const NMPlatformIP4Address *obj, NMHashStat nm_hash_update_vals (h, obj->ifindex, obj->addr_source, + nm_platform_ip4_broadcast_address_from_addr (obj), obj->timestamp, obj->lifetime, obj->preferred, @@ -7317,6 +7057,7 @@ nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4A NM_CMP_FIELD (a, b, address); NM_CMP_FIELD (a, b, plen); NM_CMP_FIELD (a, b, peer_address); + NM_CMP_DIRECT (nm_platform_ip4_broadcast_address_from_addr (a), nm_platform_ip4_broadcast_address_from_addr (b)); NM_CMP_FIELD (a, b, addr_source); NM_CMP_FIELD (a, b, timestamp); NM_CMP_FIELD (a, b, lifetime); @@ -8238,7 +7979,7 @@ finalize (GObject *object) nm_clear_g_source (&priv->ip4_dev_route_blacklist_check_id); nm_clear_g_source (&priv->ip4_dev_route_blacklist_gc_timeout_id); - g_clear_pointer (&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref); + nm_clear_pointer (&priv->ip4_dev_route_blacklist_hash, g_hash_table_unref); g_clear_object (&self->_netns); nm_dedup_multi_index_unref (priv->multi_idx); nmp_cache_free (priv->cache); diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 4bd8e34d..7edaaf58 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -287,7 +287,7 @@ typedef enum { * 2 @lifetime==@preferred==NM_PLATFORM_LIFETIME_PERMANENT: @timestamp is irrelevant (but mostly * set to 0). Such addresses are permanent. * 3 Non permanent addresses should (almost) always have @timestamp > 0. 0 is not a valid timestamp - * and never returned by nm_utils_get_monotonic_timestamp_s(). In this case @valid/@preferred + * and never returned by nm_utils_get_monotonic_timestamp_sec(). In this case @valid/@preferred * is anchored at @timestamp. * 4 Non permanent addresses with @timestamp == 0 are implicitly anchored at *now*, thus the time * moves as time goes by. This is usually not useful, except e.g. nm_platform_ip[46]_address_add(). @@ -308,6 +308,8 @@ typedef enum { guint8 plen; \ \ bool external:1; \ + \ + bool use_ip4_broadcast_address:1; \ ; /** @@ -325,7 +327,7 @@ typedef struct { /** * NMPlatformIP4Address: - * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_s() + * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_sec() **/ struct _NMPlatformIP4Address { __NMPlatformIPAddress_COMMON; @@ -344,12 +346,18 @@ struct _NMPlatformIP4Address { * */ in_addr_t peer_address; /* PTP peer address */ + /* IFA_BROADCAST. + * + * This parameter is ignored unless use_ip4_broadcast_address is TRUE. + * See nm_platform_ip4_broadcast_address_from_addr(). */ + in_addr_t broadcast_address; + char label[NMP_IFNAMSIZ]; }; /** * NMPlatformIP6Address: - * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_s() + * @timestamp: timestamp as returned by nm_utils_get_monotonic_timestamp_sec() **/ struct _NMPlatformIP6Address { __NMPlatformIPAddress_COMMON; @@ -795,8 +803,6 @@ typedef struct { bool tap:1; } NMPlatformLnkMacvlan; -typedef NMPlatformLnkMacvlan NMPlatformLnkMacvtap; - typedef struct { in_addr_t local; in_addr_t remote; @@ -830,6 +836,10 @@ typedef struct { } NMPlatformLnkVlan; typedef struct { + guint32 table; +} NMPlatformLnkVrf; + +typedef struct { struct in6_addr group6; struct in6_addr local6; in_addr_t group; @@ -965,11 +975,12 @@ typedef struct { void (*process_events) (NMPlatform *self); int (*link_add) (NMPlatform *self, - const char *name, NMLinkType type, - const char *veth_peer, + const char *name, + int parent, const void *address, size_t address_len, + gconstpointer extra_data, const NMPlatformLink **out_link); gboolean (*link_delete) (NMPlatform *self, int ifindex); gboolean (*link_refresh) (NMPlatform *self, int ifindex); @@ -1028,7 +1039,6 @@ typedef struct { guint peers_len, NMPlatformWireGuardChangeFlags change_flags); - gboolean (*vlan_add) (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link); gboolean (*link_vlan_change) (NMPlatform *self, int ifindex, NMVlanFlags flags_mask, @@ -1039,49 +1049,11 @@ typedef struct { gboolean egress_reset_all, const NMVlanQosMapping *egress_map, gsize n_egress_map); - gboolean (*link_vxlan_add) (NMPlatform *self, - const char *name, - const NMPlatformLnkVxlan *props, - const NMPlatformLink **out_link); - gboolean (*link_gre_add) (NMPlatform *self, - const char *name, - const NMPlatformLnkGre *props, - const NMPlatformLink **out_link); - gboolean (*link_ip6tnl_add) (NMPlatform *self, - const char *name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink **out_link); - gboolean (*link_ip6gre_add) (NMPlatform *self, - const char *name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink **out_link); - gboolean (*link_ipip_add) (NMPlatform *self, - const char *name, - const NMPlatformLnkIpIp *props, - const NMPlatformLink **out_link); - gboolean (*link_macsec_add) (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLnkMacsec *props, - const NMPlatformLink **out_link); - gboolean (*link_macvlan_add) (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLnkMacvlan *props, - const NMPlatformLink **out_link); - gboolean (*link_sit_add) (NMPlatform *self, - const char *name, - const NMPlatformLnkSit *props, - const NMPlatformLink **out_link); gboolean (*link_tun_add) (NMPlatform *self, const char *name, const NMPlatformLnkTun *props, const NMPlatformLink **out_link, int *out_fd); - gboolean (*link_6lowpan_add) (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLink **out_link); gboolean (*infiniband_partition_add) (NMPlatform *self, int parent, int p_key, const NMPlatformLink **out_link); gboolean (*infiniband_partition_delete) (NMPlatform *self, int parent, int p_key); @@ -1116,6 +1088,7 @@ typedef struct { in_addr_t address, guint8 plen, in_addr_t peer_address, + in_addr_t broadcast_address, guint32 lifetime, guint32 preferred_lft, guint32 flags, @@ -1187,6 +1160,31 @@ NMPlatform *nm_platform_get (void); /*****************************************************************************/ +static inline in_addr_t +nm_platform_ip4_broadcast_address_create (in_addr_t address, + guint8 plen) +{ + return address | ~_nm_utils_ip4_prefix_to_netmask (plen); +} + +static inline in_addr_t +nm_platform_ip4_broadcast_address_from_addr (const NMPlatformIP4Address *addr) +{ + nm_assert (addr); + + if (addr->use_ip4_broadcast_address) + return addr->broadcast_address; + + /* the set broadcast-address gets ignored, and we determine a default brd base + * on the peer IFA_ADDRESS. */ + if ( addr->peer_address != 0u + && addr->plen < 31 /* RFC3021 */) + return nm_platform_ip4_broadcast_address_create (addr->peer_address, addr->plen); + return 0u; +} + +/*****************************************************************************/ + /** * nm_platform_route_table_coerce: * @table: the route table, in its original value as received @@ -1352,7 +1350,8 @@ int nm_platform_sysctl_ip_conf_get_rp_filter_ipv4 (NMPlatform *platform, gboolean consider_all, gboolean *out_due_to_all); -const char *nm_platform_if_indextoname (NMPlatform *self, int ifindex, char *out_ifname/* of size IFNAMSIZ */); +const char *nm_platform_if_indextoname (NMPlatform *self, int ifindex, + char out_ifname[static 16 /* IFNAMSIZ */]); int nm_platform_if_nametoindex (NMPlatform *self, const char *ifname); const NMPObject *nm_platform_link_get_obj (NMPlatform *self, @@ -1363,11 +1362,200 @@ const NMPlatformLink *nm_platform_link_get_by_ifname (NMPlatform *self, const ch const NMPlatformLink *nm_platform_link_get_by_address (NMPlatform *self, NMLinkType link_type, gconstpointer address, size_t length); GPtrArray *nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name); -int nm_platform_link_dummy_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link); -int nm_platform_link_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, const NMPlatformLink **out_link); -int nm_platform_link_bond_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link); -int nm_platform_link_team_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link); -int nm_platform_link_veth_add (NMPlatform *self, const char *name, const char *peer, const NMPlatformLink **out_link); + +int nm_platform_link_add (NMPlatform *self, + NMLinkType type, + const char *name, + int parent, + const void *address, + size_t address_len, + gconstpointer extra_data, + const NMPlatformLink **out_link); + +static inline int +nm_platform_link_veth_add (NMPlatform *self, + const char *name, + const char *peer, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_VETH, name, 0, NULL, 0, peer, out_link); +} + +static inline int +nm_platform_link_dummy_add (NMPlatform *self, + const char *name, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_DUMMY, name, 0, NULL, 0, NULL, out_link); +} + +static inline int +nm_platform_link_bridge_add (NMPlatform *self, + const char *name, + const void *address, + size_t address_len, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_BRIDGE, name, 0, address, address_len, NULL, out_link); +} + +static inline int +nm_platform_link_bond_add (NMPlatform *self, + const char *name, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_BOND, name, 0, NULL, 0, NULL, out_link); +} + +static inline int +nm_platform_link_team_add (NMPlatform *self, + const char *name, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_TEAM, name, 0, NULL, 0, NULL, out_link); +} + +static inline int +nm_platform_link_wireguard_add (NMPlatform *self, + const char *name, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_WIREGUARD, name, 0, NULL, 0, NULL, out_link); +} + +static inline int +nm_platform_link_gre_add (NMPlatform *self, + const char *name, + const void *address, + size_t address_len, + const NMPlatformLnkGre *props, + const NMPlatformLink **out_link) +{ + g_return_val_if_fail (props, -NME_BUG); + + return nm_platform_link_add (self, props->is_tap ? NM_LINK_TYPE_GRETAP : NM_LINK_TYPE_GRE, name, 0, address, address_len, props, out_link); +} + +static inline int +nm_platform_link_sit_add (NMPlatform *self, + const char *name, + const NMPlatformLnkSit *props, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_SIT, name, 0, NULL, 0, props, out_link); +} + +static inline int +nm_platform_link_vlan_add (NMPlatform *self, + const char *name, + int parent, + int vlanid, + guint32 vlanflags, + const NMPlatformLink **out_link) +{ + g_return_val_if_fail (parent >= 0, -NME_BUG); + g_return_val_if_fail (vlanid >= 0, -NME_BUG); + + return nm_platform_link_add (self, + NM_LINK_TYPE_VLAN, + name, + parent, + NULL, + 0, + &((NMPlatformLnkVlan) { + .id = vlanid, + .flags = vlanflags, + }), + out_link); +} + +static inline int +nm_platform_link_vrf_add (NMPlatform *self, + const char *name, + const NMPlatformLnkVrf *props, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_VRF, name, 0, NULL, 0, props, out_link); +} + +static inline int +nm_platform_link_vxlan_add (NMPlatform *self, + const char *name, + const NMPlatformLnkVxlan *props, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_VXLAN, name, 0, NULL, 0, props, out_link); +} + +static inline int +nm_platform_link_6lowpan_add (NMPlatform *self, + const char *name, + int parent, + const NMPlatformLink **out_link) +{ + return nm_platform_link_add (self, NM_LINK_TYPE_6LOWPAN, name, parent, NULL, 0, NULL, out_link); +} + +static inline int +nm_platform_link_ip6tnl_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link) +{ + g_return_val_if_fail (props, -NME_BUG); + g_return_val_if_fail (!props->is_gre, -NME_BUG); + + return nm_platform_link_add (self, NM_LINK_TYPE_IP6TNL, name, 0, NULL, 0, props, out_link); +} + +static inline int +nm_platform_link_ip6gre_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link) +{ + g_return_val_if_fail (props, -NME_BUG); + g_return_val_if_fail (props->is_gre, -NME_BUG); + + return nm_platform_link_add (self, props->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, name, 0, NULL, 0, props, out_link); +} + +static inline int +nm_platform_link_ipip_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIpIp *props, + const NMPlatformLink **out_link) +{ + g_return_val_if_fail (props, -NME_BUG); + + return nm_platform_link_add (self, NM_LINK_TYPE_IPIP, name, 0, NULL, 0, props, out_link); +} + +static inline int +nm_platform_link_macsec_add (NMPlatform *self, + const char *name, + int parent, + const NMPlatformLnkMacsec *props, + const NMPlatformLink **out_link) +{ + g_return_val_if_fail (props, -NME_BUG); + g_return_val_if_fail (parent > 0, -NME_BUG); + + return nm_platform_link_add (self, NM_LINK_TYPE_MACSEC, name, parent, NULL, 0, props, out_link); +} + +static inline int +nm_platform_link_macvlan_add (NMPlatform *self, + const char *name, + int parent, + const NMPlatformLnkMacvlan *props, + const NMPlatformLink **out_link) +{ + g_return_val_if_fail (props, -NME_BUG); + g_return_val_if_fail (parent > 0, -NME_BUG); + + return nm_platform_link_add (self, props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN, name, parent, NULL, 0, props, out_link); +} gboolean nm_platform_link_delete (NMPlatform *self, int ifindex); @@ -1477,19 +1665,14 @@ const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform * const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkMacsec *nm_platform_link_get_lnk_macsec (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -const NMPlatformLnkMacvtap *nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkVrf *nm_platform_link_get_lnk_vrf (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkWireGuard *nm_platform_link_get_lnk_wireguard (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); -int nm_platform_link_vlan_add (NMPlatform *self, - const char *name, - int parent, - int vlanid, - guint32 vlanflags, - const NMPlatformLink **out_link); gboolean nm_platform_link_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to); gboolean nm_platform_link_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to); gboolean nm_platform_link_vlan_change (NMPlatform *self, @@ -1503,11 +1686,6 @@ gboolean nm_platform_link_vlan_change (NMPlatform *self, const NMVlanQosMapping *egress_map, gsize n_egress_map); -int nm_platform_link_vxlan_add (NMPlatform *self, - const char *name, - const NMPlatformLnkVxlan *props, - const NMPlatformLink **out_link); - int nm_platform_link_infiniband_add (NMPlatform *self, int parent, int p_key, @@ -1550,32 +1728,6 @@ const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Addr const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address); -int nm_platform_link_gre_add (NMPlatform *self, - const char *name, - const NMPlatformLnkGre *props, - const NMPlatformLink **out_link); -int nm_platform_link_ip6tnl_add (NMPlatform *self, - const char *name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink **out_link); -int nm_platform_link_ip6gre_add (NMPlatform *self, - const char *name, - const NMPlatformLnkIp6Tnl *props, - const NMPlatformLink **out_link); -int nm_platform_link_ipip_add (NMPlatform *self, - const char *name, - const NMPlatformLnkIpIp *props, - const NMPlatformLink **out_link); -int nm_platform_link_macsec_add (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLnkMacsec *props, - const NMPlatformLink **out_link); -int nm_platform_link_macvlan_add (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLnkMacvlan *props, - const NMPlatformLink **out_link); int nm_platform_link_sit_add (NMPlatform *self, const char *name, const NMPlatformLnkSit *props, @@ -1585,10 +1737,6 @@ int nm_platform_link_tun_add (NMPlatform *self, const NMPlatformLnkTun *props, const NMPlatformLink **out_link, int *out_fd); -int nm_platform_link_6lowpan_add (NMPlatform *self, - const char *name, - int parent, - const NMPlatformLink **out_link); gboolean nm_platform_link_6lowpan_get_properties (NMPlatform *self, int ifindex, int *out_parent); @@ -1614,6 +1762,7 @@ gboolean nm_platform_ip4_address_add (NMPlatform *self, in_addr_t address, guint8 plen, in_addr_t peer_address, + in_addr_t broadcast_address, guint32 lifetime, guint32 preferred_lft, guint32 flags, @@ -1693,6 +1842,7 @@ const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len); const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len); const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); +const char *nm_platform_lnk_vrf_to_string (const NMPlatformLnkVrf *lnk, char *buf, gsize len); const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_wireguard_to_string (const NMPlatformLnkWireGuard *lnk, char *buf, gsize len); const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len); @@ -1725,6 +1875,7 @@ int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatform int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b); int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b); int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); +int nm_platform_lnk_vrf_cmp (const NMPlatformLnkVrf *a, const NMPlatformLnkVrf *b); int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); int nm_platform_lnk_wireguard_cmp (const NMPlatformLnkWireGuard *a, const NMPlatformLnkWireGuard *b); int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); @@ -1771,6 +1922,7 @@ void nm_platform_lnk_macvlan_hash_update (const NMPlatformLnkMacvlan *obj, NMHas void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState *h); void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h); void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); +void nm_platform_lnk_vrf_hash_update (const NMPlatformLnkVrf *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); void nm_platform_lnk_wireguard_hash_update (const NMPlatformLnkWireGuard *obj, NMHashState *h); diff --git a/src/platform/nmp-netns.c b/src/platform/nmp-netns.c index 78f76cc7..bc91d7a8 100644 --- a/src/platform/nmp-netns.c +++ b/src/platform/nmp-netns.c @@ -31,7 +31,8 @@ #define _CLONE_NS_ALL ((int) (CLONE_NEWNS | CLONE_NEWNET)) #define _CLONE_NS_ALL_V CLONE_NEWNS , CLONE_NEWNET -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_clone_ns_to_str, int, +static +NM_UTILS_FLAGS2STR_DEFINE (_clone_ns_to_str, int, NM_UTILS_FLAGS2STR (CLONE_NEWNS, "mnt"), NM_UTILS_FLAGS2STR (CLONE_NEWNET, "net"), ); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 97aa4f28..541211cd 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -233,13 +233,13 @@ nm_sock_addr_union_to_string (const NMSockAddrUnion *sa, case AF_INET: g_snprintf (buf, len, "%s:%u", - nm_utils_inet4_ntop (sa->in.sin_addr.s_addr, s_addr), + _nm_utils_inet4_ntop (sa->in.sin_addr.s_addr, s_addr), (guint) htons (sa->in.sin_port)); break; case AF_INET6: g_snprintf (buf, len, "[%s%s]:%u", - nm_utils_inet6_ntop (&sa->in6.sin6_addr, s_addr), + _nm_utils_inet6_ntop (&sa->in6.sin6_addr, s_addr), ( sa->in6.sin6_scope_id != 0 ? nm_sprintf_buf (s_scope_id, "%u", sa->in6.sin6_scope_id) : ""), @@ -525,11 +525,11 @@ _vlan_xgress_qos_mappings_cpy (guint *dst_n_map, const NMVlanQosMapping *src_map) { if (src_n_map == 0) { - g_clear_pointer (dst_map, g_free); + nm_clear_g_free (dst_map); *dst_n_map = 0; } else if ( src_n_map != *dst_n_map || _vlan_xgress_qos_mappings_cmp (src_n_map, *dst_map, src_map) != 0) { - g_clear_pointer (dst_map, g_free); + nm_clear_g_free (dst_map); *dst_n_map = src_n_map; if (src_n_map > 0) *dst_map = nm_memdup (src_map, sizeof (*src_map) * src_n_map); @@ -1082,10 +1082,10 @@ _vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsiz return buf; \ } _vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", obj->ifindex); -_vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen, +_vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->ifindex, _nm_utils_inet4_ntop ( obj->address, buf1), obj->plen, obj->peer_address != obj->address ? "," : "", - obj->peer_address != obj->address ? nm_utils_inet4_ntop (nm_utils_ip4_address_clear_host_address (obj->peer_address, obj->plen), buf2) : ""); -_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1)); + obj->peer_address != obj->address ? _nm_utils_inet4_ntop (nm_utils_ip4_address_clear_host_address (obj->peer_address, obj->plen), buf2) : ""); +_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, _nm_utils_inet6_ntop (&obj->address, buf1)); _vt_cmd_plobj_to_string_id (qdisc, NMPlatformQdisc, "%d: %d", obj->ifindex, obj->parent); _vt_cmd_plobj_to_string_id (tfilter, NMPlatformTfilter, "%d: %d", obj->ifindex, obj->parent); @@ -3291,7 +3291,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_MACVTAP, .sizeof_data = sizeof (NMPObjectLnkMacvtap), - .sizeof_public = sizeof (NMPlatformLnkMacvtap), + .sizeof_public = sizeof (NMPlatformLnkMacvlan), .obj_type_name = "macvtap", .lnk_link_type = NM_LINK_TYPE_MACVTAP, .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string, @@ -3336,6 +3336,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vlan_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp, }, + [NMP_OBJECT_TYPE_LNK_VRF - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_VRF, + .sizeof_data = sizeof (NMPObjectLnkVrf), + .sizeof_public = sizeof (NMPlatformLnkVrf), + .obj_type_name = "vrf", + .lnk_link_type = NM_LINK_TYPE_VRF, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vrf_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_vrf_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vrf_cmp, + }, + [NMP_OBJECT_TYPE_LNK_VXLAN - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_VXLAN, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 0c0796c3..44525ed0 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -287,6 +287,10 @@ typedef struct { } NMPObjectLnkVlan; typedef struct { + NMPlatformLnkVrf _public; +} NMPObjectLnkVrf; + +typedef struct { NMPlatformLnkVxlan _public; } NMPObjectLnkVxlan; @@ -366,6 +370,9 @@ struct _NMPObject { NMPlatformLnkVlan lnk_vlan; NMPObjectLnkVlan _lnk_vlan; + NMPlatformLnkVrf lnk_vrf; + NMPObjectLnkVrf _lnk_vrf; + NMPlatformLnkVxlan lnk_vxlan; NMPObjectLnkVxlan _lnk_vxlan; @@ -493,6 +500,7 @@ _NMP_OBJECT_TYPE_IS_OBJ_WITH_IFINDEX (NMPObjectType obj_type) case NMP_OBJECT_TYPE_LNK_SIT: case NMP_OBJECT_TYPE_LNK_TUN: case NMP_OBJECT_TYPE_LNK_VLAN: + case NMP_OBJECT_TYPE_LNK_VRF: case NMP_OBJECT_TYPE_LNK_VXLAN: case NMP_OBJECT_TYPE_LNK_WIREGUARD: return TRUE; diff --git a/src/platform/tests/meson.build b/src/platform/tests/meson.build index 6f7173b6..4a50bca9 100644 --- a/src/platform/tests/meson.build +++ b/src/platform/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_fake_c_flags = test_c_flags + ['-DSETUP=nm_fake_platform_setup'] test_linux_c_flags = test_c_flags + ['-DSETUP=nm_linux_platform_setup'] diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 34175c01..d19ff1f0 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -61,8 +61,7 @@ test_cleanup_internal (void) break; }); - /* Add routes and addresses */ - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, 0, NULL)); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, nm_platform_ip4_broadcast_address_create (addr4, plen4), lifetime, preferred, 0, NULL)); g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags)); nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss); nmtstp_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss); diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index f831fe94..f393ae93 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -190,7 +190,7 @@ _accept_or_wait_signal (const char *file, int line, const char *func, SignalData if (data->received_count == 0) { data->loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (data->loop); - g_clear_pointer (&data->loop, g_main_loop_unref); + nm_clear_pointer (&data->loop, g_main_loop_unref); } _accept_signal (file, line, func, data); @@ -205,7 +205,7 @@ _wait_signal (const char *file, int line, const char *func, SignalData *data) data->loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (data->loop); - g_clear_pointer (&data->loop, g_main_loop_unref); + nm_clear_pointer (&data->loop, g_main_loop_unref); _accept_signal (file, line, func, data); } @@ -356,7 +356,7 @@ _nmtstp_assert_ip4_route_exists (const char *file, g_error ("[%s:%u] %s(): The ip4 route %s/%d metric %u tos %u shall exist %u times, but platform has it %u times", file, line, func, - nm_utils_inet4_ntop (network, sbuf), + _nm_utils_inet4_ntop (network, sbuf), plen, metric, tos, @@ -467,10 +467,10 @@ _nmtstp_assert_ip6_route_exists (const char *file, g_error ("[%s:%u] %s(): The ip6 route %s/%d metric %u src %s/%d shall exist %u times, but platform has it %u times", file, line, func, - nm_utils_inet6_ntop (network, s_network), + _nm_utils_inet6_ntop (network, s_network), plen, metric, - nm_utils_inet6_ntop (src, s_src), + _nm_utils_inet6_ntop (src, s_src), src_plen, c_exists, c); @@ -553,7 +553,7 @@ _wait_for_signal_timeout (gpointer user_data) } guint -nmtstp_wait_for_signal (NMPlatform *platform, gint64 timeout_ms) +nmtstp_wait_for_signal (NMPlatform *platform, gint64 timeout_msec) { WaitForSignalData data = { 0 }; gulong id_link, id_ip4_address, id_ip6_address, id_ip4_route, id_ip6_route; @@ -568,7 +568,7 @@ nmtstp_wait_for_signal (NMPlatform *platform, gint64 timeout_ms) id_ip4_route = g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); id_ip6_route = g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); - /* if timeout_ms is negative, it means the wait-time already expired. + /* if timeout_msec is negative, it means the wait-time already expired. * Maybe, we should do nothing and return right away, without even * processing events from platform. However, that inconsistency (of not * processing events from mainloop) is inconvenient. @@ -578,7 +578,7 @@ nmtstp_wait_for_signal (NMPlatform *platform, gint64 timeout_ms) * a zero timeout: we check whether there are any events pending in platform, * and quite the mainloop immediately afterwards. But we always check. */ - data.id = g_timeout_add (CLAMP (timeout_ms, 0, G_MAXUINT32), + data.id = g_timeout_add (CLAMP (timeout_msec, 0, G_MAXUINT32), _wait_for_signal_timeout, &data); g_main_loop_run (data.loop); @@ -590,7 +590,7 @@ nmtstp_wait_for_signal (NMPlatform *platform, gint64 timeout_ms) g_assert (nm_clear_g_signal_handler (platform, &id_ip4_route)); g_assert (nm_clear_g_signal_handler (platform, &id_ip6_route)); - g_clear_pointer (&data.loop, g_main_loop_unref); + nm_clear_pointer (&data.loop, g_main_loop_unref); /* return the number of signals, or 0 if timeout was reached .*/ return data.signal_counts; @@ -603,7 +603,7 @@ nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms) guint signal_counts; while (TRUE) { - now = nm_utils_get_monotonic_timestamp_ms (); + now = nm_utils_get_monotonic_timestamp_msec (); if (until_ms < now) return 0; @@ -615,11 +615,11 @@ nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms) } const NMPlatformLink * -nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 timeout_ms) +nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 timeout_msec) { return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, - timeout_ms - ? nm_utils_get_monotonic_timestamp_ms () + timeout_ms + timeout_msec + ? nm_utils_get_monotonic_timestamp_msec () + timeout_msec : 0); } @@ -633,7 +633,7 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType _init_platform (&platform, FALSE); while (TRUE) { - now = nm_utils_get_monotonic_timestamp_ms (); + now = nm_utils_get_monotonic_timestamp_msec (); plink = nm_platform_link_get_by_ifname (platform, ifname); if ( plink @@ -704,7 +704,7 @@ nmtstp_ip_address_check_lifetime (const NMPlatformIPAddress *addr, g_assert (addr); if (now == -1) - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); g_assert (now > 0); g_assert (expected_preferred <= expected_lifetime); @@ -750,7 +750,7 @@ nmtstp_ip_address_assert_lifetime (const NMPlatformIPAddress *addr, g_assert (addr); if (now == -1) - now = nm_utils_get_monotonic_timestamp_s (); + now = nm_utils_get_monotonic_timestamp_sec (); g_assert (now > 0); g_assert (expected_preferred <= expected_lifetime); @@ -831,12 +831,12 @@ _ip_address_add (NMPlatform *platform, if ( peer_address->addr4 != address->addr4 || nmtst_get_rand_uint32 () % 2) { /* If the peer is the same as the local address, we can omit it. The result should be identical */ - nm_sprintf_buf (s_peer, " peer %s", nm_utils_inet4_ntop (peer_address->addr4, b2)); + nm_sprintf_buf (s_peer, " peer %s", _nm_utils_inet4_ntop (peer_address->addr4, b2)); } else s_peer[0] = '\0'; nmtstp_run_command_check ("ip address change %s%s/%d dev %s%s%s%s", - nm_utils_inet4_ntop (address->addr4, b1), + _nm_utils_inet4_ntop (address->addr4, b1), s_peer, plen, ifname, @@ -849,9 +849,9 @@ _ip_address_add (NMPlatform *platform, /* flags not implemented (yet) */ g_assert (flags == 0); nmtstp_run_command_check ("ip address change %s%s%s/%d dev %s%s%s%s", - nm_utils_inet6_ntop (&address->addr6, b1), + _nm_utils_inet6_ntop (&address->addr6, b1), !IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) ? " peer " : "", - !IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) ? nm_utils_inet6_ntop (&peer_address->addr6, b2) : "", + !IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) ? _nm_utils_inet6_ntop (&peer_address->addr6, b2) : "", plen, ifname, s_valid ?: "", @@ -867,6 +867,7 @@ _ip_address_add (NMPlatform *platform, address->addr4, plen, peer_address->addr4, + 0u, lifetime, preferred, flags, @@ -886,7 +887,7 @@ _ip_address_add (NMPlatform *platform, } /* Let's wait until we see the address. */ - end_time = nm_utils_get_monotonic_timestamp_ms () + 500; + end_time = nm_utils_get_monotonic_timestamp_msec () + 500; do { if (external_command) @@ -1058,15 +1059,15 @@ _ip_address_del (NMPlatform *platform, if (is_v4) { success = nmtstp_run_command ("ip address delete %s%s%s/%d dev %s", - nm_utils_inet4_ntop (address->addr4, b1), + _nm_utils_inet4_ntop (address->addr4, b1), peer_address->addr4 != address->addr4 ? " peer " : "", - peer_address->addr4 != address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "", + peer_address->addr4 != address->addr4 ? _nm_utils_inet4_ntop (peer_address->addr4, b2) : "", plen, ifname); } else { g_assert (!peer_address); success = nmtstp_run_command ("ip address delete %s/%d dev %s", - nm_utils_inet6_ntop (&address->addr6, b1), + _nm_utils_inet6_ntop (&address->addr6, b1), plen, ifname); } @@ -1091,7 +1092,7 @@ _ip_address_del (NMPlatform *platform, } /* Let's wait until we get the result */ - end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + end_time = nm_utils_get_monotonic_timestamp_msec () + 250; do { if (external_command) nm_platform_process_events (platform); @@ -1257,15 +1258,15 @@ nmtstp_link_gre_add (NMPlatform *platform, name, type, dev ?: "", - nm_utils_inet4_ntop (lnk->local, b1), - nm_utils_inet4_ntop (lnk->remote, b2), + _nm_utils_inet4_ntop (lnk->local, b1), + _nm_utils_inet4_ntop (lnk->remote, b2), lnk->ttl, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); if (success) pllink = nmtstp_assert_wait_for_link (platform, name, link_type, 100); } else - success = NMTST_NM_ERR_SUCCESS (nm_platform_link_gre_add (platform, name, lnk, &pllink)); + success = NMTST_NM_ERR_SUCCESS (nm_platform_link_gre_add (platform, name, NULL, 0, lnk, &pllink)); _assert_pllink (platform, success, pllink, name, link_type); @@ -1319,8 +1320,8 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, name, mode, dev, - nm_utils_inet6_ntop (&lnk->local, b1), - nm_utils_inet6_ntop (&lnk->remote, b2), + _nm_utils_inet6_ntop (&lnk->local, b1), + _nm_utils_inet6_ntop (&lnk->remote, b2), lnk->ttl, tclass_inherit ? "inherit" : nm_sprintf_buf (tclass, "%02x", lnk->tclass), encap_ignore ? "none" : nm_sprintf_buf (encap, "%u", lnk->encap_limit), @@ -1367,8 +1368,8 @@ nmtstp_link_ip6gre_add (NMPlatform *platform, name, lnk->is_tap ? "ip6gretap" : "ip6gre", dev, - nm_utils_inet6_ntop (&lnk->local, b1), - nm_utils_inet6_ntop (&lnk->remote, b2), + _nm_utils_inet6_ntop (&lnk->local, b1), + _nm_utils_inet6_ntop (&lnk->remote, b2), lnk->ttl, tclass_inherit ? "inherit" : nm_sprintf_buf (tclass, "%02x", lnk->tclass), lnk->flow_label); @@ -1412,8 +1413,8 @@ nmtstp_link_ipip_add (NMPlatform *platform, success = !nmtstp_run_command ("ip tunnel add %s mode ipip %s local %s remote %s ttl %u tos %02x %s", name, dev, - nm_utils_inet4_ntop (lnk->local, b1), - nm_utils_inet4_ntop (lnk->remote, b2), + _nm_utils_inet4_ntop (lnk->local, b1), + _nm_utils_inet4_ntop (lnk->remote, b2), lnk->ttl, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); @@ -1506,8 +1507,8 @@ nmtstp_link_sit_add (NMPlatform *platform, success = !nmtstp_run_command ("ip tunnel add %s mode sit%s local %s remote %s ttl %u tos %02x %s", name, dev, - nm_utils_inet4_ntop (lnk->local, b1), - nm_utils_inet4_ntop (lnk->remote, b2), + _nm_utils_inet4_ntop (lnk->local, b1), + _nm_utils_inet4_ntop (lnk->remote, b2), lnk->ttl, lnk->tos, lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); @@ -1586,6 +1587,45 @@ nmtstp_link_tun_add (NMPlatform *platform, } const NMPlatformLink * +nmtstp_link_vrf_add (NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkVrf *lnk, + gboolean *out_not_supported) +{ + const NMPlatformLink *pllink = NULL; + int r = 0; + + g_assert (nm_utils_ifname_valid_kernel (name, NULL)); + + NM_SET_OUT (out_not_supported, FALSE); + external_command = nmtstp_run_command_check_external (external_command); + + _init_platform (&platform, external_command); + + if (external_command) { + r = nmtstp_run_command ("ip link add %s type vrf table %u", + name, + lnk->table); + + if (r == 0) + pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_VRF, 100); + else + _LOGI ("Adding vrf device via iproute2 failed. Assume iproute2 is not up to the task."); + } + + if (!pllink) { + r = nm_platform_link_vrf_add (platform, name, lnk, &pllink); + if (r == -EOPNOTSUPP) + NM_SET_OUT (out_not_supported, TRUE); + } + + _assert_pllink (platform, r == 0, pllink, name, NM_LINK_TYPE_VRF); + + return pllink; +} + +const NMPlatformLink * nmtstp_link_vxlan_add (NMPlatform *platform, gboolean external_command, const char *name, @@ -1610,16 +1650,16 @@ nmtstp_link_vxlan_add (NMPlatform *platform, dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (platform, lnk->parent_ifindex)); if (lnk->local) - nm_utils_inet4_ntop (lnk->local, local); + _nm_utils_inet4_ntop (lnk->local, local); else if (memcmp (&lnk->local6, &in6addr_any, sizeof (in6addr_any))) - nm_utils_inet6_ntop (&lnk->local6, local); + _nm_utils_inet6_ntop (&lnk->local6, local); else local[0] = '\0'; if (lnk->group) - nm_utils_inet4_ntop (lnk->group, group); + _nm_utils_inet4_ntop (lnk->group, group); else if (memcmp (&lnk->group6, &in6addr_any, sizeof (in6addr_any))) - nm_utils_inet6_ntop (&lnk->group6, group); + _nm_utils_inet6_ntop (&lnk->group6, group); else group[0] = '\0'; @@ -1736,7 +1776,7 @@ nmtstp_link_delete (NMPlatform *platform, } /* Let's wait until we get the result */ - end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + end_time = nm_utils_get_monotonic_timestamp_msec () + 250; do { if (external_command) nm_platform_process_events (platform); @@ -1785,7 +1825,7 @@ nmtstp_link_set_updown (NMPlatform *platform, } /* Let's wait until we get the result */ - end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + end_time = nm_utils_get_monotonic_timestamp_msec () + 250; do { if (external_command) nm_platform_process_events (platform); diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index c571df6a..522c3756 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -32,13 +32,13 @@ const NMLogDomain __domain = (domain); \ \ if (nm_logging_enabled (__level, __domain)) { \ - gint64 _ts = nm_utils_get_monotonic_timestamp_ns (); \ + gint64 _ts = nm_utils_get_monotonic_timestamp_nsec (); \ \ _nm_log (__level, __domain, 0, NULL, NULL, \ "%s[%ld.%09ld]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ - (long) (_ts / NM_UTILS_NS_PER_SECOND), \ - (long) (_ts % NM_UTILS_NS_PER_SECOND) \ + (long) (_ts / NM_UTILS_NSEC_PER_SEC), \ + (long) (_ts % NM_UTILS_NSEC_PER_SEC) \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ } G_STMT_END @@ -101,14 +101,14 @@ int nmtstp_run_command (const char *format, ...) _nm_printf (1, 2); /*****************************************************************************/ -guint nmtstp_wait_for_signal (NMPlatform *platform, gint64 timeout_ms); +guint nmtstp_wait_for_signal (NMPlatform *platform, gint64 timeout_msec); guint nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms); -const NMPlatformLink *nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 timeout_ms); +const NMPlatformLink *nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 timeout_msec); const NMPlatformLink *nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms); -#define nmtstp_assert_wait_for_signal(platform, timeout_ms) \ +#define nmtstp_assert_wait_for_signal(platform, timeout_msec) \ G_STMT_START { \ - if (nmtstp_wait_for_signal (platform, timeout_ms) == 0) \ + if (nmtstp_wait_for_signal (platform, timeout_msec) == 0) \ g_assert_not_reached (); \ } G_STMT_END @@ -118,8 +118,8 @@ const NMPlatformLink *nmtstp_wait_for_link_until (NMPlatform *platform, const ch g_assert_not_reached (); \ } G_STMT_END -#define nmtstp_assert_wait_for_link(platform, ifname, expected_link_type, timeout_ms) \ - nmtst_assert_nonnull (nmtstp_wait_for_link (platform, ifname, expected_link_type, timeout_ms)) +#define nmtstp_assert_wait_for_link(platform, ifname, expected_link_type, timeout_msec) \ + nmtst_assert_nonnull (nmtstp_wait_for_link (platform, ifname, expected_link_type, timeout_msec)) #define nmtstp_assert_wait_for_link_until(platform, ifname, expected_link_type, until_ms) \ nmtst_assert_nonnull (nmtstp_wait_for_link_until (platform, ifname, expected_link_type, until_ms)) @@ -360,6 +360,11 @@ const NMPlatformLink *nmtstp_link_tun_add (NMPlatform *platform, const char *name, const NMPlatformLnkTun *lnk, int *out_fd); +const NMPlatformLink *nmtstp_link_vrf_add (NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkVrf *lnk, + gboolean *out_not_supported); const NMPlatformLink *nmtstp_link_vxlan_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 37e1cde5..2661914b 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -1144,7 +1144,7 @@ test_software_detect (gconstpointer user_data) break; } case NM_LINK_TYPE_MACVTAP: { - NMPlatformLnkMacvtap lnk_macvtap = { }; + NMPlatformLnkMacvlan lnk_macvtap = { }; lnk_macvtap.mode = MACVLAN_MODE_PRIVATE; lnk_macvtap.no_promisc = FALSE; @@ -1182,6 +1182,21 @@ test_software_detect (gconstpointer user_data) case NM_LINK_TYPE_VLAN: nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1242", DEVICE_NAME, PARENT_NAME); break; + case NM_LINK_TYPE_VRF: { + NMPlatformLnkVrf lnk_vrf = { }; + gboolean not_supported; + + lnk_vrf.table = 9876; + + if (!nmtstp_link_vrf_add (NULL, ext, DEVICE_NAME, &lnk_vrf, ¬_supported)) { + if (not_supported) { + g_test_skip ("Cannot create VRF interface because of missing kernel support"); + goto out_delete_parent; + } + g_error ("Failed adding VRF interface"); + } + break; + } case NM_LINK_TYPE_VXLAN: { NMPlatformLnkVxlan lnk_vxlan = { }; @@ -1389,7 +1404,7 @@ test_software_detect (gconstpointer user_data) break; } case NM_LINK_TYPE_MACVTAP: { - const NMPlatformLnkMacvtap *plnk = &lnk->lnk_macvlan; + const NMPlatformLnkMacvlan *plnk = &lnk->lnk_macvlan; g_assert (plnk == nm_platform_link_get_lnk_macvtap (NM_PLATFORM_GET, ifindex, NULL)); g_assert_cmpint (plnk->no_promisc, ==, FALSE); @@ -1444,6 +1459,13 @@ test_software_detect (gconstpointer user_data) g_assert_cmpint (plnk->id, ==, 1242); break; } + case NM_LINK_TYPE_VRF: { + const NMPlatformLnkVrf *plnk = &lnk->lnk_vrf; + + g_assert (plnk == nm_platform_link_get_lnk_vrf (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->table, ==, 9876); + break; + } case NM_LINK_TYPE_VXLAN: { const NMPlatformLnkVxlan *plnk = &lnk->lnk_vxlan; @@ -2095,7 +2117,7 @@ test_vlan_set_xgress (void) static void test_create_many_links_do (guint n_devices) { - gint64 time, start_time = nm_utils_get_monotonic_timestamp_ns (); + gint64 time, start_time = nm_utils_get_monotonic_timestamp_nsec (); guint i; char name[64]; const NMPlatformLink *pllink; @@ -2149,8 +2171,8 @@ test_create_many_links_do (guint n_devices) _LOGI (">>> process events after deleting devices..."); nm_platform_process_events (NM_PLATFORM_GET); - time = nm_utils_get_monotonic_timestamp_ns () - start_time; - _LOGI (">>> finished in %ld.%09ld seconds", (long) (time / NM_UTILS_NS_PER_SECOND), (long) (time % NM_UTILS_NS_PER_SECOND)); + time = nm_utils_get_monotonic_timestamp_nsec () - start_time; + _LOGI (">>> finished in %ld.%09ld seconds", (long) (time / NM_UTILS_NSEC_PER_SEC), (long) (time % NM_UTILS_NSEC_PER_SEC)); } static void @@ -3313,6 +3335,7 @@ _nmtstp_setup_tests (void) test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0); test_software_detect_add ("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0); test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0); + test_software_detect_add ("/link/software/detect/vrf", NM_LINK_TYPE_VRF, 0); test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0); test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1); test_software_detect_add ("/link/software/detect/wireguard/0", NM_LINK_TYPE_WIREGUARD, 0); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index f8b1bb9a..f074ca69 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -19,7 +19,7 @@ static void _wait_for_ipv4_addr_device_route (NMPlatform *platform, - gint64 timeout_ms, + gint64 timeout_msec, int ifindex, in_addr_t addr, guint8 plen) @@ -55,7 +55,7 @@ _wait_for_ipv4_addr_device_route (NMPlatform *platform, static void _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, - gint64 timeout_ms, + gint64 timeout_msec, int ifindex, guint addr_n, const struct in6_addr *addrs) @@ -67,7 +67,7 @@ _wait_for_ipv6_addr_non_tentative (NMPlatform *platform, * small amount of time, which prevents the immediate addition of the route * with RTA_PREFSRC */ - NMTST_WAIT_ASSERT (timeout_ms, { + NMTST_WAIT_ASSERT (timeout_msec, { gboolean should_wait = FALSE; const NMPlatformIP6Address *plt_addr; @@ -544,6 +544,7 @@ test_ip4_route_options (gconstpointer test_data) a->address, a->plen, a->peer_address, + nm_platform_ip4_broadcast_address_create (a->address, a->plen), a->lifetime, a->preferred, a->n_ifa_flags, @@ -1238,7 +1239,7 @@ again_uid_range: rr->uid_range.end = nmtst_rand_select (0u, uids.uid, uids.euid); if (rr->uid_range_has) { if (rr->uid_range.end < rr->uid_range.start) - NMTST_SWAP (rr->uid_range.start, rr->uid_range.end); + NM_SWAP (rr->uid_range.start, rr->uid_range.end); if ( rr->uid_range.start == ((guint32) -1) || rr->uid_range.end == ((guint32) -1)) goto again_uid_range; @@ -1258,7 +1259,7 @@ again_uid_range: range->start = nmtst_rand_select (1u, 0xFFFEu, ((p ) % 0xFFFEu) + 1); range->end = nmtst_rand_select (1u, 0xFFFEu, ((p >> 16) % 0xFFFEu) + 1, range->start); if (range->end < range->start) - NMTST_SWAP (range->start, range->end); + NM_SWAP (range->start, range->end); } } } diff --git a/src/platform/wifi/nm-wifi-utils-nl80211.c b/src/platform/wifi/nm-wifi-utils-nl80211.c index afeb3b02..a090ef9e 100644 --- a/src/platform/wifi/nm-wifi-utils-nl80211.c +++ b/src/platform/wifi/nm-wifi-utils-nl80211.c @@ -152,7 +152,7 @@ dispose (GObject *object) { NMWifiUtilsNl80211 *self = NM_WIFI_UTILS_NL80211 (object); - g_clear_pointer (&self->freqs, g_free); + nm_clear_g_free (&self->freqs); } struct nl80211_iface_info { diff --git a/src/ppp/meson.build b/src/ppp/meson.build index 0c458768..181a6bef 100644 --- a/src/ppp/meson.build +++ b/src/ppp/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + name = 'nm-pppd-plugin' c_flags = [ diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c index f649e0cb..751ec28b 100644 --- a/src/ppp/nm-ppp-manager.c +++ b/src/ppp/nm-ppp-manager.c @@ -41,7 +41,8 @@ #define NM_PPPD_PLUGIN PPPD_PLUGIN_DIR "/nm-pppd-plugin.so" -static NM_CACHED_QUARK_FCN ("ppp-manager-secret-tries", ppp_manager_secret_tries_quark) +static +NM_CACHED_QUARK_FCN ("ppp-manager-secret-tries", ppp_manager_secret_tries_quark) /*****************************************************************************/ @@ -664,7 +665,8 @@ out: /*****************************************************************************/ -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (pppd_exit_code_to_str, int, +static +NM_UTILS_LOOKUP_STR_DEFINE (pppd_exit_code_to_str, int, NM_UTILS_LOOKUP_DEFAULT ("Unknown error"), NM_UTILS_LOOKUP_STR_ITEM ( 1, "Fatal pppd error"); NM_UTILS_LOOKUP_STR_ITEM ( 2, "pppd options error"), @@ -1259,7 +1261,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE ((NMPPPManager *) object); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (object); switch (prop_id) { case PROP_PARENT_IFACE: @@ -1275,7 +1277,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE ((NMPPPManager *) object); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (object); switch (prop_id) { case PROP_PARENT_IFACE: @@ -1333,7 +1335,7 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE ((NMPPPManager *) object); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (object); g_free (priv->parent_iface); diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index ecca0eb3..363b1175 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -35,15 +35,9 @@ typedef struct { NMAuthManager *auth_mgr; NMSessionMonitor *session_monitor; - /* Auth chains for checking agent permissions */ - GSList *chains; + CList agent_lst_head; - /* Hashed by owner name, not identifier, since two agents in different - * sessions can use the same identifier. - */ - GHashTable *agents; - - CList requests; + CList request_lst_head; guint64 agent_version_id; } NMAgentManagerPrivate; @@ -119,6 +113,8 @@ static void _con_del_request_start (Request *req); static gboolean _con_get_try_complete_early (Request *req); +static void agent_disconnected_cb (NMSecretAgent *agent, gpointer user_data); + /*****************************************************************************/ guint64 @@ -152,7 +148,7 @@ _request_type_to_string (RequestType request_type, gboolean verbose) /*****************************************************************************/ struct _NMAgentManagerCallId { - CList lst_request; + CList request_lst; NMAgentManager *self; @@ -201,40 +197,73 @@ struct _NMAgentManagerCallId { /*****************************************************************************/ -static gboolean -remove_agent (NMAgentManager *self, const char *owner) +static NMSecretAgent * +_agent_find_by_owner (NMAgentManagerPrivate *priv, + const char *owner) { - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); NMSecretAgent *agent; - CList *iter, *safe; - g_return_val_if_fail (owner != NULL, FALSE); + c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) { + if (nm_streq (nm_secret_agent_get_dbus_owner (agent), owner)) + return agent; + } + return NULL; +} - /* Make sure this agent has already registered */ - agent = g_hash_table_lookup (priv->agents, owner); - if (!agent) - return FALSE; +static NMSecretAgent * +_agent_find_by_identifier_and_uid (NMAgentManagerPrivate *priv, + const char *identifier, + gulong sender_uid) +{ + NMSecretAgent *agent; + + c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) { + if ( nm_streq0 (nm_secret_agent_get_identifier (agent), identifier) + && sender_uid == nm_secret_agent_get_owner_uid (agent)) + return agent; + } + return NULL; +} + +/*****************************************************************************/ + +static void +_agent_remove (NMAgentManager *self, NMSecretAgent *agent) +{ + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + CList *iter, *safe; + + nm_assert (NM_IS_SECRET_AGENT (agent)); + nm_assert (c_list_contains (&priv->agent_lst_head, &agent->agent_lst)); _LOGD (agent, "agent unregistered or disappeared"); + nm_clear_pointer (&agent->auth_chain, nm_auth_chain_destroy); + + c_list_unlink (&agent->agent_lst); + + g_signal_handlers_disconnect_by_func (agent, G_CALLBACK (agent_disconnected_cb), self); + /* Remove this agent from any in-progress secrets requests */ - c_list_for_each_safe (iter, safe, &priv->requests) - request_remove_agent (c_list_entry (iter, Request, lst_request), agent); + c_list_for_each_safe (iter, safe, &priv->request_lst_head) + request_remove_agent (c_list_entry (iter, Request, request_lst), agent); - /* And dispose of the agent */ - g_hash_table_remove (priv->agents, owner); - return TRUE; + g_object_unref (agent); } /* Call this *after* calling request_next_agent() */ static void -maybe_remove_agent_on_error (NMSecretAgent *agent, +maybe_remove_agent_on_error (NMAgentManager *self, + NMSecretAgent *agent, GError *error) { - if ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER)) - remove_agent (nm_agent_manager_get (), nm_secret_agent_get_dbus_owner (agent)); + if ( !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED) + && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER)) + return; + + if (!c_list_is_empty (&agent->agent_lst)) + _agent_remove (self, agent); } /*****************************************************************************/ @@ -295,70 +324,92 @@ validate_identifier (const char *identifier, GError **error) } static void -agent_register_permissions_done (NMAuthChain *chain, - GDBusMethodInvocation *context, - gpointer user_data) +_agent_permissions_check_done (NMAuthChain *chain, + GDBusMethodInvocation *context, + gpointer user_data) { NMAgentManager *self = NM_AGENT_MANAGER (user_data); NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); NMSecretAgent *agent; - const char *sender; - NMAuthCallResult result; - CList *iter; + Request *request; - nm_assert (G_IS_DBUS_METHOD_INVOCATION (context)); - - priv->chains = g_slist_remove (priv->chains, chain); + nm_assert (!context || G_IS_DBUS_METHOD_INVOCATION (context)); agent = nm_auth_chain_steal_data (chain, "agent"); - nm_assert (agent); - result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); - if (result == NM_AUTH_CALL_RESULT_YES) - nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, TRUE); + nm_assert (NM_IS_SECRET_AGENT (agent)); + nm_assert (agent->auth_chain == chain); + nm_assert (agent->fully_registered == (!context)); + nm_assert (c_list_contains (&priv->agent_lst_head, &agent->agent_lst)); - result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN); - if (result == NM_AUTH_CALL_RESULT_YES) - nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, TRUE); + agent->auth_chain = NULL; + + nm_secret_agent_add_permission (agent, + NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, + (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED) == NM_AUTH_CALL_RESULT_YES)); + nm_secret_agent_add_permission (agent, + NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, + (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN) == NM_AUTH_CALL_RESULT_YES)); + + if (agent->fully_registered) { + _LOGD (agent, "updated agent permissions"); + return; + } - priv->agent_version_id += 1; - sender = nm_secret_agent_get_dbus_owner (agent); - g_hash_table_insert (priv->agents, g_strdup (sender), agent); _LOGI (agent, "agent registered"); + + agent->fully_registered = TRUE; + + priv->agent_version_id += 1; + g_dbus_method_invocation_return_value (context, NULL); - /* Signal an agent was registered */ - g_signal_emit (self, signals[AGENT_REGISTERED], 0, agent); + c_list_for_each_entry (request, &priv->request_lst_head, request_lst) + request_add_agent (request, agent); - /* Add this agent to any in-progress secrets requests */ - c_list_for_each (iter, &priv->requests) - request_add_agent (c_list_entry (iter, Request, lst_request), agent); + g_signal_emit (self, signals[AGENT_REGISTERED], 0, agent); } -static NMSecretAgent * -find_agent_by_identifier_and_uid (NMAgentManager *self, - const char *identifier, - gulong sender_uid) +static NMAuthChain * +_agent_create_auth_chain (NMAgentManager *self, + NMSecretAgent *agent, + GDBusMethodInvocation *context) { - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - NMSecretAgent *agent; + NMAuthChain *chain; - g_hash_table_iter_init (&iter, priv->agents); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { - if ( g_strcmp0 (nm_secret_agent_get_identifier (agent), identifier) == 0 - && nm_secret_agent_get_owner_uid (agent) == sender_uid) - return agent; + _LOGD (agent, "requesting permissions"); + + nm_assert ( !agent->auth_chain + || (agent->fully_registered == (!nm_auth_chain_get_context (agent->auth_chain)))); + + if ( agent->auth_chain + && !context + && !agent->fully_registered) { + /* we restart the authorization check (without a @context), but the currently + * pending auth-chain carries a context. We need to pass it on as we replace + * the auth-chain. */ + context = nm_auth_chain_get_context (agent->auth_chain); + nm_assert (context); } - return NULL; + + chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent), + context, + _agent_permissions_check_done, + self); + + nm_auth_chain_set_data (chain, "agent", agent, NULL); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); + nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); + + nm_clear_pointer (&agent->auth_chain, nm_auth_chain_destroy); + agent->auth_chain = chain; + return chain; } static void agent_disconnected_cb (NMSecretAgent *agent, gpointer user_data) { - /* The agent quit, so remove it and let interested clients know */ - remove_agent (NM_AGENT_MANAGER (user_data), - nm_secret_agent_get_dbus_owner (agent)); + _agent_remove (NM_AGENT_MANAGER (user_data), agent); } static void @@ -368,65 +419,44 @@ agent_manager_register_with_capabilities (NMAgentManager *self, guint32 capabilities) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - NMAuthSubject *subject; + gs_unref_object NMAuthSubject *subject = NULL; gulong sender_uid = G_MAXULONG; GError *error = NULL; NMSecretAgent *agent; - NMAuthChain *chain; - subject = nm_auth_subject_new_unix_process_from_context (context); + subject = nm_dbus_manager_new_auth_subject_from_context (context); if (!subject) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN); - goto done; + g_dbus_method_invocation_take_error (context, error); + return; } sender_uid = nm_auth_subject_get_unix_process_uid (subject); /* Validate the identifier */ - if (!validate_identifier (identifier, &error)) - goto done; + if (!validate_identifier (identifier, &error)) { + g_dbus_method_invocation_take_error (context, error); + return; + } /* Only one agent for each identifier is allowed per user */ - if (find_agent_by_identifier_and_uid (self, identifier, sender_uid)) { + if (_agent_find_by_identifier_and_uid (priv, identifier, sender_uid)) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, "An agent with this ID is already registered for this user."); - goto done; + g_dbus_method_invocation_take_error (context, error); + return; } - /* Success, add the new agent */ agent = nm_secret_agent_new (context, subject, identifier, capabilities); - if (!agent) { - error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, - NM_AGENT_MANAGER_ERROR_FAILED, - "Failed to initialize the agent"); - goto done; - } + g_signal_connect (agent, NM_SECRET_AGENT_DISCONNECTED, G_CALLBACK (agent_disconnected_cb), self); - _LOGD (agent, "requesting permissions"); - - /* Kick off permissions requests for this agent */ - chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self); - if (chain) { - nm_auth_chain_set_data (chain, "agent", agent, g_object_unref); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); + c_list_link_tail (&priv->agent_lst_head, &agent->agent_lst); - priv->chains = g_slist_append (priv->chains, chain); - } else { - g_object_unref (agent); - error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, - NM_AGENT_MANAGER_ERROR_FAILED, - "Unable to start agent authentication."); - } - -done: - if (error) - g_dbus_method_invocation_take_error (context, error); - g_clear_object (&subject); + _agent_create_auth_chain (self, agent, context); } static void @@ -470,8 +500,11 @@ impl_agent_manager_unregister (NMDBusObject *obj, GVariant *parameters) { NMAgentManager *self = NM_AGENT_MANAGER (obj); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + NMSecretAgent *agent; - if (!remove_agent (self, sender)) { + agent = _agent_find_by_owner (priv, sender); + if (!agent) { g_dbus_method_invocation_return_error_literal (invocation, NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_NOT_REGISTERED, @@ -479,6 +512,8 @@ impl_agent_manager_unregister (NMDBusObject *obj, return; } + _agent_remove (self, agent); + g_dbus_method_invocation_return_value (invocation, NULL); } @@ -497,7 +532,7 @@ request_new (NMAgentManager *self, req->request_type = request_type; req->detail = g_strdup (detail); req->subject = g_object_ref (subject); - c_list_link_tail (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &req->lst_request); + c_list_link_tail (&NM_AGENT_MANAGER_GET_PRIVATE (self)->request_lst_head, &req->request_lst); return req; } @@ -583,7 +618,7 @@ req_complete_cancel (Request *req, gboolean is_disposing) gs_free_error GError *error = NULL; nm_assert (req && req->self); - nm_assert (!c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (req->self)->requests, &req->lst_request)); + nm_assert (!c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (req->self)->request_lst_head, &req->request_lst)); nm_utils_error_set_cancelled (&error, is_disposing, "NMAgentManager"); req_complete_release (req, NULL, NULL, NULL, error); @@ -598,9 +633,9 @@ req_complete (Request *req, { NMAgentManager *self = req->self; - nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &req->lst_request)); + nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->request_lst_head, &req->request_lst)); - c_list_unlink (&req->lst_request); + c_list_unlink (&req->request_lst); req_complete_release (req, secrets, agent_dbus_owner, agent_username, error); } @@ -626,7 +661,7 @@ agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data) b_pid = nm_secret_agent_get_pid (b); /* Prefer agents in the process the request came from */ - if (nm_auth_subject_is_unix_process (req->subject)) { + if (nm_auth_subject_get_subject_type (req->subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) { requester = nm_auth_subject_get_unix_process_pid (req->subject); if (a_pid != b_pid) { @@ -682,7 +717,7 @@ request_add_agent (Request *req, NMSecretAgent *agent) } /* If the request should filter agents by UID, do that now */ - if (nm_auth_subject_is_unix_process (req->subject)) { + if (nm_auth_subject_get_subject_type (req->subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) { uid_t agent_uid, subject_uid; agent_uid = nm_secret_agent_get_owner_uid (agent); @@ -710,12 +745,12 @@ static void request_add_agents (NMAgentManager *self, Request *req) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - gpointer data; + NMSecretAgent *agent; - g_hash_table_iter_init (&iter, priv->agents); - while (g_hash_table_iter_next (&iter, NULL, &data)) - request_add_agent (req, NM_SECRET_AGENT (data)); + c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) { + if (agent->fully_registered) + request_add_agent (req, agent); + } } static void @@ -868,7 +903,7 @@ _con_get_request_done (NMSecretAgent *agent, /* Try the next agent */ request_next_agent (req); - maybe_remove_agent_on_error (agent, error); + maybe_remove_agent_on_error (self, agent, error); } return; } @@ -1037,7 +1072,7 @@ _con_get_request_start (Request *req) NULL, _con_get_request_start_validated, req); - g_assert (req->con.chain); + nm_assert (req->con.chain); /* If the caller is the only user in the connection's permissions, then * we use the 'modify.own' permission instead of 'modify.system'. If the @@ -1188,7 +1223,6 @@ nm_agent_manager_get_secrets (NMAgentManager *self, req->con.get.callback = callback; req->con.get.callback_data = callback_data; - /* Kick off the request */ if (!(req->con.get.flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM)) request_add_agents (self, req); req->idle_id = g_idle_add (request_start, req); @@ -1203,9 +1237,9 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self, g_return_if_fail (request_id); g_return_if_fail (request_id->request_type == REQUEST_TYPE_CON_GET); - nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &request_id->lst_request)); + nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->request_lst_head, &request_id->request_lst)); - c_list_unlink (&request_id->lst_request); + c_list_unlink (&request_id->request_lst); req_complete_cancel (request_id, FALSE); } @@ -1242,7 +1276,7 @@ _con_save_request_done (NMSecretAgent *agent, LOG_REQ_ARG (req), error->message); /* Try the next agent */ request_next_agent (req); - maybe_remove_agent_on_error (agent, error); + maybe_remove_agent_on_error (self, agent, error); return; } @@ -1291,7 +1325,6 @@ nm_agent_manager_save_secrets (NMAgentManager *self, req->con.path = g_strdup (path); req->con.connection = g_object_ref (connection); - /* Kick off the request */ request_add_agents (self, req); req->idle_id = g_idle_add (request_start, req); } @@ -1333,7 +1366,7 @@ _con_del_request_done (NMSecretAgent *agent, /* Tell the next agent to delete secrets */ request_next_agent (req); if (error) - maybe_remove_agent_on_error (agent, error); + maybe_remove_agent_on_error (self, agent, error); } static void @@ -1376,27 +1409,36 @@ nm_agent_manager_delete_secrets (NMAgentManager *self, req->con.connection = g_object_ref (connection); g_object_unref (subject); - /* Kick off the request */ request_add_agents (self, req); req->idle_id = g_idle_add (request_start, req); } /*****************************************************************************/ -NMSecretAgent * -nm_agent_manager_get_agent_by_user (NMAgentManager *self, const char *username) +gboolean +nm_agent_manager_has_agent_with_permission (NMAgentManager *self, + const char *username, + const char *permission) { - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; + NMAgentManagerPrivate *priv; NMSecretAgent *agent; - g_hash_table_iter_init (&iter, priv->agents); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { - if (g_strcmp0 (nm_secret_agent_get_owner_username (agent), username) == 0) - return agent; + g_return_val_if_fail (NM_IS_AGENT_MANAGER (self), FALSE); + g_return_val_if_fail (username, FALSE); + g_return_val_if_fail (permission, FALSE); + + priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + + c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) { + if (!agent->fully_registered) + continue; + if (!nm_streq0 (nm_secret_agent_get_owner_username (agent), username)) + continue; + if (nm_secret_agent_has_permission (agent, permission)) + return TRUE; } - return NULL; + return FALSE; } /*****************************************************************************/ @@ -1407,17 +1449,16 @@ nm_agent_manager_all_agents_have_capability (NMAgentManager *manager, NMSecretAgentCapabilities capability) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (manager); - GHashTableIter iter; NMSecretAgent *agent; - gboolean subject_is_unix_process = nm_auth_subject_is_unix_process (subject); - gulong subject_uid = subject_is_unix_process ? nm_auth_subject_get_unix_process_uid (subject) : 0; + gboolean subject_is_unix_process = (nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS); + gulong subject_uid = subject_is_unix_process ? nm_auth_subject_get_unix_process_uid (subject) : 0u; - g_hash_table_iter_init (&iter, priv->agents); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { + c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) { + if (!agent->fully_registered) + continue; if ( subject_is_unix_process && nm_secret_agent_get_owner_uid (agent) != subject_uid) continue; - if (!(nm_secret_agent_get_capabilities (agent) & capability)) return FALSE; } @@ -1428,58 +1469,13 @@ nm_agent_manager_all_agents_have_capability (NMAgentManager *manager, /*****************************************************************************/ static void -agent_permissions_changed_done (NMAuthChain *chain, - GDBusMethodInvocation *context, - gpointer user_data) -{ - NMAgentManager *self = NM_AGENT_MANAGER (user_data); - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - NMSecretAgent *agent; - gboolean share_protected = FALSE, share_open = FALSE; - - priv->chains = g_slist_remove (priv->chains, chain); - - agent = nm_auth_chain_get_data (chain, "agent"); - g_assert (agent); - - _LOGD (agent, "updated agent permissions"); - - if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED) == NM_AUTH_CALL_RESULT_YES) - share_protected = TRUE; - if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN) == NM_AUTH_CALL_RESULT_YES) - share_open = TRUE; - - nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, share_protected); - nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, share_open); -} - -static void authority_changed_cb (NMAuthManager *auth_manager, NMAgentManager *self) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; NMSecretAgent *agent; - /* Recheck the permissions of all secret agents */ - g_hash_table_iter_init (&iter, priv->agents); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) { - NMAuthChain *chain; - - /* Kick off permissions requests for this agent */ - chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent), - NULL, - agent_permissions_changed_done, - self); - g_assert (chain); - priv->chains = g_slist_append (priv->chains, chain); - - /* Make sure if the agent quits while the permissions call is in progress - * that the object sticks around until our callback. - */ - nm_auth_chain_set_data (chain, "agent", g_object_ref (agent), g_object_unref); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE); - } + c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) + _agent_create_auth_chain (self, agent, NULL); } /*****************************************************************************/ @@ -1490,14 +1486,14 @@ nm_agent_manager_init (NMAgentManager *self) NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); priv->agent_version_id = 1; - c_list_init (&priv->requests); - priv->agents = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref); + c_list_init (&priv->agent_lst_head); + c_list_init (&priv->request_lst_head); } static void constructed (GObject *object) { - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE ((NMAgentManager *) object); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (object); G_OBJECT_CLASS (nm_agent_manager_parent_class)->constructed (object); @@ -1515,24 +1511,19 @@ constructed (GObject *object) static void dispose (GObject *object) { - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE ((NMAgentManager *) object); - CList *iter; - -cancel_more: - c_list_for_each (iter, &priv->requests) { - c_list_unlink (iter); - req_complete_cancel (c_list_entry (iter, Request, lst_request), TRUE); - goto cancel_more; - } - - g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_destroy); - priv->chains = NULL; + NMAgentManager *self = NM_AGENT_MANAGER (object); + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + Request *request; + NMSecretAgent *agent; - if (priv->agents) { - g_hash_table_destroy (priv->agents); - priv->agents = NULL; + while ((request = c_list_first_entry (&priv->request_lst_head, Request, request_lst))) { + c_list_unlink (&request->request_lst); + req_complete_cancel (request, TRUE); } + while ((agent = c_list_first_entry (&priv->agent_lst_head, NMSecretAgent, agent_lst))) + _agent_remove (self, agent); + if (priv->auth_mgr) { g_signal_handlers_disconnect_by_func (priv->auth_mgr, G_CALLBACK (authority_changed_cb), diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index 5200d241..bf2dcb6c 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -65,8 +65,9 @@ void nm_agent_manager_delete_secrets (NMAgentManager *manager, const char *path, NMConnection *connection); -NMSecretAgent *nm_agent_manager_get_agent_by_user (NMAgentManager *manager, - const char *username); +gboolean nm_agent_manager_has_agent_with_permission (NMAgentManager *self, + const char *username, + const char *permission); gboolean nm_agent_manager_all_agents_have_capability (NMAgentManager *manager, NMAuthSubject *subject, diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index 74bd9b2f..d7172c63 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -14,7 +14,7 @@ #include "nm-glib-aux/nm-dbus-aux.h" #include "nm-dbus-interface.h" #include "nm-core-internal.h" -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "nm-simple-connection.h" #include "NetworkManagerUtils.h" #include "c-list/src/c-list.h" @@ -34,33 +34,28 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; -typedef struct { +typedef struct _NMSecretAgentPrivate { CList permissions; + CList requests; + GDBusConnection *dbus_connection; char *description; NMAuthSubject *subject; char *identifier; char *owner_username; char *dbus_owner; - GDBusConnection *dbus_connection; GCancellable *name_owner_cancellable; - CList requests; - NMSecretAgentCapabilities capabilities; guint name_owner_changed_id; + NMSecretAgentCapabilities capabilities; bool shutdown_wait_obj_registered:1; } NMSecretAgentPrivate; -struct _NMSecretAgent { - GObject parent; - NMSecretAgentPrivate _priv; -}; - struct _NMSecretAgentClass { GObjectClass parent; }; G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) -#define NM_SECRET_AGENT_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSecretAgent, NM_IS_SECRET_AGENT) +#define NM_SECRET_AGENT_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR (self, NMSecretAgent, NM_IS_SECRET_AGENT) /*****************************************************************************/ @@ -112,7 +107,8 @@ G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) /*****************************************************************************/ -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_capabilities_to_string, NMSecretAgentCapabilities, +static +NM_UTILS_FLAGS2STR_DEFINE (_capabilities_to_string, NMSecretAgentCapabilities, NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_NONE, "none"), NM_UTILS_FLAGS2STR (NM_SECRET_AGENT_CAPABILITY_VPN_HINTS, "vpn-hints"), ); @@ -375,7 +371,7 @@ _dbus_call_cb (GObject *source, ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if ( !ret - && nm_utils_error_is_cancelled (error, FALSE)) + && nm_utils_error_is_cancelled (error)) return; call_id = user_data; @@ -709,7 +705,8 @@ nm_secret_agent_new (GDBusMethodInvocation *context, g_return_val_if_fail (context != NULL, NULL); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - g_return_val_if_fail (nm_auth_subject_is_unix_process (subject), NULL); + g_return_val_if_fail (nm_auth_subject_get_subject_type (subject) + == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL); g_return_val_if_fail (identifier != NULL, NULL); dbus_connection = g_dbus_method_invocation_get_connection (context); @@ -764,8 +761,13 @@ nm_secret_agent_new (GDBusMethodInvocation *context, static void nm_secret_agent_init (NMSecretAgent *self) { - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + NMSecretAgentPrivate *priv; + priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_SECRET_AGENT, NMSecretAgentPrivate); + + self->_priv = priv; + + c_list_init (&self->agent_lst); c_list_init (&priv->permissions); c_list_init (&priv->requests); } @@ -776,6 +778,8 @@ dispose (GObject *object) NMSecretAgent *self = NM_SECRET_AGENT (object); NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + nm_assert (c_list_is_empty (&self->agent_lst)); + nm_assert (!self->auth_chain); nm_assert (c_list_is_empty (&priv->requests)); nm_clear_g_dbus_connection_signal (priv->dbus_connection, @@ -813,6 +817,8 @@ nm_secret_agent_class_init (NMSecretAgentClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); + g_type_class_add_private (object_class, sizeof (NMSecretAgentPrivate)); + object_class->dispose = dispose; object_class->finalize = finalize; diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h index ea86e432..37a93d17 100644 --- a/src/settings/nm-secret-agent.h +++ b/src/settings/nm-secret-agent.h @@ -8,6 +8,8 @@ #include "nm-connection.h" +#include "c-list/src/c-list.h" + #define NM_TYPE_SECRET_AGENT (nm_secret_agent_get_type ()) #define NM_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent)) #define NM_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) @@ -20,6 +22,17 @@ typedef struct _NMSecretAgentClass NMSecretAgentClass; typedef struct _NMSecretAgentCallId NMSecretAgentCallId; +struct _NMAuthChain; +struct _NMSecretAgentPrivate; + +struct _NMSecretAgent { + GObject parent; + CList agent_lst; + struct _NMAuthChain *auth_chain; + struct _NMSecretAgentPrivate *_priv; + bool fully_registered:1; +}; + GType nm_secret_agent_get_type (void); NMSecretAgent *nm_secret_agent_new (GDBusMethodInvocation *context, diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index ccbab807..48e3dce2 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -18,12 +18,12 @@ #include "nm-session-monitor.h" #include "nm-auth-manager.h" #include "nm-auth-utils.h" -#include "nm-auth-subject.h" #include "nm-agent-manager.h" #include "NetworkManagerUtils.h" #include "nm-core-internal.h" #include "nm-audit-manager.h" #include "nm-settings.h" +#include "nm-dbus-manager.h" #include "settings/plugins/keyfile/nms-keyfile-storage.h" #define AUTOCONNECT_RETRIES_UNSET -2 @@ -409,10 +409,7 @@ nm_settings_connection_check_permission (NMSettingsConnection *self, * either. */ if (nm_setting_connection_get_permission (s_con, i, NULL, &puser, NULL)) { - NMSecretAgent *agent = nm_agent_manager_get_agent_by_user (priv->agent_mgr, puser); - - if ( agent - && nm_secret_agent_has_permission (agent, permission)) + if (nm_agent_manager_has_agent_with_permission (priv->agent_mgr, puser, permission)) return TRUE; } } @@ -1249,7 +1246,7 @@ _new_auth_subject (GDBusMethodInvocation *context, GError **error) { NMAuthSubject *subject; - subject = nm_auth_subject_new_unix_process_from_context (context); + subject = nm_dbus_manager_new_auth_subject_from_context (context); if (!subject) { g_set_error_literal (error, NM_SETTINGS_ERROR, @@ -1971,7 +1968,8 @@ _nm_settings_connection_emit_signal_updated_internal (NMSettingsConnection *self /*****************************************************************************/ -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_settings_connection_flags_to_string, NMSettingsConnectionIntFlags, +static +NM_UTILS_FLAGS2STR_DEFINE (_settings_connection_flags_to_string, NMSettingsConnectionIntFlags, NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, "none"), NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_INT_FLAGS_UNSAVED, "unsaved"), NM_UTILS_FLAGS2STR (NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED, "nm-generated"), @@ -2365,7 +2363,7 @@ _autoconnect_retries_set (NMSettingsConnection *self, * the tracking of resetting the retry count in NMPolicy needs adjustment * in _connection_autoconnect_retries_set() (as it would need to re-evaluate * the next-timeout every time a connection gets blocked). */ - priv->autoconnect_retries_blocked_until = nm_utils_get_monotonic_timestamp_s () + AUTOCONNECT_RESET_RETRIES_TIMER; + priv->autoconnect_retries_blocked_until = nm_utils_get_monotonic_timestamp_sec () + AUTOCONNECT_RESET_RETRIES_TIMER; } } @@ -2416,7 +2414,8 @@ nm_settings_connection_autoconnect_retries_blocked_until (NMSettingsConnection * return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->autoconnect_retries_blocked_until; } -NM_UTILS_FLAGS2STR_DEFINE_STATIC (_autoconnect_blocked_reason_to_string, NMSettingsAutoconnectBlockedReason, +static +NM_UTILS_FLAGS2STR_DEFINE (_autoconnect_blocked_reason_to_string, NMSettingsAutoconnectBlockedReason, NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, "none"), NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, "user-request"), NM_UTILS_FLAGS2STR (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, "failed"), @@ -2612,14 +2611,14 @@ dispose (GObject *object) nm_clear_pointer (&priv->system_secrets, g_variant_unref); nm_clear_pointer (&priv->agent_secrets, g_variant_unref); - g_clear_pointer (&priv->seen_bssids, g_hash_table_destroy); + nm_clear_pointer (&priv->seen_bssids, g_hash_table_destroy); g_clear_object (&priv->agent_mgr); g_clear_object (&priv->connection); - g_clear_pointer (&priv->kf_db_timestamps, nm_key_file_db_unref); - g_clear_pointer (&priv->kf_db_seen_bssids, nm_key_file_db_unref); + nm_clear_pointer (&priv->kf_db_timestamps, nm_key_file_db_unref); + nm_clear_pointer (&priv->kf_db_seen_bssids, nm_key_file_db_unref); G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index f964fb16..874efbfc 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -22,7 +22,7 @@ #include "nm-libnm-core-intern/nm-common-macros.h" #include "nm-glib-aux/nm-keyfile-aux.h" -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" #include "nm-dbus-interface.h" #include "nm-connection.h" #include "nm-setting-8021x.h" @@ -54,7 +54,7 @@ #include "nm-settings-plugin.h" #include "nm-dbus-manager.h" #include "nm-auth-utils.h" -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "nm-session-monitor.h" #include "plugins/keyfile/nms-keyfile-plugin.h" #include "plugins/keyfile/nms-keyfile-storage.h" @@ -67,7 +67,11 @@ /*****************************************************************************/ -static NM_CACHED_QUARK_FCN ("default-wired-connection", _default_wired_connection_quark) +static +NM_CACHED_QUARK_FCN ("default-wired-connection", _default_wired_connection_quark) + +static +NM_CACHED_QUARK_FCN ("default-wired-connection-blocked", _default_wired_connection_blocked_quark) /*****************************************************************************/ @@ -548,7 +552,7 @@ _startup_complete_check (NMSettings *self, goto ready; if (!now_us) - now_us = nm_utils_get_monotonic_timestamp_us (); + now_us = nm_utils_get_monotonic_timestamp_usec (); next_expiry = 0; @@ -654,7 +658,7 @@ _startup_complete_notify_connection (NMSettings *self, } else scd = g_hash_table_lookup (priv->startup_complete_idx, &sett_conn); if (!scd) { - now_us = nm_utils_get_monotonic_timestamp_us (); + now_us = nm_utils_get_monotonic_timestamp_usec (); scd = g_slice_new (StartupCompleteData); *scd = (StartupCompleteData) { .sett_conn = g_object_ref (sett_conn), @@ -2574,7 +2578,7 @@ settings_add_connection_helper (NMSettings *self, return; } - subject = nm_auth_subject_new_unix_process_from_context (context); + subject = nm_dbus_manager_new_auth_subject_from_context (context); if (!subject) { g_dbus_method_invocation_return_error_literal (context, NM_SETTINGS_ERROR, @@ -2918,7 +2922,7 @@ impl_settings_get_connection_by_uuid (NMDBusObject *obj, goto error; } - subject = nm_auth_subject_new_unix_process_from_context (invocation); + subject = nm_dbus_manager_new_auth_subject_from_context (invocation); if (!subject) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, @@ -3431,9 +3435,13 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self) */ if ( !NM_DEVICE_GET_CLASS (device)->new_default_connection || !nm_device_get_managed (device, FALSE) - || g_object_get_qdata (G_OBJECT (device), _default_wired_connection_quark ())) + || g_object_get_qdata (G_OBJECT (device), _default_wired_connection_blocked_quark ())) return; + /* we only check once whether to create the auto-default connection. If we reach this point, + * we mark the creation of the default-wired-connection as blocked. */ + g_object_set_qdata (G_OBJECT (device), _default_wired_connection_blocked_quark (), device); + if (nm_config_get_no_auto_default_for_device (priv->config, device)) { _LOGT ("auto-default: cannot create auto-default connection for device %s: disabled by \"no-auto-default\"", nm_device_get_iface (device)); diff --git a/src/settings/plugins/ifcfg-rh/meson.build b/src/settings/plugins/ifcfg-rh/meson.build index d9dd3edb..e193ff96 100644 --- a/src/settings/plugins/ifcfg-rh/meson.build +++ b/src/settings/plugins/ifcfg-rh/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + install_data( 'nm-ifcfg-rh.conf', install_dir: dbus_conf_dir, diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index f57ca1a7..f5c9bb5e 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -20,6 +20,7 @@ #include "nm-utils.h" #include "nm-core-internal.h" #include "nm-config.h" +#include "nm-dbus-manager.h" #include "settings/nm-settings-plugin.h" #include "settings/nm-settings-utils.h" #include "NetworkManagerUtils.h" @@ -205,9 +206,9 @@ _load_file (NMSIfcfgRHPlugin *self, const char *unmanaged_spec; const char *unrecognized_spec; - if (!nms_ifcfg_rh_util_parse_unhandled_spec (unhandled_spec, - &unmanaged_spec, - &unrecognized_spec)) { + if (!nms_ifcfg_rh_utils_parse_unhandled_spec (unhandled_spec, + &unmanaged_spec, + &unrecognized_spec)) { nm_utils_error_set (error, NM_UTILS_ERROR_UNKNOWN, "invalid unhandled spec \"%s\"", unhandled_spec); @@ -1132,6 +1133,13 @@ _dbus_setup (NMSIfcfgRHPlugin *self) _dbus_clear (self); + if (!NM_MAIN_DBUS_CONNECTION_GET) { + _LOGW ("dbus: don't use D-Bus for %s service", IFCFGRH1_BUS_NAME); + return; + } + + /* We use a separate D-Bus connection so that org.freedesktop.NetworkManager and com.redhat.ifcfgrh1 + * are exported by different connections. */ address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (address == NULL) { _LOGW ("dbus: failed getting address for system bus: %s", error->message); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index e01f7344..8e153412 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -399,7 +399,9 @@ make_connection_setting (const char *file, if (v) { GError *error = NULL; - if (nm_utils_ifname_valid_kernel (v, &error)) { + /* Only validate for NMU_IFACE_KERNEL, because ifcfg plugin anyway + * doesn't support OVS types. */ + if (nm_utils_ifname_valid (v, NMU_IFACE_KERNEL, &error)) { g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, v, NULL); @@ -502,6 +504,24 @@ make_connection_setting (const char *file, } nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "VRF_UUID", &value); + if (!v) + v = svGetValueStr (ifcfg, "VRF", &value); + if (v) { + const char *old_value; + + if ((old_value = nm_setting_connection_get_master (s_con))) { + PARSE_WARNING ("Already configured as slave of %s. Ignoring VRF{_UUID}=\"%s\"", + old_value, v); + } else { + g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, v, NULL); + g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, + NM_SETTING_VRF_SETTING_NAME, NULL); + } + } + + + nm_clear_g_free (&value); v = svGetValueStr (ifcfg, "GATEWAY_PING_TIMEOUT", &value); if (v) { gint64 tmp; @@ -530,16 +550,18 @@ make_connection_setting (const char *file, g_object_set (s_con, NM_SETTING_CONNECTION_AUTH_RETRIES, (int) vint64, NULL); nm_clear_g_free (&value); - v = svGetValueStr (ifcfg, "DEVTIMEOUT", &value); + v = svGetValue (ifcfg, "DEVTIMEOUT", &value); if (v) { + v = nm_str_skip_leading_spaces (v); vint64 = _nm_utils_ascii_str_to_int64 (v, 10, 0, ((gint64) G_MAXINT32) / 1000, -1); if (vint64 != -1) vint64 *= 1000; - else { + else if (v[0] != '\0') { char *endptr; double d; - d = g_ascii_strtod (v, &endptr); + d = nm_g_ascii_strtod (v, &endptr); + endptr = nm_str_skip_leading_spaces (endptr); if ( errno == 0 && endptr[0] == '\0' && d >= 0.0) { @@ -709,7 +731,7 @@ read_full_ip4_address (shvarFile *ifcfg, else { /* Try to autodetermine the prefix for the address' class */ prefix = _nm_utils_ip4_get_default_prefix (ipaddr); - PARSE_WARNING ("missing %s, assuming %s/%d", prefix_tag, nm_utils_inet4_ntop (ipaddr, inet_buf), prefix); + PARSE_WARNING ("missing %s, assuming %s/%d", prefix_tag, _nm_utils_inet4_ntop (ipaddr, inet_buf), prefix); } } } @@ -1287,7 +1309,7 @@ read_one_ip4_route (shvarFile *ifcfg, prefix = nm_utils_ip4_netmask_to_prefix (netmask); if (netmask != _nm_utils_ip4_prefix_to_netmask (prefix)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, nm_utils_inet4_ntop (netmask, inet_buf)); + "Invalid IP4 netmask '%s' \"%s\"", netmask_tag, _nm_utils_inet4_ntop (netmask, inet_buf)); return FALSE; } } else { @@ -1318,7 +1340,7 @@ read_one_ip4_route (shvarFile *ifcfg, v = svGetValueStr (ifcfg, numbered_tag (tag, "OPTIONS", which), &value); if (v) { if (parse_route_line (v, AF_INET, *out_route, NULL, error) < 0) { - g_clear_pointer (out_route, nm_ip_route_unref); + nm_clear_pointer (out_route, nm_ip_route_unref); return FALSE; } } @@ -1327,39 +1349,40 @@ read_one_ip4_route (shvarFile *ifcfg, } static gboolean -read_route_file (int addr_family, - const char *filename, - NMSettingIPConfig *s_ip, - GError **error) +read_route_file_parse (int addr_family, + const char *filename, + const char *contents, + gsize len, + NMSettingIPConfig *s_ip, + GError **error) { - gs_free char *contents = NULL; - char *contents_rest = NULL; - const char *line; - gsize len = 0; gsize line_num; - g_return_val_if_fail (filename, FALSE); - g_return_val_if_fail ( (addr_family == AF_INET && NM_IS_SETTING_IP4_CONFIG (s_ip)) - || (addr_family == AF_INET6 && NM_IS_SETTING_IP6_CONFIG (s_ip)), FALSE); - g_return_val_if_fail (!error || !*error, FALSE); + nm_assert (filename); + nm_assert (addr_family == nm_setting_ip_config_get_addr_family (s_ip)); + nm_assert (!error || !*error); - if ( !g_file_get_contents (filename, &contents, &len, NULL) - || !len) { + if (len <= 0) return TRUE; /* missing/empty = success */ - } line_num = 0; - for (line = strtok_r (contents, "\n", &contents_rest); - line; - line = strtok_r (NULL, "\n", &contents_rest)) { + while (TRUE) { nm_auto_unref_ip_route NMIPRoute *route = NULL; gs_free_error GError *local = NULL; + const char *line = contents; + char *eol; int e; + eol = strchr (contents, '\n'); + if (eol) { + eol[0] = '\0'; + contents = &eol[1]; + } + line_num++; if (parse_route_line_is_comment (line)) - continue; + goto next; e = parse_route_line (line, addr_family, NULL, &route, &local); @@ -1371,14 +1394,38 @@ read_route_file (int addr_family, * entire connection. */ PARSE_WARNING ("ignoring invalid route at \"%s\" (%s:%lu): %s", line, filename, (long unsigned) line_num, local->message); } - continue; + goto next; } if (!nm_setting_ip_config_add_route (s_ip, route)) PARSE_WARNING ("duplicate IPv%c route", addr_family == AF_INET ? '4' : '6'); + +next: + if (!eol) + return TRUE; + + /* restore original content. */ + eol[0] = '\n'; } +} - return TRUE; +static gboolean +read_route_file (int addr_family, + const char *filename, + NMSettingIPConfig *s_ip, + GError **error) +{ + gs_free char *contents = NULL; + gsize len; + + nm_assert (filename); + nm_assert (addr_family == nm_setting_ip_config_get_addr_family (s_ip)); + nm_assert (!error || !*error); + + if (!g_file_get_contents (filename, &contents, &len, NULL)) + return TRUE; /* missing/empty = success */ + + return read_route_file_parse (addr_family, filename, contents, len, s_ip, error); } static void @@ -1577,7 +1624,6 @@ make_ip4_setting (shvarFile *ifcfg, int i; guint32 a; gboolean has_key; - shvarFile *route_ifcfg; gboolean never_default; gint64 i64; int priority; @@ -1771,10 +1817,10 @@ make_ip4_setting (shvarFile *ifcfg, nm_clear_g_free (&value); v = svGetValueStr (ifcfg, tag, &value); if (v) { - if (nm_utils_ipaddr_valid (AF_INET, v)) { + if (nm_utils_ipaddr_is_valid (AF_INET, v)) { if (!nm_setting_ip_config_add_dns (s_ip4, v)) PARSE_WARNING ("duplicate DNS server %s", tag); - } else if (nm_utils_ipaddr_valid (AF_INET6, v)) { + } else if (nm_utils_ipaddr_is_valid (AF_INET6, v)) { /* Ignore IPv6 addresses */ } else { PARSE_WARNING ("invalid DNS server address %s", v); @@ -1814,32 +1860,34 @@ make_ip4_setting (shvarFile *ifcfg, /* Static routes - route-<name> file */ route_path = utils_get_route_path (svFileGetName (ifcfg)); - if (!routes_read) { - /* NOP */ - } else if (utils_has_route_file_new_syntax (route_path)) { - /* Parse route file in new syntax */ - route_ifcfg = utils_get_route_ifcfg (svFileGetName (ifcfg), FALSE); - if (route_ifcfg) { + if (routes_read) { + gs_free char *contents = NULL; + gsize len; + + if (!g_file_get_contents (route_path, &contents, &len, NULL)) + len = 0; + + if (utils_has_route_file_new_syntax_content (contents, len)) { + nm_auto_shvar_file_close shvarFile *route_ifcfg = NULL; + + /* Parse route file in new syntax */ + route_ifcfg = svFile_new (route_path, -1, contents); for (i = 0;; i++) { - NMIPRoute *route = NULL; + nm_auto_unref_ip_route NMIPRoute *route = NULL; - if (!read_one_ip4_route (route_ifcfg, i, &route, error)) { - svCloseFile (route_ifcfg); + if (!read_one_ip4_route (route_ifcfg, i, &route, error)) return NULL; - } if (!route) break; if (!nm_setting_ip_config_add_route (s_ip4, route)) PARSE_WARNING ("duplicate IP4 route"); - nm_ip_route_unref (route); } - svCloseFile (route_ifcfg); + } else { + if (!read_route_file_parse (AF_INET, route_path, contents, len, s_ip4, error)) + return NULL; } - } else { - if (!read_route_file (AF_INET, route_path, s_ip4, error)) - return NULL; } /* Legacy value NM used for a while but is incorrect (rh #459370) */ @@ -2214,7 +2262,7 @@ make_ip6_setting (shvarFile *ifcfg, char *ptr; if ((ptr = strchr (v, '%')) != NULL) *ptr = '\0'; /* remove %interface prefix if present */ - if (!nm_utils_ipaddr_valid (AF_INET6, v)) { + if (!nm_utils_ipaddr_is_valid (AF_INET6, v)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IP6 address '%s'", v); return NULL; @@ -2253,10 +2301,10 @@ make_ip6_setting (shvarFile *ifcfg, break; } - if (nm_utils_ipaddr_valid (AF_INET6, v)) { + if (nm_utils_ipaddr_is_valid (AF_INET6, v)) { if (!nm_setting_ip_config_add_dns (s_ip6, v)) PARSE_WARNING ("duplicate DNS server %s", tag); - } else if (nm_utils_ipaddr_valid (AF_INET, v)) { + } else if (nm_utils_ipaddr_is_valid (AF_INET, v)) { /* Ignore IPv4 addresses */ } else { PARSE_WARNING ("invalid DNS server address %s", v); @@ -3623,6 +3671,14 @@ next: v = svGetValueStr (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH", &value); g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH, v, NULL); + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_DOMAIN_MATCH", &value); + g_object_set (s_8021x, NM_SETTING_802_1X_DOMAIN_MATCH, v, NULL); + + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_MATCH", &value); + g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_DOMAIN_MATCH, v, NULL); + timeout = svGetValueInt64 (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", 10, 0, G_MAXINT32, 0); g_object_set (s_8021x, NM_SETTING_802_1X_AUTH_TIMEOUT, (int) timeout, NULL); @@ -3645,7 +3701,7 @@ make_wpa_setting (shvarFile *ifcfg, gs_unref_object NMSettingWirelessSecurity *wsec = NULL; gs_free char *value = NULL; const char *v; - gboolean wpa_psk = FALSE, wpa_sae = FALSE, wpa_eap = FALSE, ieee8021x = FALSE; + gboolean wpa_psk = FALSE, wpa_sae = FALSE, wpa_owe = FALSE, wpa_eap = FALSE, ieee8021x = FALSE; int i_val; GError *local = NULL; @@ -3654,10 +3710,12 @@ make_wpa_setting (shvarFile *ifcfg, v = svGetValueStr (ifcfg, "KEY_MGMT", &value); wpa_psk = nm_streq0 (v, "WPA-PSK"); wpa_sae = nm_streq0 (v, "SAE"); + wpa_owe = nm_streq0 (v, "OWE"); wpa_eap = nm_streq0 (v, "WPA-EAP"); ieee8021x = nm_streq0 (v, "IEEE8021X"); if ( !wpa_psk && !wpa_sae + && !wpa_owe && !wpa_eap && !ieee8021x) return NULL; /* Not WPA or Dynamic WEP */ @@ -3673,7 +3731,7 @@ make_wpa_setting (shvarFile *ifcfg, NULL); /* Pairwise and Group ciphers (only relevant for WPA/RSN) */ - if (wpa_psk || wpa_sae || wpa_eap) { + if (wpa_psk || wpa_sae || wpa_owe || wpa_eap) { fill_wpa_ciphers (ifcfg, wsec, FALSE, adhoc); fill_wpa_ciphers (ifcfg, wsec, TRUE, adhoc); } @@ -3722,7 +3780,7 @@ make_wpa_setting (shvarFile *ifcfg, g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "sae", NULL); } } else { - nm_assert (wpa_eap || ieee8021x); + nm_assert (wpa_eap || ieee8021x || wpa_owe); /* Adhoc mode is mutually exclusive with any 802.1x-based authentication */ if (adhoc) { @@ -3731,14 +3789,17 @@ make_wpa_setting (shvarFile *ifcfg, return NULL; } - *s_8021x = fill_8021x (ifcfg, file, v, TRUE, error); - if (!*s_8021x) - return NULL; - - { - gs_free char *lower = g_ascii_strdown (v, -1); + if (wpa_owe) { + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "owe", NULL); + } else { + *s_8021x = fill_8021x (ifcfg, file, v, TRUE, error); + if (!*s_8021x) + return NULL; - g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL); + { + gs_free char *lower = g_ascii_strdown (v, -1); + g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL); + } } } @@ -3782,7 +3843,7 @@ make_leap_setting (shvarFile *ifcfg, nm_clear_g_free (&value); value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); - if (!value || strcasecmp (value, "leap")) + if (!value || g_ascii_strcasecmp (value, "leap")) return NULL; /* Not LEAP */ nm_clear_g_free (&value); @@ -4339,7 +4400,7 @@ parse_ethtool_option (const char *value, i++; if (nm_utils_hwaddr_valid (opt_val, ETH_ALEN)) { - g_clear_pointer (out_password, g_free); + nm_clear_g_free (out_password); *out_password = g_strdup (opt_val); } else PARSE_WARNING ("Wake-on-LAN password '%s' is invalid", opt_val); @@ -5091,18 +5152,24 @@ handle_bridge_option (NMSetting *setting, gboolean only_with_stp; gboolean extended_bool; } m/*etadata*/[] = { - { "DELAY", NM_SETTING_BRIDGE_FORWARD_DELAY, BRIDGE_OPT_TYPE_MAIN, .only_with_stp = TRUE }, - { "priority", NM_SETTING_BRIDGE_PRIORITY, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, - { "hello_time", NM_SETTING_BRIDGE_HELLO_TIME, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, - { "max_age", NM_SETTING_BRIDGE_MAX_AGE, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, - { "ageing_time", NM_SETTING_BRIDGE_AGEING_TIME, BRIDGE_OPT_TYPE_OPTION }, - { "multicast_snooping", NM_SETTING_BRIDGE_MULTICAST_SNOOPING, BRIDGE_OPT_TYPE_OPTION }, - { "vlan_filtering", NM_SETTING_BRIDGE_VLAN_FILTERING, BRIDGE_OPT_TYPE_OPTION }, - { "default_pvid", NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID, BRIDGE_OPT_TYPE_OPTION }, - { "group_fwd_mask", NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, BRIDGE_OPT_TYPE_OPTION }, - { "priority", NM_SETTING_BRIDGE_PORT_PRIORITY, BRIDGE_OPT_TYPE_PORT_OPTION }, - { "path_cost", NM_SETTING_BRIDGE_PORT_PATH_COST, BRIDGE_OPT_TYPE_PORT_OPTION }, - { "hairpin_mode", NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, BRIDGE_OPT_TYPE_PORT_OPTION, .extended_bool = TRUE, }, + { "DELAY", NM_SETTING_BRIDGE_FORWARD_DELAY, BRIDGE_OPT_TYPE_MAIN, .only_with_stp = TRUE }, + { "priority", NM_SETTING_BRIDGE_PRIORITY, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "hello_time", NM_SETTING_BRIDGE_HELLO_TIME, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "max_age", NM_SETTING_BRIDGE_MAX_AGE, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "ageing_time", NM_SETTING_BRIDGE_AGEING_TIME, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_querier", NM_SETTING_BRIDGE_MULTICAST_QUERIER, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_query_use_ifaddr", NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_snooping", NM_SETTING_BRIDGE_MULTICAST_SNOOPING, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_router", NM_SETTING_BRIDGE_MULTICAST_ROUTER, BRIDGE_OPT_TYPE_OPTION }, + { "vlan_filtering", NM_SETTING_BRIDGE_VLAN_FILTERING, BRIDGE_OPT_TYPE_OPTION }, + { "default_pvid", NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID, BRIDGE_OPT_TYPE_OPTION }, + { "group_address", NM_SETTING_BRIDGE_GROUP_ADDRESS, BRIDGE_OPT_TYPE_OPTION }, + { "group_fwd_mask", NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, BRIDGE_OPT_TYPE_OPTION }, + { "vlan_protocol", NM_SETTING_BRIDGE_VLAN_PROTOCOL, BRIDGE_OPT_TYPE_OPTION }, + { "vlan_stats_enabled", NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, BRIDGE_OPT_TYPE_OPTION }, + { "priority", NM_SETTING_BRIDGE_PORT_PRIORITY, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "path_cost", NM_SETTING_BRIDGE_PORT_PATH_COST, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "hairpin_mode", NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, BRIDGE_OPT_TYPE_PORT_OPTION, .extended_bool = TRUE, }, }; const char *error_message = NULL; int i; @@ -5124,9 +5191,9 @@ handle_bridge_option (NMSetting *setting, switch (param_spec->value_type) { case G_TYPE_BOOLEAN: if (m[i].extended_bool) { - if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1")) + if (!g_ascii_strcasecmp (value, "on") || !g_ascii_strcasecmp (value, "yes") || !strcmp (value, "1")) v = TRUE; - else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) + else if (!g_ascii_strcasecmp (value, "off") || !g_ascii_strcasecmp (value, "no")) v = FALSE; else { error_message = "is not a boolean"; @@ -5155,6 +5222,9 @@ handle_bridge_option (NMSetting *setting, goto warn; } return; + case G_TYPE_STRING: + nm_g_object_set_property_string (G_OBJECT (setting), m[i].property_name, value, NULL); + return; default: nm_assert_not_reached (); continue; @@ -5259,11 +5329,11 @@ make_bridge_setting (shvarFile *ifcfg, value = svGetValueStr (ifcfg, "STP", &value_to_free); if (value) { - if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) { + if (!g_ascii_strcasecmp (value, "on") || !g_ascii_strcasecmp (value, "yes")) { g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL); stp = TRUE; stp_set = TRUE; - } else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) { + } else if (!g_ascii_strcasecmp (value, "off") || !g_ascii_strcasecmp (value, "no")) { g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL); stp_set = TRUE; } else @@ -5774,9 +5844,9 @@ connection_from_file_full (const char *filename, devtype = svGetValueStr_cp (main_ifcfg, "DEVICETYPE"); if (devtype) { - if (!strcasecmp (devtype, TYPE_TEAM)) + if (!g_ascii_strcasecmp (devtype, TYPE_TEAM)) type = g_strdup (TYPE_TEAM); - else if (!strcasecmp (devtype, TYPE_TEAM_PORT)) { + else if (!g_ascii_strcasecmp (devtype, TYPE_TEAM_PORT)) { gs_free char *device = NULL; type = svGetValueStr_cp (main_ifcfg, "TYPE"); @@ -5910,26 +5980,26 @@ connection_from_file_full (const char *filename, } if (svGetValueBoolean (main_ifcfg, "BONDING_MASTER", FALSE) && - strcasecmp (type, TYPE_BOND)) { + g_ascii_strcasecmp (type, TYPE_BOND)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "BONDING_MASTER=yes key only allowed in TYPE=bond connections"); return NULL; } /* Construct the connection */ - if (!strcasecmp (type, TYPE_ETHERNET)) + if (!g_ascii_strcasecmp (type, TYPE_ETHERNET)) connection = wired_connection_from_ifcfg (filename, main_ifcfg, error); - else if (!strcasecmp (type, TYPE_WIRELESS)) + else if (!g_ascii_strcasecmp (type, TYPE_WIRELESS)) connection = wireless_connection_from_ifcfg (filename, main_ifcfg, error); - else if (!strcasecmp (type, TYPE_INFINIBAND)) + else if (!g_ascii_strcasecmp (type, TYPE_INFINIBAND)) connection = infiniband_connection_from_ifcfg (filename, main_ifcfg, error); - else if (!strcasecmp (type, TYPE_BOND)) + else if (!g_ascii_strcasecmp (type, TYPE_BOND)) connection = bond_connection_from_ifcfg (filename, main_ifcfg, error); - else if (!strcasecmp (type, TYPE_TEAM)) + else if (!g_ascii_strcasecmp (type, TYPE_TEAM)) connection = team_connection_from_ifcfg (filename, main_ifcfg, error); - else if (!strcasecmp (type, TYPE_VLAN)) + else if (!g_ascii_strcasecmp (type, TYPE_VLAN)) connection = vlan_connection_from_ifcfg (filename, main_ifcfg, error); - else if (!strcasecmp (type, TYPE_BRIDGE)) + else if (!g_ascii_strcasecmp (type, TYPE_BRIDGE)) connection = bridge_connection_from_ifcfg (filename, main_ifcfg, error); else { connection = create_unhandled_connection (filename, main_ifcfg, "unrecognized", out_unhandled); diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index ee389bd9..28f57f50 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -17,9 +17,9 @@ /*****************************************************************************/ gboolean -nms_ifcfg_rh_util_parse_unhandled_spec (const char *unhandled_spec, - const char **out_unmanaged_spec, - const char **out_unrecognized_spec) +nms_ifcfg_rh_utils_parse_unhandled_spec (const char *unhandled_spec, + const char **out_unmanaged_spec, + const char **out_unrecognized_spec) { if (unhandled_spec) { if (NM_STR_HAS_PREFIX (unhandled_spec, "unmanaged:")) { @@ -72,7 +72,7 @@ check_suffix (const char *base, const char *tag) len = strlen (base); tag_len = strlen (tag); - if ((len > tag_len) && !strcasecmp (base + len - tag_len, tag)) + if ((len > tag_len) && !g_ascii_strcasecmp (base + len - tag_len, tag)) return TRUE; return FALSE; } @@ -260,27 +260,60 @@ utils_get_route_ifcfg (const char *parent, gboolean should_create) gboolean utils_has_route_file_new_syntax (const char *filename) { - char *contents = NULL; - gsize len = 0; - gboolean ret = FALSE; - const char *pattern = "^[[:space:]]*ADDRESS[0-9]+="; + gs_free char *contents_data = NULL; + gsize len; g_return_val_if_fail (filename != NULL, TRUE); - if (!g_file_get_contents (filename, &contents, &len, NULL)) + if (!g_file_get_contents (filename, &contents_data, &len, NULL)) return TRUE; - if (len <= 0) { - ret = TRUE; - goto gone; - } + return utils_has_route_file_new_syntax_content (contents_data, len); +} + +gboolean +utils_has_route_file_new_syntax_content (const char *contents, + gsize len) +{ + if (len <= 0) + return TRUE; + + while (TRUE) { + const char *line = contents; + char *eol; + gboolean found = FALSE; + + /* matches regex "^[[:space:]]*ADDRESS[0-9]+=" */ + + eol = (char *) strchr (contents, '\n'); + if (eol) { + eol[0] = '\0'; + contents = &eol[1]; + } - if (g_regex_match_simple (pattern, contents, G_REGEX_MULTILINE, 0)) - ret = TRUE; + line = nm_str_skip_leading_spaces (line); + if (NM_STR_HAS_PREFIX (line, "ADDRESS")) { + line += NM_STRLEN ("ADDRESS"); + if (g_ascii_isdigit (line[0])) { + while (g_ascii_isdigit ((++line)[0])) { + /* pass */ + } + if (line[0] == '=') + found = TRUE; + } + } + + if (eol) { + /* restore the line ending. We don't want to mangle the content from + * POV of the caller. */ + eol[0] = '\n'; + } -gone: - g_free (contents); - return ret; + if (found) + return TRUE; + if (!eol) + return FALSE; + } } gboolean @@ -546,31 +579,15 @@ const char *const _nm_ethtool_ifcfg_names[] = { ETHT_NAME (NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, "tx-vlan-stag-hw-insert"), }; -const NMEthtoolData * -nms_ifcfg_rh_utils_get_ethtool_by_name (const char *name) -{ - static const struct { - NMEthtoolID ethtool_id; - const char *kernel_name; - } kernel_names[] = { - { NM_ETHTOOL_ID_FEATURE_GRO, "rx-gro" }, - { NM_ETHTOOL_ID_FEATURE_GSO, "tx-generic-segmentation" }, - { NM_ETHTOOL_ID_FEATURE_LRO, "rx-lro" }, - { NM_ETHTOOL_ID_FEATURE_NTUPLE, "rx-ntuple-filter" }, - { NM_ETHTOOL_ID_FEATURE_RX, "rx-checksum" }, - { NM_ETHTOOL_ID_FEATURE_RXHASH, "rx-hashing" }, - { NM_ETHTOOL_ID_FEATURE_RXVLAN, "rx-vlan-hw-parse" }, - { NM_ETHTOOL_ID_FEATURE_TXVLAN, "tx-vlan-hw-insert" }, - }; - guint i; - - for (i = 0; i < G_N_ELEMENTS (_nm_ethtool_ifcfg_names); i++) { - if (nm_streq (name, _nm_ethtool_ifcfg_names[i])) - return nm_ethtool_data[i]; - } +static +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE ( + _get_ethtoolid_by_name, + NMEthtoolID, + { nm_assert (name); }, + { return NM_ETHTOOL_ID_UNKNOWN; }, - /* Option not found. Note that ethtool utility has built-in features and - * NetworkManager's API follows the naming of these built-in features, whenever + /* Map the names from kernel/ethtool/ifcfg to NMEthtoolID. Note that ethtool utility has built-in + * features and NetworkManager's API follows the naming of these built-in features, whenever * they exist. * For example, NM's "ethtool.feature-ntuple" corresponds to ethtool utility's "ntuple" * feature. However the underlying kernel feature is called "rx-ntuple-filter" (as reported @@ -578,10 +595,430 @@ nms_ifcfg_rh_utils_get_ethtool_by_name (const char *name) * * With ethtool utility, whose command line we attempt to parse here, the user can also * specify the name of the underlying kernel feature directly. So, check whether that is - * the case and if yes, map them to the corresponding NetworkManager's features. */ - for (i = 0; i < G_N_ELEMENTS (kernel_names); i++) { - if (nm_streq (name, kernel_names[i].kernel_name)) - return nm_ethtool_data[kernel_names[i].ethtool_id]; + * the case and if yes, map them to the corresponding NetworkManager's features. + * + * That is why there are duplicate IDs in this list. */ + { "esp-hw-offload", NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD }, + { "esp-tx-csum-hw-offload", NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD }, + { "fcoe-mtu", NM_ETHTOOL_ID_FEATURE_FCOE_MTU }, + { "gro", NM_ETHTOOL_ID_FEATURE_GRO }, + { "gso", NM_ETHTOOL_ID_FEATURE_GSO }, + { "highdma", NM_ETHTOOL_ID_FEATURE_HIGHDMA }, + { "hw-tc-offload", NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD }, + { "l2-fwd-offload", NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD }, + { "loopback", NM_ETHTOOL_ID_FEATURE_LOOPBACK }, + { "lro", NM_ETHTOOL_ID_FEATURE_LRO }, + { "ntuple", NM_ETHTOOL_ID_FEATURE_NTUPLE }, + { "rx", NM_ETHTOOL_ID_FEATURE_RX }, + { "rx-all", NM_ETHTOOL_ID_FEATURE_RX_ALL }, + { "rx-checksum", NM_ETHTOOL_ID_FEATURE_RX }, // kernel-only name + { "rx-fcs", NM_ETHTOOL_ID_FEATURE_RX_FCS }, + { "rx-gro", NM_ETHTOOL_ID_FEATURE_GRO }, // kernel-only name + { "rx-gro-hw", NM_ETHTOOL_ID_FEATURE_RX_GRO_HW }, + { "rx-hashing", NM_ETHTOOL_ID_FEATURE_RXHASH }, // kernel-only name + { "rx-lro", NM_ETHTOOL_ID_FEATURE_LRO }, // kernel-only name + { "rx-ntuple-filter", NM_ETHTOOL_ID_FEATURE_NTUPLE }, // kernel-only name + { "rx-udp_tunnel-port-offload", NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD }, + { "rx-vlan-filter", NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER }, + { "rx-vlan-hw-parse", NM_ETHTOOL_ID_FEATURE_RXVLAN }, // kernel-only name + { "rx-vlan-stag-filter", NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER }, + { "rx-vlan-stag-hw-parse", NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE }, + { "rxhash", NM_ETHTOOL_ID_FEATURE_RXHASH }, + { "rxvlan", NM_ETHTOOL_ID_FEATURE_RXVLAN }, + { "sg", NM_ETHTOOL_ID_FEATURE_SG }, + { "tls-hw-record", NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD }, + { "tls-hw-tx-offload", NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD }, + { "tso", NM_ETHTOOL_ID_FEATURE_TSO }, + { "tx", NM_ETHTOOL_ID_FEATURE_TX }, + { "tx-checksum-fcoe-crc", NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC }, + { "tx-checksum-ip-generic", NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC }, + { "tx-checksum-ipv4", NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4 }, + { "tx-checksum-ipv6", NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6 }, + { "tx-checksum-sctp", NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP }, + { "tx-esp-segmentation", NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION }, + { "tx-fcoe-segmentation", NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION }, + { "tx-generic-segmentation", NM_ETHTOOL_ID_FEATURE_GSO }, // kernel-only name + { "tx-gre-csum-segmentation", NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION }, + { "tx-gre-segmentation", NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION }, + { "tx-gso-partial", NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL }, + { "tx-gso-robust", NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST }, + { "tx-ipxip4-segmentation", NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION }, + { "tx-ipxip6-segmentation", NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION }, + { "tx-nocache-copy", NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY }, + { "tx-scatter-gather", NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER }, + { "tx-scatter-gather-fraglist", NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST }, + { "tx-sctp-segmentation", NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION }, + { "tx-tcp-ecn-segmentation", NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION }, + { "tx-tcp-mangleid-segmentation", NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION }, + { "tx-tcp-segmentation", NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION }, + { "tx-tcp6-segmentation", NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION }, + { "tx-udp-segmentation", NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION }, + { "tx-udp_tnl-csum-segmentation", NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION }, + { "tx-udp_tnl-segmentation", NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION }, + { "tx-vlan-hw-insert", NM_ETHTOOL_ID_FEATURE_TXVLAN }, // kernel-only name + { "tx-vlan-stag-hw-insert", NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT }, + { "txvlan", NM_ETHTOOL_ID_FEATURE_TXVLAN }, +); + +const NMEthtoolData * +nms_ifcfg_rh_utils_get_ethtool_by_name (const char *name) +{ + NMEthtoolID id; + + id = _get_ethtoolid_by_name (name); + if (id == NM_ETHTOOL_ID_UNKNOWN) + return NULL; + + nm_assert (_NM_INT_NOT_NEGATIVE (id)); + nm_assert (id < G_N_ELEMENTS (nm_ethtool_data)); + nm_assert (nm_ethtool_data[id]); + nm_assert (nm_ethtool_data[id]->id == id); + return nm_ethtool_data[id]; +} + +/*****************************************************************************/ + +gboolean +nms_ifcfg_rh_utils_is_numbered_tag_impl (const char *key, + const char *tag, + gsize tag_len, + gint64 *out_idx) +{ + gint64 idx; + + nm_assert (key); + nm_assert (tag); + nm_assert (tag_len == strlen (tag)); + nm_assert (tag_len > 0); + + if (strncmp (key, tag, tag_len) != 0) + return FALSE; + + key += tag_len; + + if (key[0] == '\0') { + /* The key has no number suffix. We treat this also as a numbered + * tag, and it is for certain tags like "IPADDR", but not so much + * for others like "ROUTING_RULE_". The caller may want to handle + * this case specially. */ + NM_SET_OUT (out_idx, -1); + return TRUE; + } + + if (!NM_STRCHAR_ALL (key, ch, g_ascii_isdigit (ch))) + return FALSE; + + idx = _nm_utils_ascii_str_to_int64 (key, 10, 0, G_MAXINT64, -1); + if (idx == -1) + return FALSE; + + NM_SET_OUT (out_idx, idx); + return TRUE; +} + +/*****************************************************************************/ + +#define _KEY_TYPE(key, flags) { .key_name = ""key"", .key_flags = ((NMS_IFCFG_KEY_TYPE_WELL_KNOWN) | (flags)), } + +const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { + _KEY_TYPE ("ACD_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("ADDRESS", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("ARPING_WAIT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("AUTH_RETRIES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("AUTOCONNECT_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("AUTOCONNECT_RETRIES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("AUTOCONNECT_SLAVES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BAND", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BONDING_MASTER", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BONDING_OPTS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BOOTPROTO", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BRIDGE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BRIDGE_MACADDR", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BRIDGE_PORT_VLANS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BRIDGE_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BRIDGE_VLANS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BRIDGING_OPTS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BROWSER_ONLY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("BSSID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("CHANNEL", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("CIPHER_GROUP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("CIPHER_PAIRWISE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("CONNECTED_MODE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("CONNECTION_METERED", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("CTCPROT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DCB", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_FCOE_ADVERTISE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_FCOE_ENABLE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_FCOE_MODE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DCB_APP_FCOE_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_FCOE_WILLING, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_FIP_ADVERTISE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_FIP_ENABLE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DCB_APP_FIP_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_FIP_WILLING, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_ISCSI_ADVERTISE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_ISCSI_ENABLE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DCB_APP_ISCSI_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_APP_ISCSI_WILLING, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PFC_ADVERTISE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PFC_ENABLE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PFC_UP, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PFC_WILLING, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PG_ADVERTISE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PG_ENABLE, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PG_ID, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PG_PCT, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PG_STRICT, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PG_UP2TC, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PG_UPPCT, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE (KEY_DCB_PG_WILLING, NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DEFAULTKEY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DEFROUTE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DELAY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DEVICE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DEVICETYPE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DEVTIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCPV6C", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCPV6_DUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCPV6_HOSTNAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCPV6_HOSTNAME_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCPV6_IAID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCPV6_SEND_HOSTNAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCP_CLIENT_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCP_FQDN", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCP_HOSTNAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCP_HOSTNAME_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCP_IAID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCP_SEND_HOSTNAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCPv6_DUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DHCPv6_IAID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("DNS", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("DOMAIN", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("ESSID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("ETHTOOL_OPTS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("ETHTOOL_WAKE_ON_LAN", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("FILS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("FILTER", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("GATEWAY", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("GATEWAYDEV", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("GATEWAY_PING_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("GENERATE_MAC_ADDRESS_MASK", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("GVRP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("HWADDR", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("HWADDR_BLACKLIST", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_ALTSUBJECT_MATCHES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_ANON_IDENTITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_AUTH_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_CA_CERT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_CA_CERT_PASSWORD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_CA_CERT_PASSWORD_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_CLIENT_CERT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_CLIENT_CERT_PASSWORD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_CLIENT_CERT_PASSWORD_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_DOMAIN_MATCH", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_DOMAIN_SUFFIX_MATCH", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_EAP_METHODS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_FAST_PROVISIONING", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_IDENTITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_AUTH_METHODS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_CA_CERT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_CA_CERT_PASSWORD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_CA_CERT_PASSWORD_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_CLIENT_CERT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_CLIENT_CERT_PASSWORD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_CLIENT_CERT_PASSWORD_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_PRIVATE_KEY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_OPTIONAL", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PAC_FILE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PASSWORD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PASSWORD_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PASSWORD_RAW", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PASSWORD_RAW_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PEAP_FORCE_NEW_LABEL", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PEAP_VERSION", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PHASE1_AUTH_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PHASE2_DOMAIN_MATCH", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PHASE2_SUBJECT_MATCH", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PRIVATE_KEY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PRIVATE_KEY_PASSWORD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_SUBJECT_MATCH", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IEEE_8021X_SYSTEM_CA_CERTS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPADDR", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("IPV4_DHCP_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV4_DNS_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV4_FAILURE_FATAL", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV4_ROUTE_METRIC", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV4_ROUTE_TABLE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6ADDR", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6ADDR_SECONDARIES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6FORWARDING", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6INIT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6TUNNELIPV4", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_ADDR_GEN_MODE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_AUTOCONF", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_DEFAULTDEV", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_DEFAULTGW", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_DEFROUTE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_DHCP_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_DISABLED", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_DNS_PRIORITY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_DOMAIN", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_FAILURE_FATAL", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_PEERDNS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_PEERROUTES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_PRIVACY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_PRIVACY_PREFER_PUBLIC_IP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_RA_TIMEOUT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_RES_OPTIONS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_ROUTE_METRIC", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_ROUTE_TABLE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("IPV6_TOKEN", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("KEY", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("KEY_MGMT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("KEY_PASSPHRASE", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("KEY_TYPE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("LLDP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("LLMNR", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MACADDR", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MAC_ADDRESS_RANDOMIZATION", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MASTER", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MASTER_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MATCH_INTERFACE_NAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MDNS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("METRIC", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("MODE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MTU", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MULTI_CONNECT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("MVRP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("NAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("NETMASK", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("NETTYPE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("NM_CONTROLLED", NMS_IFCFG_KEY_TYPE_IS_PLAIN | NMS_IFCFG_KEY_TYPE_KEEP_WHEN_DIRTY ), + _KEY_TYPE ("NM_USER_", NMS_IFCFG_KEY_TYPE_IS_PREFIX ), + _KEY_TYPE ("ONBOOT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("OPTIONS", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("OVS_PORT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("OVS_PORT_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PAC_SCRIPT", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PAC_URL", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PEERDNS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PEERROUTES", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PHYSDEV", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PKEY", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PMF", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PORTNAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("POWERSAVE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("PREFIX", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("PROXY_METHOD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("QDISC", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("REORDER_HDR", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("RES_OPTIONS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("ROUTING_RULE6_", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("ROUTING_RULE_", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("SEARCH", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("SECONDARY_UUIDS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("SECURITYMODE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("SLAVE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("SRIOV_AUTOPROBE_DRIVERS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("SRIOV_TOTAL_VFS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("SRIOV_VF", NMS_IFCFG_KEY_TYPE_IS_NUMBERED ), + _KEY_TYPE ("SSID_HIDDEN", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("STABLE_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("STP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("SUBCHANNELS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("TEAM_CONFIG", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("TEAM_MASTER", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("TEAM_MASTER_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("TEAM_PORT_CONFIG", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("TYPE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("USERS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VLAN", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VLAN_EGRESS_PRIORITY_MAP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VLAN_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VLAN_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VLAN_INGRESS_PRIORITY_MAP", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VRF", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("VRF_UUID", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("WEP_KEY_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("WPA_ALLOW_WPA", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("WPA_ALLOW_WPA2", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("WPA_PSK", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("WPA_PSK_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("WPS_METHOD", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), + _KEY_TYPE ("ZONE", NMS_IFCFG_KEY_TYPE_IS_PLAIN ), +}; + +const NMSIfcfgKeyTypeInfo * +nms_ifcfg_well_known_key_find_info (const char *key, gssize *out_idx) +{ + gssize idx; + + G_STATIC_ASSERT (G_STRUCT_OFFSET (NMSIfcfgKeyTypeInfo, key_name) == 0); + + idx = nm_utils_array_find_binary_search (nms_ifcfg_well_known_keys, + sizeof (nms_ifcfg_well_known_keys[0]), + G_N_ELEMENTS (nms_ifcfg_well_known_keys), + &key, + nm_strcmp_p_with_data, + NULL); + NM_SET_OUT (out_idx, idx); + if (idx < 0) + return NULL; + return &nms_ifcfg_well_known_keys[idx]; +} + +const NMSIfcfgKeyTypeInfo * +nms_ifcfg_rh_utils_is_well_known_key (const char *key) +{ + const NMSIfcfgKeyTypeInfo *ti; + gssize idx; + + nm_assert (key); + + ti = nms_ifcfg_well_known_key_find_info (key, &idx); + + if (ti) { + if (NM_FLAGS_ANY (ti->key_flags, NMS_IFCFG_KEY_TYPE_IS_PLAIN + | NMS_IFCFG_KEY_TYPE_IS_NUMBERED)) { + /* These tags are valid on full match. + * + * Note that numbered tags we also treat as valid if they have no + * suffix. That is correct for "IPADDR", but less so for "ROUTING_RULE_". */ + return ti; + } + nm_assert (NM_FLAGS_HAS (ti->key_flags, NMS_IFCFG_KEY_TYPE_IS_PREFIX)); + /* a prefix tag needs some extra suffix afterwards to be valid. */ + return NULL; + } + + /* Not found. Maybe it's a numbered/prefixed key? With idx we got the index where + * we should insert the key. Since the numbered/prefixed keys share a prefix, we can + * find the possible prefix at the index before the insert position. */ + idx = ~idx; + if (idx == 0) + return NULL; + + ti = &nms_ifcfg_well_known_keys[idx - 1]; + + if (NM_FLAGS_HAS (ti->key_flags, NMS_IFCFG_KEY_TYPE_IS_NUMBERED)) { + if (nms_ifcfg_rh_utils_is_numbered_tag (key, ti->key_name, NULL)) + return ti; + return NULL; + } + + if (NM_FLAGS_HAS (ti->key_flags, NMS_IFCFG_KEY_TYPE_IS_PREFIX)) { + gsize l = strlen (ti->key_name); + + if ( strncmp (key, ti->key_name, l) == 0 + && key[l] != '\0') + return ti; + return NULL; } return NULL; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 035146ff..8941fc19 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -11,9 +11,48 @@ #include "shvar.h" -gboolean nms_ifcfg_rh_util_parse_unhandled_spec (const char *unhandled_spec, - const char **out_unmanaged_spec, - const char **out_unrecognized_spec); +/*****************************************************************************/ + +typedef enum { + NMS_IFCFG_KEY_TYPE_UNKNOWN = 0, + NMS_IFCFG_KEY_TYPE_WELL_KNOWN = (1u << 0), + + NMS_IFCFG_KEY_TYPE_IS_PLAIN = (1u << 1), + NMS_IFCFG_KEY_TYPE_IS_NUMBERED = (1u << 2), + NMS_IFCFG_KEY_TYPE_IS_PREFIX = (1u << 3), + + /* by default, well knowns keys that are not explicitly set + * by the writer (the unvisited, dirty ones) are removed. + * With this flag, such keys are kept if they are present. */ + NMS_IFCFG_KEY_TYPE_KEEP_WHEN_DIRTY = (1u << 4), + +} NMSIfcfgKeyTypeFlags; + +typedef struct { + const char *key_name; + NMSIfcfgKeyTypeFlags key_flags; +} NMSIfcfgKeyTypeInfo; + +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[231]; + +const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info (const char *key, gssize *out_idx); + +static inline NMSIfcfgKeyTypeFlags +nms_ifcfg_well_known_key_find_info_flags (const char *key) +{ + const NMSIfcfgKeyTypeInfo *ti; + + ti = nms_ifcfg_well_known_key_find_info (key, NULL); + if (!ti) + return NMS_IFCFG_KEY_TYPE_UNKNOWN; + return ti->key_flags; +} + +/*****************************************************************************/ + +gboolean nms_ifcfg_rh_utils_parse_unhandled_spec (const char *unhandled_spec, + const char **out_unmanaged_spec, + const char **out_unrecognized_spec); #define NM_IFCFG_CONNECTION_LOG_PATH(path) ((path) ?: "in-memory") #define NM_IFCFG_CONNECTION_LOG_FMT "%s (%s,\"%s\")" @@ -37,6 +76,8 @@ shvarFile *utils_get_keys_ifcfg (const char *parent, gboolean should_create); shvarFile *utils_get_route_ifcfg (const char *parent, gboolean should_create); gboolean utils_has_route_file_new_syntax (const char *filename); +gboolean utils_has_route_file_new_syntax_content (const char *contents, + gsize len); gboolean utils_has_complex_routes (const char *filename, int addr_family); gboolean utils_is_ifcfg_alias_file (const char *alias, const char *ifcfg); @@ -51,6 +92,12 @@ _nms_ifcfg_rh_utils_numbered_tag (char *buf, gsize buf_len, const char *tag_name { gsize l; +#if NM_MORE_ASSERTS > 5 + nm_assert (NM_FLAGS_ALL (nms_ifcfg_well_known_key_find_info_flags (tag_name), + NMS_IFCFG_KEY_TYPE_WELL_KNOWN + | NMS_IFCFG_KEY_TYPE_IS_NUMBERED)); +#endif + l = g_strlcpy (buf, tag_name, buf_len); nm_assert (l < buf_len); if (which != -1) { @@ -70,6 +117,28 @@ _nms_ifcfg_rh_utils_numbered_tag (char *buf, gsize buf_len, const char *tag_name _nms_ifcfg_rh_utils_numbered_tag (buf, sizeof (buf), ""tag_name"", (which)); \ }) +gboolean nms_ifcfg_rh_utils_is_numbered_tag_impl (const char *key, + const char *tag, + gsize tag_len, + gint64 *out_idx); + +static inline gboolean +nms_ifcfg_rh_utils_is_numbered_tag (const char *key, + const char *tag, + gint64 *out_idx) +{ + nm_assert (tag); + + return nms_ifcfg_rh_utils_is_numbered_tag_impl (key, tag, strlen (tag), out_idx); +} + +#define NMS_IFCFG_RH_UTIL_IS_NUMBERED_TAG(key, tag, out_idx) \ + nms_ifcfg_rh_utils_is_numbered_tag_impl (key, tag, NM_STRLEN (tag), out_idx) + +/*****************************************************************************/ + +const NMSIfcfgKeyTypeInfo *nms_ifcfg_rh_utils_is_well_known_key (const char *key); + /*****************************************************************************/ extern const char *const _nm_ethtool_ifcfg_names[_NM_ETHTOOL_ID_FEATURE_NUM]; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 90a1a2b8..a0797fdc 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -66,10 +66,8 @@ save_secret_flags (shvarFile *ifcfg, g_return_if_fail (ifcfg != NULL); g_return_if_fail (key != NULL); - if (flags == NM_SETTING_SECRET_FLAG_NONE) { - svUnsetValue (ifcfg, key); + if (flags == NM_SETTING_SECRET_FLAG_NONE) return; - } /* Convert flags bitfield into string representation */ str = g_string_sized_new (20); @@ -100,9 +98,6 @@ set_secret (shvarFile *ifcfg, const char *flags_key, NMSettingSecretFlags flags) { - /* Clear the secret from the ifcfg and the associated "keys" file */ - svUnsetValue (ifcfg, key); - /* Save secret flags */ save_secret_flags (ifcfg, flags_key, flags); @@ -131,9 +126,6 @@ write_secrets (shvarFile *ifcfg, return FALSE; } - /* we purge all existing secrets. */ - svUnsetAll (keyfile, SV_KEY_TYPE_ANY); - secrets_keys = nm_utils_strdict_get_keys (secrets, TRUE, &secrets_keys_n); for (i = 0; i < secrets_keys_n; i++) { const char *k = secrets_keys[i]; @@ -147,7 +139,7 @@ write_secrets (shvarFile *ifcfg, if (!any_secrets) (void) unlink (svFileGetName (keyfile)); - else if (!svWriteFile (keyfile, 0600, &local)) { + else if (!svWriteFileWithoutDirtyWellknown (keyfile, 0600, &local)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Failure to write secrets to '%s': %s", svFileGetName (keyfile), local->message); return FALSE; @@ -372,12 +364,8 @@ write_8021x_setting (NMConnection *connection, int vint; s_8021x = nm_connection_get_setting_802_1x (connection); - if (!s_8021x) { - /* If wired, clear KEY_MGMT */ - if (wired) - svUnsetValue (ifcfg, "KEY_MGMT"); + if (!s_8021x) return TRUE; - } /* If wired, write KEY_MGMT */ if (wired) @@ -424,10 +412,7 @@ write_8021x_setting (NMConnection *connection, nm_setting_802_1x_get_system_ca_certs (s_8021x)); value = nm_setting_802_1x_get_phase1_peapver (s_8021x); - if (NM_IN_STRSET (value, "0", "1")) - svSetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", value); - else - svUnsetValue (ifcfg, "IEEE_8021X_PEAP_VERSION"); + svSetValueStr (ifcfg, "IEEE_8021X_PEAP_VERSION", value); svSetValueBoolean_cond_true (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", @@ -452,7 +437,6 @@ write_8021x_setting (NMConnection *connection, svSetValueStr (ifcfg, "IEEE_8021X_FAST_PROVISIONING", value); /* Phase2 auth methods */ - svUnsetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS"); phase2_auth = g_string_new (NULL); value = nm_setting_802_1x_get_phase2_auth (s_8021x); @@ -473,9 +457,7 @@ write_8021x_setting (NMConnection *connection, } auth_flags = nm_setting_802_1x_get_phase1_auth_flags (s_8021x); - if (auth_flags == NM_SETTING_802_1X_AUTH_FLAGS_NONE) { - svUnsetValue (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS"); - } else { + if (auth_flags != NM_SETTING_802_1X_AUTH_FLAGS_NONE) { svSetValueEnum (ifcfg, "IEEE_8021X_PHASE1_AUTH_FLAGS", nm_setting_802_1x_auth_flags_get_type(), auth_flags); @@ -492,7 +474,6 @@ write_8021x_setting (NMConnection *connection, svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_SUBJECT_MATCH", nm_setting_802_1x_get_phase2_subject_match (s_8021x)); - svUnsetValue (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES"); str = g_string_new (NULL); num = nm_setting_802_1x_get_num_altsubject_matches (s_8021x); for (i = 0; i < num; i++) { @@ -505,7 +486,6 @@ write_8021x_setting (NMConnection *connection, svSetValueStr (ifcfg, "IEEE_8021X_ALTSUBJECT_MATCHES", str->str); g_string_free (str, TRUE); - svUnsetValue (ifcfg, "IEEE_8021X_PHASE2_ALTSUBJECT_MATCHES"); str = g_string_new (NULL); num = nm_setting_802_1x_get_num_phase2_altsubject_matches (s_8021x); for (i = 0; i < num; i++) { @@ -523,6 +503,11 @@ write_8021x_setting (NMConnection *connection, svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_SUFFIX_MATCH", nm_setting_802_1x_get_phase2_domain_suffix_match (s_8021x)); + svSetValueStr (ifcfg, "IEEE_8021X_DOMAIN_MATCH", + nm_setting_802_1x_get_domain_match (s_8021x)); + svSetValueStr (ifcfg, "IEEE_8021X_PHASE2_DOMAIN_MATCH", + nm_setting_802_1x_get_phase2_domain_match (s_8021x)); + vint = nm_setting_802_1x_get_auth_timeout (s_8021x); svSetValueInt64_cond (ifcfg, "IEEE_8021X_AUTH_TIMEOUT", vint > 0, vint); @@ -565,14 +550,11 @@ write_wireless_security_setting (NMConnection *connection, } key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec); - g_assert (key_mgmt); + nm_assert (key_mgmt); auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec); - svUnsetValue (ifcfg, "DEFAULTKEY"); - if (!strcmp (key_mgmt, "none")) { - svUnsetValue (ifcfg, "KEY_MGMT"); wep = TRUE; *no_8021x = TRUE; } else if (!strcmp (key_mgmt, "wpa-psk")) { @@ -583,6 +565,10 @@ write_wireless_security_setting (NMConnection *connection, svSetValueStr (ifcfg, "KEY_MGMT", "SAE"); wpa = TRUE; *no_8021x = TRUE; + } else if (!strcmp (key_mgmt, "owe")) { + svSetValueStr (ifcfg, "KEY_MGMT", "OWE"); + wpa = FALSE; + *no_8021x = TRUE; } else if (!strcmp (key_mgmt, "ieee8021x")) { svSetValueStr (ifcfg, "KEY_MGMT", "IEEE8021X"); dynamic_wep = TRUE; @@ -591,7 +577,6 @@ write_wireless_security_setting (NMConnection *connection, wpa = TRUE; } - svUnsetValue (ifcfg, "SECURITYMODE"); if (auth_alg) { if (!strcmp (auth_alg, "shared")) svSetValueStr (ifcfg, "SECURITYMODE", "restricted"); @@ -611,11 +596,8 @@ write_wireless_security_setting (NMConnection *connection, } } - /* WPS */ wps_method = nm_setting_wireless_security_get_wps_method (s_wsec); - if (wps_method == NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT) - svUnsetValue (ifcfg, "WPS_METHOD"); - else + if (wps_method != NM_SETTING_WIRELESS_SECURITY_WPS_METHOD_DEFAULT) svSetValueEnum (ifcfg, "WPS_METHOD", nm_setting_wireless_security_wps_method_get_type (), wps_method); /* WEP keys */ @@ -701,8 +683,6 @@ write_wireless_security_setting (NMConnection *connection, } /* WPA protos */ - svUnsetValue (ifcfg, "WPA_ALLOW_WPA"); - svUnsetValue (ifcfg, "WPA_ALLOW_WPA2"); num = nm_setting_wireless_security_get_num_protos (s_wsec); for (i = 0; i < num; i++) { proto = nm_setting_wireless_security_get_proto (s_wsec, i); @@ -713,7 +693,6 @@ write_wireless_security_setting (NMConnection *connection, } /* WPA Pairwise ciphers */ - svUnsetValue (ifcfg, "CIPHER_PAIRWISE"); str = g_string_new (NULL); num = nm_setting_wireless_security_get_num_pairwise (s_wsec); for (i = 0; i < num; i++) { @@ -735,7 +714,6 @@ write_wireless_security_setting (NMConnection *connection, g_string_free (str, TRUE); /* WPA Group ciphers */ - svUnsetValue (ifcfg, "CIPHER_GROUP"); str = g_string_new (NULL); num = nm_setting_wireless_security_get_num_groups (s_wsec); for (i = 0; i < num; i++) { @@ -760,16 +738,12 @@ write_wireless_security_setting (NMConnection *connection, "WPA_PSK_FLAGS", wpa ? nm_setting_wireless_security_get_psk_flags (s_wsec) : NM_SETTING_SECRET_FLAG_NONE); - if (nm_setting_wireless_security_get_pmf (s_wsec) == NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT) - svUnsetValue (ifcfg, "PMF"); - else { + if (nm_setting_wireless_security_get_pmf (s_wsec) != NM_SETTING_WIRELESS_SECURITY_PMF_DEFAULT) { svSetValueEnum (ifcfg, "PMF", nm_setting_wireless_security_pmf_get_type (), nm_setting_wireless_security_get_pmf (s_wsec)); } - if (nm_setting_wireless_security_get_fils (s_wsec) == NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT) - svUnsetValue (ifcfg, "FILS"); - else { + if (nm_setting_wireless_security_get_fils (s_wsec) != NM_SETTING_WIRELESS_SECURITY_FILS_DEFAULT) { svSetValueEnum (ifcfg, "FILS", nm_setting_wireless_security_fils_get_type (), nm_setting_wireless_security_get_fils (s_wsec)); } @@ -810,14 +784,12 @@ write_wireless_setting (NMConnection *connection, svSetValueStr (ifcfg, "GENERATE_MAC_ADDRESS_MASK", nm_setting_wireless_get_generate_mac_address_mask (s_wireless)); - svUnsetValue (ifcfg, "HWADDR_BLACKLIST"); macaddr_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); if (macaddr_blacklist[0]) { - char *blacklist_str; + gs_free char *blacklist_str = NULL; blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist); svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str); - g_free (blacklist_str); } mtu = nm_setting_wireless_get_mtu (s_wireless); @@ -879,9 +851,9 @@ write_wireless_setting (NMConnection *connection, } mode = nm_setting_wireless_get_mode (s_wireless); - if (!mode) - svUnsetValue(ifcfg, "MODE"); - else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_INFRA)) + if (!mode) { + /* pass */ + } else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_INFRA)) svSetValueStr (ifcfg, "MODE", "Managed"); else if (nm_streq (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) { svSetValueStr (ifcfg, "MODE", "Ad-Hoc"); @@ -895,8 +867,6 @@ write_wireless_setting (NMConnection *connection, return FALSE; } - svUnsetValue (ifcfg, "CHANNEL"); - svUnsetValue (ifcfg, "BAND"); chan = nm_setting_wireless_get_channel (s_wireless); if (chan) { svSetValueInt64 (ifcfg, "CHANNEL", chan); @@ -912,18 +882,13 @@ write_wireless_setting (NMConnection *connection, * otherwise there's no way to detect WEP vs. open when WEP keys aren't * saved. */ - svUnsetValue (ifcfg, "DEFAULTKEY"); - svUnsetValue (ifcfg, "SECURITYMODE"); if (nm_connection_get_setting_wireless_security (connection)) { if (!write_wireless_security_setting (connection, ifcfg, secrets, adhoc, no_8021x, error)) return FALSE; } else { /* Clear out wifi security keys */ - svUnsetValue (ifcfg, "KEY_MGMT"); - svUnsetValue (ifcfg, "IEEE_8021X_IDENTITY"); set_secret (ifcfg, secrets, "IEEE_8021X_PASSWORD", NULL, "IEEE_8021X_PASSWORD_FLAGS", NM_SETTING_SECRET_FLAG_NONE); - svUnsetValue (ifcfg, "SECURITYMODE"); /* Clear existing keys */ set_secret (ifcfg, secrets, "KEY", NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); @@ -937,11 +902,6 @@ write_wireless_setting (NMConnection *connection, set_secret (ifcfg, secrets, tag, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE); } - svUnsetValue (ifcfg, "DEFAULTKEY"); - svUnsetValue (ifcfg, "WPA_ALLOW_WPA"); - svUnsetValue (ifcfg, "WPA_ALLOW_WPA2"); - svUnsetValue (ifcfg, "CIPHER_PAIRWISE"); - svUnsetValue (ifcfg, "CIPHER_GROUP"); set_secret (ifcfg, secrets, "WPA_PSK", NULL, "WPA_PSK_FLAGS", NM_SETTING_SECRET_FLAG_NONE); } @@ -959,7 +919,6 @@ write_wireless_setting (NMConnection *connection, break; default: case NM_SETTING_WIRELESS_POWERSAVE_DEFAULT: - svUnsetValue (ifcfg, "POWERSAVE"); break; } @@ -1050,8 +1009,7 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) blacklist_str = g_strjoinv (" ", (char **) macaddr_blacklist); svSetValueStr (ifcfg, "HWADDR_BLACKLIST", blacklist_str); - } else - svUnsetValue (ifcfg, "HWADDR_BLACKLIST"); + } mtu = nm_setting_wired_get_mtu (s_wired); svSetValueInt64_cond (ifcfg, "MTU", mtu != 0, mtu); @@ -1085,7 +1043,6 @@ write_wired_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValueStr (ifcfg, "CTCPROT", nm_setting_wired_get_s390_option_by_key (s_wired, "ctcprot")); - svUnsetValue (ifcfg, "OPTIONS"); num_opts = nm_setting_wired_get_num_s390_options (s_wired); if (s390_subchannels && num_opts) { nm_auto_free_gstring GString *tmp = NULL; @@ -1137,11 +1094,9 @@ write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **erro s_wired = nm_connection_get_setting_wired (connection); s_ethtool = NM_SETTING_ETHTOOL (nm_connection_get_setting (connection, NM_TYPE_SETTING_ETHTOOL)); - if (!s_wired && !s_ethtool) { - svUnsetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN"); - svUnsetValue (ifcfg, "ETHTOOL_OPTS"); + if ( !s_wired + && !s_ethtool) return TRUE; - } if (s_wired) { auto_negotiate = nm_setting_wired_get_auto_negotiate (s_wired); @@ -1200,8 +1155,7 @@ write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **erro if (wol_password && NM_FLAGS_HAS (wol, NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC)) g_string_append_printf (str, "s sopass %s", wol_password); } - } else - svUnsetValue (ifcfg, "ETHTOOL_WAKE_ON_LAN"); + } if (s_ethtool) { NMEthtoolID ethtool_id; @@ -1246,8 +1200,7 @@ write_ethtool_setting (NMConnection *connection, shvarFile *ifcfg, GError **erro if (str) { svSetValueStr (ifcfg, "ETHTOOL_OPTS", str->str); g_string_free (str, TRUE); - } else - svUnsetValue (ifcfg, "ETHTOOL_OPTS"); + } return TRUE; } @@ -1346,10 +1299,6 @@ write_vlan_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, svSetValueStr (ifcfg, "VLAN_EGRESS_PRIORITY_MAP", tmp); g_free (tmp); - svUnsetValue (ifcfg, "HWADDR"); - svUnsetValue (ifcfg, "MACADDR"); - svUnsetValue (ifcfg, "MTU"); - *wired = write_wired_for_virtual (connection, ifcfg); return TRUE; @@ -1368,8 +1317,6 @@ write_bond_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, return FALSE; } - svUnsetValue (ifcfg, "BONDING_OPTS"); - num_opts = nm_setting_bond_get_num_options (s_bond); if (num_opts) { nm_auto_free_gstring GString *str = NULL; @@ -1463,10 +1410,9 @@ write_bridge_vlans (NMSetting *setting, g_object_get (setting, property_name, &vlans, NULL); - if (!vlans || !vlans->len) { - svUnsetValue (ifcfg, key); + if ( !vlans + || !vlans->len) return TRUE; - } string = g_string_new (""); for (i = 0; i < vlans->len; i++) { @@ -1492,8 +1438,8 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire NMSettingBridge *s_bridge; guint32 i; gboolean b; + const char *s; GString *opts; - const char *mac; s_bridge = nm_connection_get_setting_bridge (connection); if (!s_bridge) { @@ -1502,12 +1448,10 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire return FALSE; } - svUnsetValue (ifcfg, "BRIDGING_OPTS"); svSetValueBoolean (ifcfg, "STP", FALSE); - svUnsetValue (ifcfg, "DELAY"); - mac = nm_setting_bridge_get_mac_address (s_bridge); - svSetValueStr (ifcfg, "BRIDGE_MACADDR", mac); + s = nm_setting_bridge_get_mac_address (s_bridge); + svSetValueStr (ifcfg, "BRIDGE_MACADDR", s); /* Bridge options */ opts = g_string_sized_new (32); @@ -1543,6 +1487,13 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire g_string_append_printf (opts, "ageing_time=%u", i); } + s = nm_setting_bridge_get_group_address (s_bridge); + if (s) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "group_address=%s", s); + } + i = nm_setting_bridge_get_group_forward_mask (s_bridge); if (i != get_setting_default_uint (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_GROUP_FORWARD_MASK)) { if (opts->len) @@ -1550,6 +1501,20 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire g_string_append_printf (opts, "group_fwd_mask=%u", i); } + b = nm_setting_bridge_get_multicast_querier (s_bridge); + if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MULTICAST_QUERIER)) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "multicast_querier=%u", (guint) b); + } + + b = nm_setting_bridge_get_multicast_query_use_ifaddr (s_bridge); + if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR)) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "multicast_query_use_ifaddr=%u", (guint) b); + } + b = nm_setting_bridge_get_multicast_snooping (s_bridge); if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MULTICAST_SNOOPING)) { if (opts->len) @@ -1557,6 +1522,13 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire g_string_append_printf (opts, "multicast_snooping=%u", (guint32) b); } + s = nm_setting_bridge_get_multicast_router (s_bridge); + if (s) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "multicast_router=%s", s); + } + b = nm_setting_bridge_get_vlan_filtering (s_bridge); if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_VLAN_FILTERING)) { if (opts->len) @@ -1571,6 +1543,20 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire g_string_append_printf (opts, "default_pvid=%u", i); } + s = nm_setting_bridge_get_vlan_protocol (s_bridge); + if (s) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "vlan_protocol=%s", s); + } + + b = nm_setting_bridge_get_vlan_stats_enabled (s_bridge); + if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_VLAN_STATS_ENABLED)) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "vlan_stats_enabled=%u", (guint) b); + } + if (opts->len) svSetValueStr (ifcfg, "BRIDGING_OPTS", opts->str); g_string_free (opts, TRUE); @@ -1600,8 +1586,6 @@ write_bridge_port_setting (NMConnection *connection, shvarFile *ifcfg, GError ** if (!s_port) return TRUE; - svUnsetValue (ifcfg, "BRIDGING_OPTS"); - /* Bridge options */ string = g_string_sized_new (32); @@ -1677,11 +1661,11 @@ write_dcb_app (shvarFile *ifcfg, write_dcb_flags (ifcfg, tag, flags); - nm_sprintf_buf (prop, "DCB_%s_PRIORITY", tag); - if ((flags & NM_SETTING_DCB_FLAG_ENABLE) && (priority >= 0)) + if ( (flags & NM_SETTING_DCB_FLAG_ENABLE) + && (priority >= 0)) { + nm_sprintf_buf (prop, "DCB_%s_PRIORITY", tag); svSetValueInt64 (ifcfg, prop, priority); - else - svUnsetValue (ifcfg, prop); + } } typedef gboolean (*DcbGetBoolFunc) (NMSettingDcb *, guint); @@ -1696,10 +1680,8 @@ write_dcb_bool_array (shvarFile *ifcfg, char str[9]; guint i; - if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { - svUnsetValue (ifcfg, key); + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) return; - } str[8] = 0; for (i = 0; i < 8; i++) @@ -1719,10 +1701,8 @@ write_dcb_uint_array (shvarFile *ifcfg, char str[9]; guint i, num; - if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { - svUnsetValue (ifcfg, key); + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) return; - } str[8] = 0; for (i = 0; i < 8; i++) { @@ -1747,10 +1727,8 @@ write_dcb_percent_array (shvarFile *ifcfg, GString *str; guint i; - if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) { - svUnsetValue (ifcfg, key); + if (!(flags & NM_SETTING_DCB_FLAG_ENABLE)) return; - } str = g_string_sized_new (30); for (i = 0; i < 8; i++) { @@ -1769,38 +1747,8 @@ write_dcb_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) NMSettingDcbFlags flags; s_dcb = nm_connection_get_setting_dcb (connection); - if (!s_dcb) { - static const char *clear_keys[] = { - "DCB", - KEY_DCB_APP_FCOE_ENABLE, - KEY_DCB_APP_FCOE_ADVERTISE, - KEY_DCB_APP_FCOE_WILLING, - KEY_DCB_APP_FCOE_MODE, - KEY_DCB_APP_ISCSI_ENABLE, - KEY_DCB_APP_ISCSI_ADVERTISE, - KEY_DCB_APP_ISCSI_WILLING, - KEY_DCB_APP_FIP_ENABLE, - KEY_DCB_APP_FIP_ADVERTISE, - KEY_DCB_APP_FIP_WILLING, - KEY_DCB_PFC_ENABLE, - KEY_DCB_PFC_ADVERTISE, - KEY_DCB_PFC_WILLING, - KEY_DCB_PFC_UP, - KEY_DCB_PG_ENABLE, - KEY_DCB_PG_ADVERTISE, - KEY_DCB_PG_WILLING, - KEY_DCB_PG_ID, - KEY_DCB_PG_PCT, - KEY_DCB_PG_UPPCT, - KEY_DCB_PG_STRICT, - KEY_DCB_PG_UP2TC, - NULL }; - const char **iter; - - for (iter = clear_keys; *iter; iter++) - svUnsetValue (ifcfg, *iter); + if (!s_dcb) return TRUE; - } svSetValueStr (ifcfg, "DCB", "yes"); @@ -1809,8 +1757,6 @@ write_dcb_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) nm_setting_dcb_get_app_fcoe_priority (s_dcb)); if (nm_setting_dcb_get_app_fcoe_flags (s_dcb) & NM_SETTING_DCB_FLAG_ENABLE) svSetValueStr (ifcfg, KEY_DCB_APP_FCOE_MODE, nm_setting_dcb_get_app_fcoe_mode (s_dcb)); - else - svUnsetValue (ifcfg, KEY_DCB_APP_FCOE_MODE); write_dcb_app (ifcfg, "APP_ISCSI", nm_setting_dcb_get_app_iscsi_flags (s_dcb), @@ -1877,9 +1823,7 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) svSetValueStr (ifcfg, "AUTOCONNECT_SLAVES", autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_YES ? "yes" : autoconnect_slaves == NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_NO ? "no" : NULL); - } else - svUnsetValue (ifcfg, "AUTOCONNECT_SLAVES"); - + } switch (nm_setting_connection_get_lldp (s_con)) { case NM_SETTING_CONNECTION_LLDP_ENABLE_RX: tmp = "rx"; @@ -1893,7 +1837,6 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) svSetValueStr (ifcfg, "LLDP", tmp); /* Permissions */ - svUnsetValue (ifcfg, "USERS"); n = nm_setting_connection_get_num_permissions (s_con); if (n > 0) { str = g_string_sized_new (n * 20); @@ -1923,8 +1866,6 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) svSetValueStr (ifcfg, "BRIDGE", NULL); svSetValueStr (ifcfg, "TEAM_MASTER_UUID", NULL); svSetValueStr (ifcfg, "TEAM_MASTER", NULL); - svSetValueStr (ifcfg, "OVS_PORT_UUID", NULL); - svSetValueStr (ifcfg, "OVS_PORT", NULL); master = nm_setting_connection_get_master (s_con); if (master) { @@ -1957,6 +1898,9 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_OVS_PORT_SETTING_NAME)) { svSetValueStr (ifcfg, "OVS_PORT_UUID", master); svSetValueStr (ifcfg, "OVS_PORT", master_iface); + } else if (nm_setting_connection_is_slave_type (s_con, NM_SETTING_VRF_SETTING_NAME)) { + svSetValueStr (ifcfg, "VRF_UUID", master); + svSetValueStr (ifcfg, "VRF", master_iface); } else { _LOGW ("don't know how to set master for a %s slave", nm_setting_connection_get_slave_type (s_con)); @@ -1967,11 +1911,8 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) svSetValueStr (ifcfg, "DEVICETYPE", TYPE_TEAM); else if (master_iface && nm_setting_connection_is_slave_type (s_con, NM_SETTING_TEAM_SETTING_NAME)) svSetValueStr (ifcfg, "DEVICETYPE", TYPE_TEAM_PORT); - else - svUnsetValue (ifcfg, "DEVICETYPE"); /* secondary connection UUIDs */ - svUnsetValue (ifcfg, "SECONDARY_UUIDS"); n = nm_setting_connection_get_num_secondaries (s_con); if (n > 0) { str = g_string_sized_new (n * 37); @@ -2004,17 +1945,19 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) case NM_METERED_NO: svSetValueStr (ifcfg, "CONNECTION_METERED", "no"); break; - default: - svUnsetValue (ifcfg, "CONNECTION_METERED"); + case NM_METERED_UNKNOWN: + case NM_METERED_GUESS_YES: + case NM_METERED_GUESS_NO: + break; } vint = nm_setting_connection_get_auth_retries (s_con); svSetValueInt64_cond (ifcfg, "AUTH_RETRIES", vint >= 0, vint); vint32 = nm_setting_connection_get_wait_device_timeout (s_con); - if (vint32 == -1) - svUnsetValue (ifcfg, "DEVTIMEOUT"); - else if ((vint32 % 1000) == 0) + if (vint32 == -1) { + /* pass */ + } else if ((vint32 % 1000) == 0) svSetValueInt64 (ifcfg, "DEVTIMEOUT", vint32 / 1000); else { char b[100]; @@ -2028,15 +1971,13 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) if (mdns != NM_SETTING_CONNECTION_MDNS_DEFAULT) { svSetValueEnum (ifcfg, "MDNS", nm_setting_connection_mdns_get_type (), mdns); - } else - svUnsetValue (ifcfg, "MDNS"); + } llmnr = nm_setting_connection_get_llmnr (s_con); if (llmnr != NM_SETTING_CONNECTION_LLMNR_DEFAULT) { svSetValueEnum (ifcfg, "LLMNR", nm_setting_connection_llmnr_get_type (), llmnr); - } else - svUnsetValue (ifcfg, "LLMNR"); + } } static char * @@ -2119,8 +2060,6 @@ write_route_file_svformat (const char *filename, NMSettingIPConfig *s_ip4) routefile = utils_get_route_ifcfg (filename, TRUE); - svUnsetAll (routefile, SV_KEY_TYPE_ROUTE_SVFORMAT); - num = nm_setting_ip_config_get_num_routes (s_ip4); for (i = 0; i < num; i++) { char buf[INET_ADDRSTRLEN]; @@ -2144,7 +2083,7 @@ write_route_file_svformat (const char *filename, NMSettingIPConfig *s_ip4) netmask = _nm_utils_ip4_prefix_to_netmask (nm_ip_route_get_prefix (route)); svSetValueStr (routefile, netmask_key, - nm_utils_inet4_ntop (netmask, buf)); + _nm_utils_inet4_ntop (netmask, buf)); svSetValueStr (routefile, gw_key, nm_ip_route_get_next_hop (route)); @@ -2221,10 +2160,6 @@ write_proxy_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (!s_proxy) return TRUE; - svUnsetValue (ifcfg, "BROWSER_ONLY"); - svUnsetValue (ifcfg, "PAC_URL"); - svUnsetValue (ifcfg, "PAC_SCRIPT"); - method = nm_setting_proxy_get_method (s_proxy); switch (method) { case NM_SETTING_PROXY_METHOD_AUTO: @@ -2258,8 +2193,6 @@ write_user_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) s_user = NM_SETTING_USER (nm_connection_get_setting (connection, NM_TYPE_SETTING_USER)); - svUnsetAll (ifcfg, SV_KEY_TYPE_USER); - if (!s_user) return TRUE; @@ -2292,13 +2225,9 @@ write_sriov_setting (NMConnection *connection, shvarFile *ifcfg) char key[32]; char *str; - svUnsetAll (ifcfg, SV_KEY_TYPE_SRIOV_VF); - s_sriov = NM_SETTING_SRIOV (nm_connection_get_setting (connection, NM_TYPE_SETTING_SRIOV)); if (!s_sriov) { - svUnsetValue (ifcfg, "SRIOV_TOTAL_VFS"); - svUnsetValue (ifcfg, "SRIOV_AUTOPROBE_DRIVERS"); return; } @@ -2307,8 +2236,6 @@ write_sriov_setting (NMConnection *connection, shvarFile *ifcfg) b = nm_setting_sriov_get_autoprobe_drivers (s_sriov); if (b != NM_TERNARY_DEFAULT) svSetValueInt64 (ifcfg, "SRIOV_AUTOPROBE_DRIVERS", b); - else - svUnsetValue (ifcfg, "SRIOV_AUTOPROBE_DRIVERS"); num = nm_setting_sriov_get_num_vfs (s_sriov); for (i = 0; i < num; i++) { @@ -2327,8 +2254,6 @@ write_tc_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) guint i, num, n; char tag[64]; - svUnsetAll (ifcfg, SV_KEY_TYPE_TC); - s_tc = nm_connection_get_setting_tc_config (connection); if (!s_tc) return TRUE; @@ -2371,8 +2296,6 @@ write_match_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) nm_auto_free_gstring GString *str = NULL; guint i, num; - svUnsetValue (ifcfg, "MATCH_INTERFACE_NAME"); - s_match = (NMSettingMatch *) nm_connection_get_setting (connection, NM_TYPE_SETTING_MATCH); if (!s_match) return TRUE; @@ -2404,10 +2327,8 @@ write_res_options (shvarFile *ifcfg, NMSettingIPConfig *s_ip, const char *var) nm_auto_free_gstring GString *value = NULL; guint i, num_options; - if (!nm_setting_ip_config_has_dns_options (s_ip)) { - svUnsetValue (ifcfg, var); + if (!nm_setting_ip_config_has_dns_options (s_ip)) return; - } value = g_string_new (NULL); num_options = nm_setting_ip_config_get_num_dns_options (s_ip); @@ -2420,6 +2341,47 @@ write_res_options (shvarFile *ifcfg, NMSettingIPConfig *s_ip, const char *var) svSetValue (ifcfg, var, value->str); } +static void +write_dns_setting (shvarFile *ifcfg, + NMConnection *connection, + int addr_family) +{ + NMSettingIPConfig *s_ip; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6 = NULL; + guint num4; + guint num6 = 0; + guint num; + guint i; + guint offset; + + if (addr_family == AF_INET6) { + s_ip6 = nm_connection_get_setting_ip6_config (connection); + num6 = s_ip6 ? nm_setting_ip_config_get_num_dns (s_ip6) : 0u; + } + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + num4 = s_ip4 ? nm_setting_ip_config_get_num_dns (s_ip4) : 0u; + + if (addr_family == AF_INET6) { + num = num6; + offset = num4; + s_ip = s_ip6; + } else { + num = num4; + offset = 0; + s_ip = s_ip4; + } + + for (i = 0; i < num; i++) { + char tag[64]; + + svSetValueStr (ifcfg, + numbered_tag (tag, "DNS", offset + i + 1u), + nm_setting_ip_config_get_dns (s_ip, i)); + } +} + static gboolean write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, @@ -2446,16 +2408,8 @@ write_ip4_setting (NMConnection *connection, NM_SET_OUT (out_route_content, NULL); s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (!s_ip4) { - /* slave-type: clear IPv4 settings. - * - * Some IPv4 setting related options are not cleared, - * for no strong reason. */ - svUnsetValue (ifcfg, "BOOTPROTO"); - svUnsetValue (ifcfg, "RES_OPTIONS"); - svUnsetAll (ifcfg, SV_KEY_TYPE_IP4_ADDRESS); + if (!s_ip4) return TRUE; - } method = nm_setting_ip_config_get_method (s_ip4); @@ -2463,17 +2417,8 @@ write_ip4_setting (NMConnection *connection, if (!method) method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; - if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { - /* IPv4 disabled, clear IPv4 related parameters */ - svUnsetValue (ifcfg, "BOOTPROTO"); - for (j = -1; j < 256; j++) { - svUnsetValue (ifcfg, numbered_tag (tag, "IPADDR", j)); - svUnsetValue (ifcfg, numbered_tag (tag, "PREFIX", j)); - svUnsetValue (ifcfg, numbered_tag (tag, "NETMASK", j)); - svUnsetValue (ifcfg, numbered_tag (tag, "GATEWAY", j)); - } + if (nm_streq (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) return TRUE; - } num = nm_setting_ip_config_get_num_addresses (s_ip4); @@ -2490,7 +2435,7 @@ write_ip4_setting (NMConnection *connection, else if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) svSetValueStr (ifcfg, "BOOTPROTO", "shared"); - has_netmask = !!svFindFirstKeyWithPrefix (ifcfg, "NETMASK"); + has_netmask = !!svFindFirstNumberedKey (ifcfg, "NETMASK"); /* Write out IPADDR<n>, PREFIX<n>, GATEWAY<n> for current IP addresses * without labels. Unset obsolete NETMASK<n>. @@ -2532,45 +2477,15 @@ write_ip4_setting (NMConnection *connection, char buf[INET_ADDRSTRLEN]; svSetValueStr (ifcfg, tag, - nm_utils_inet4_ntop (_nm_utils_ip4_prefix_to_netmask (prefix), buf)); - } else - svUnsetValue (ifcfg, tag); + _nm_utils_inet4_ntop (_nm_utils_ip4_prefix_to_netmask (prefix), buf)); + } n++; } - svUnsetValue (ifcfg, numbered_tag (tag, "IPADDR", 0)); - svUnsetValue (ifcfg, numbered_tag (tag, "PREFIX", 0)); - svUnsetValue (ifcfg, numbered_tag (tag, "NETMASK", 0)); - if (n == 0) { - svUnsetValue (ifcfg, "IPADDR"); - svUnsetValue (ifcfg, "PREFIX"); - svUnsetValue (ifcfg, "NETMASK"); - } - for (j = n; j < 256; j++) { - svUnsetValue (ifcfg, numbered_tag (tag, "IPADDR", j)); - svUnsetValue (ifcfg, numbered_tag (tag, "PREFIX", j)); - svUnsetValue (ifcfg, numbered_tag (tag, "NETMASK", j)); - } - - for (j = -1; j < 256; j++) { - if (j != 0) - svUnsetValue (ifcfg, numbered_tag (tag, "GATEWAY", j)); - } svSetValueStr (ifcfg, "GATEWAY", nm_setting_ip_config_get_gateway (s_ip4)); - num = nm_setting_ip_config_get_num_dns (s_ip4); - for (i = 0; i < 254; i++) { - const char *dns; - - numbered_tag (tag, "DNS", i + 1); - if (i >= num) - svUnsetValue (ifcfg, tag); - else { - dns = nm_setting_ip_config_get_dns (s_ip4, i); - svSetValueStr (ifcfg, tag, dns); - } - } + write_dns_setting (ifcfg, connection, AF_INET); num = nm_setting_ip_config_get_num_dns_searches (s_ip4); if (num > 0) { @@ -2582,8 +2497,7 @@ write_ip4_setting (NMConnection *connection, } svSetValueStr (ifcfg, "DOMAIN", searches->str); g_string_free (searches, TRUE); - } else - svUnsetValue (ifcfg, "DOMAIN"); + } /* DEFROUTE; remember that it has the opposite meaning from never-default */ svSetValueBoolean (ifcfg, "DEFROUTE", !nm_setting_ip_config_get_never_default (s_ip4)); @@ -2644,8 +2558,7 @@ write_ip4_setting (NMConnection *connection, timeout = nm_setting_ip_config_get_dad_timeout (s_ip4); if (timeout < 0) { - svUnsetValue (ifcfg, "ACD_TIMEOUT"); - svUnsetValue (ifcfg, "ARPING_WAIT"); + /* pass */ } else if (timeout == 0) { svSetValueStr (ifcfg, "ACD_TIMEOUT", "0"); svSetValueStr (ifcfg, "ARPING_WAIT", "0"); @@ -2658,8 +2571,6 @@ write_ip4_setting (NMConnection *connection, priority = nm_setting_ip_config_get_dns_priority (s_ip4); if (priority) svSetValueInt64 (ifcfg, "IPV4_DNS_PRIORITY", priority); - else - svUnsetValue (ifcfg, "IPV4_DNS_PRIORITY"); write_res_options (ifcfg, s_ip4, "RES_OPTIONS"); @@ -2745,7 +2656,7 @@ write_ip4_aliases (NMConnection *connection, const char *base_ifcfg_path) svSetValueInt64 (ifcfg, "PREFIX", nm_ip_address_get_prefix(addr)); - svWriteFile (ifcfg, 0644, NULL); + svWriteFileWithoutDirtyWellknown (ifcfg, 0644, NULL); svCloseFile (ifcfg); } } @@ -2757,12 +2668,10 @@ write_ip6_setting (NMConnection *connection, GError **error) { NMSettingIPConfig *s_ip6; - NMSettingIPConfig *s_ip4; const char *value; - guint i, num, num4; + guint i, num; int priority; NMIPAddress *addr; - const char *dns; gint64 route_metric; NMIPRouteTableSyncMode route_table; GString *ip_str1, *ip_str2, *ip_ptr; @@ -2774,45 +2683,21 @@ write_ip6_setting (NMConnection *connection, NM_SET_OUT (out_route6_content, NULL); s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (!s_ip6) { - /* slave-type: clear IPv6 settings - * - * Some IPv6 setting related options are not cleared, - * for no strong reason. */ - svUnsetValue (ifcfg, "IPV6INIT"); - svUnsetValue (ifcfg, "IPV6_AUTOCONF"); - svUnsetValue (ifcfg, "DHCPV6C"); - svUnsetValue (ifcfg, "DHCPv6_DUID"); - svUnsetValue (ifcfg, "DHCPv6_IAID"); - svUnsetValue (ifcfg, "DHCPV6_HOSTNAME"); - svUnsetValue (ifcfg, "DHCPV6_SEND_HOSTNAME"); - svUnsetValue (ifcfg, "IPV6_DEFROUTE"); - svUnsetValue (ifcfg, "IPV6_PEERDNS"); - svUnsetValue (ifcfg, "IPV6_PEERROUTES"); - svUnsetValue (ifcfg, "IPV6_FAILURE_FATAL"); - svUnsetValue (ifcfg, "IPV6_ROUTE_METRIC"); - svUnsetValue (ifcfg, "IPV6_ADDR_GEN_MODE"); - svUnsetValue (ifcfg, "IPV6_RES_OPTIONS"); + if (!s_ip6) return TRUE; - } value = nm_setting_ip_config_get_method (s_ip6); g_assert (value); - svUnsetValue (ifcfg, "IPV6_DISABLED"); if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { svSetValueStr (ifcfg, "IPV6INIT", "no"); - svUnsetValue (ifcfg, "DHCPV6C"); return TRUE; } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) { svSetValueStr (ifcfg, "IPV6_DISABLED", "yes"); svSetValueStr (ifcfg, "IPV6INIT", "no"); - svUnsetValue (ifcfg, "DHCPV6C"); - svUnsetValue (ifcfg, "IPV6_AUTOCONF"); return TRUE; } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { svSetValueStr (ifcfg, "IPV6INIT", "yes"); svSetValueStr (ifcfg, "IPV6_AUTOCONF", "yes"); - svUnsetValue (ifcfg, "DHCPV6C"); } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) { svSetValueStr (ifcfg, "IPV6INIT", "yes"); svSetValueStr (ifcfg, "IPV6_AUTOCONF", "no"); @@ -2820,15 +2705,12 @@ write_ip6_setting (NMConnection *connection, } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) { svSetValueStr (ifcfg, "IPV6INIT", "yes"); svSetValueStr (ifcfg, "IPV6_AUTOCONF", "no"); - svUnsetValue (ifcfg, "DHCPV6C"); } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) { svSetValueStr (ifcfg, "IPV6INIT", "yes"); svSetValueStr (ifcfg, "IPV6_AUTOCONF", "no"); - svUnsetValue (ifcfg, "DHCPV6C"); } else if (!strcmp (value, NM_SETTING_IP6_CONFIG_METHOD_SHARED)) { svSetValueStr (ifcfg, "IPV6INIT", "yes"); svSetValueStr (ifcfg, "IPV6_AUTOCONF", "shared"); - svUnsetValue (ifcfg, "DHCPV6C"); } svSetValueStr (ifcfg, "DHCPV6_DUID", @@ -2842,9 +2724,7 @@ write_ip6_setting (NMConnection *connection, /* Missing DHCPV6_SEND_HOSTNAME means TRUE, and we prefer not write it * explicitly in that case, because it is NM-specific variable */ - if (nm_setting_ip_config_get_dhcp_send_hostname (s_ip6)) - svUnsetValue (ifcfg, "DHCPV6_SEND_HOSTNAME"); - else + if (!nm_setting_ip_config_get_dhcp_send_hostname (s_ip6)) svSetValueStr (ifcfg, "DHCPV6_SEND_HOSTNAME", "no"); timeout = nm_setting_ip6_config_get_ra_timeout (NM_SETTING_IP6_CONFIG (s_ip6)); @@ -2889,22 +2769,7 @@ write_ip6_setting (NMConnection *connection, g_string_free (ip_str1, TRUE); g_string_free (ip_str2, TRUE); - /* Write out DNS - 'DNS' key is used both for IPv4 and IPv6 */ - s_ip4 = nm_connection_get_setting_ip4_config (connection); - num4 = s_ip4 ? nm_setting_ip_config_get_num_dns (s_ip4) : 0; /* from where to start with IPv6 entries */ - num = nm_setting_ip_config_get_num_dns (s_ip6); - for (i = 0; i < 254; i++) { - char tag[64]; - - numbered_tag (tag, "DNS", i + num4 + 1); - - if (i >= num) - svUnsetValue (ifcfg, tag); - else { - dns = nm_setting_ip_config_get_dns (s_ip6, i); - svSetValueStr (ifcfg, tag, dns); - } - } + write_dns_setting (ifcfg, connection, AF_INET6); /* Write out DNS domains */ num = nm_setting_ip_config_get_num_dns_searches (s_ip6); @@ -2918,15 +2783,11 @@ write_ip6_setting (NMConnection *connection, g_string_append (searches, nm_setting_ip_config_get_dns_search (s_ip6, i)); } svSetValueStr (ifcfg, "IPV6_DOMAIN", searches->str); - } else - svUnsetValue (ifcfg, "IPV6_DOMAIN"); + } /* handle IPV6_DEFROUTE */ /* IPV6_DEFROUTE has the opposite meaning from 'never-default' */ - if (nm_setting_ip_config_get_never_default (s_ip6)) - svSetValueStr (ifcfg, "IPV6_DEFROUTE", "no"); - else - svSetValueStr (ifcfg, "IPV6_DEFROUTE", "yes"); + svSetValueBoolean (ifcfg, "IPV6_DEFROUTE", !nm_setting_ip_config_get_never_default (s_ip6)); svSetValueStr (ifcfg, "IPV6_PEERDNS", nm_setting_ip_config_get_ignore_auto_dns (s_ip6) ? "no" : NULL); @@ -2950,8 +2811,6 @@ write_ip6_setting (NMConnection *connection, route_table); /* IPv6 Privacy Extensions */ - svUnsetValue (ifcfg, "IPV6_PRIVACY"); - svUnsetValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP"); switch (nm_setting_ip6_config_get_ip6_privacy (NM_SETTING_IP6_CONFIG (s_ip6))) { case NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED: svSetValueStr (ifcfg, "IPV6_PRIVACY", "no"); @@ -2972,8 +2831,6 @@ write_ip6_setting (NMConnection *connection, if (addr_gen_mode != NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) { svSetValueEnum (ifcfg, "IPV6_ADDR_GEN_MODE", nm_setting_ip6_config_addr_gen_mode_get_type (), addr_gen_mode); - } else { - svUnsetValue (ifcfg, "IPV6_ADDR_GEN_MODE"); } /* IPv6 tokenized interface identifier */ @@ -2983,8 +2840,6 @@ write_ip6_setting (NMConnection *connection, priority = nm_setting_ip_config_get_dns_priority (s_ip6); if (priority) svSetValueInt64 (ifcfg, "IPV6_DNS_PRIORITY", priority); - else - svUnsetValue (ifcfg, "IPV6_DNS_PRIORITY"); write_res_options (ifcfg, s_ip6, "IPV6_RES_OPTIONS"); @@ -3001,8 +2856,6 @@ write_ip_routing_rules (NMConnection *connection, gsize idx; int is_ipv4; - svUnsetAll (ifcfg, SV_KEY_TYPE_ROUTING_RULE4 | SV_KEY_TYPE_ROUTING_RULE6); - if (route_ignore) return; @@ -3233,8 +3086,6 @@ do_write_construct (NMConnection *connection, if (!write_tc_setting (connection, ifcfg, error)) return FALSE; - svUnsetValue (ifcfg, "DHCP_HOSTNAME"); - svUnsetValue (ifcfg, "DHCP_FQDN"); route_path_is_svformat = utils_has_route_file_new_syntax (route_path); @@ -3321,7 +3172,7 @@ do_write_to_disk (NMConnection *connection, * only. But we loaded the ifcfg files from disk, and managled our * new settings (in-memory). */ - if (!svWriteFile (ifcfg, 0644, error)) + if (!svWriteFileWithoutDirtyWellknown (ifcfg, 0644, error)) return FALSE; write_ip4_aliases (connection, svFileGetName (ifcfg)); @@ -3340,7 +3191,7 @@ do_write_to_disk (NMConnection *connection, else { nm_assert (route_content_svformat || route_content); if (route_content_svformat) { - if (!svWriteFile (route_content_svformat, 0644, error)) + if (!svWriteFileWithoutDirtyWellknown (route_content_svformat, 0644, error)) return FALSE; } else { if (!g_file_set_contents (route_path, route_content->str, route_content->len, NULL)) { @@ -3450,6 +3301,11 @@ nms_ifcfg_rh_writer_write_connection (NMConnection *connection, _LOGW ("write: failure to re-read connection \"%s\": %s", svFileGetName (ifcfg), "connection is unhandled"); } else { + /* ifcfg-rh doesn't support the 'timestamp' property, let's add it here */ + g_object_set (nm_connection_get_setting_connection (reread), + NM_SETTING_CONNECTION_TIMESTAMP, + nm_setting_connection_get_timestamp (nm_connection_get_setting_connection (connection)), + NULL); if (out_reread_same) { reread_same = nm_connection_compare (reread, connection, NM_SETTING_COMPARE_FLAG_EXACT); if (!reread_same) { diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index 16b2dd37..f2a1dd78 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -19,13 +19,23 @@ #include "nm-glib-aux/nm-enum-utils.h" #include "nm-glib-aux/nm-io-utils.h" #include "c-list/src/c-list.h" +#include "nms-ifcfg-rh-utils.h" /*****************************************************************************/ struct _shvarLine { + const char *key; + CList lst; + /* We index variables by their key in shvarFile.lst_idx. One shell variable might + * occur multiple times in a file (in which case the last occurrence wins). + * Hence, we need to keep a list of all the same keys. + * + * This is a pointer to the next shadowed line. */ + struct _shvarLine *prev_shadowed; + /* There are three cases: * * 1) the line is not a valid variable assignment (that is, it doesn't @@ -43,21 +53,41 @@ struct _shvarLine { * @key/@key_with_prefix. * */ char *line; - const char *key; char *key_with_prefix; + + /* svSetValue() will clear the dirty flag. */ + bool dirty:1; }; typedef struct _shvarLine shvarLine; struct _shvarFile { - char *fileName; - int fd; - CList lst_head; - gboolean modified; + char *fileName; + CList lst_head; + GHashTable *lst_idx; + int fd; + bool modified:1; }; /*****************************************************************************/ +static void _line_link_parse (shvarFile *s, const char *value, gsize len); + +/*****************************************************************************/ + +#define ASSERT_key_is_well_known(key) \ + nm_assert ( ({ \ + const char *_key = (key); \ + gboolean _is_wellknown = TRUE; \ + \ + if (!nms_ifcfg_rh_utils_is_well_known_key (_key)) { \ + _is_wellknown = FALSE; \ + g_critical ("ifcfg-rh key \"%s\" is not well-known", _key); \ + } \ + \ + _is_wellknown; \ + }) ) + /** * svParseBoolean: * @value: the input string @@ -603,15 +633,33 @@ out_error: /*****************************************************************************/ -static shvarFile * -svFile_new (const char *name) +shvarFile * +svFile_new (const char *name, + int fd, + const char *content) { shvarFile *s; + const char *p; + const char *q; + + nm_assert (name); + nm_assert (fd >= -1); + + s = g_slice_new (shvarFile); + *s = (shvarFile) { + .fileName = g_strdup (name), + .fd = fd, + .lst_head = C_LIST_INIT (s->lst_head), + .lst_idx = g_hash_table_new (nm_pstr_hash, nm_pstr_equal), + }; + + if (content) { + for (p = content; (q = strchr (p, '\n')) != NULL; p = q + 1) + _line_link_parse (s, p, q - p); + if (p[0]) + _line_link_parse (s, p, strlen (p)); + } - s = g_slice_new0 (shvarFile); - s->fd = -1; - s->fileName = g_strdup (name); - c_list_init (&s->lst_head); return s; } @@ -671,8 +719,11 @@ line_new_parse (const char *value, gsize len) nm_assert (value); - line = g_slice_new0 (shvarLine); - c_list_init (&line->lst); + line = g_slice_new (shvarLine); + *line = (shvarLine) { + .lst = C_LIST_INIT (line->lst), + .dirty = TRUE, + }; for (k = 0; k < len; k++) { if (g_ascii_isspace (value[k])) @@ -706,14 +757,19 @@ line_new_build (const char *key, const char *value) { char *value_escaped = NULL; shvarLine *line; + char *new_key; value = svEscape (value, &value_escaped); line = g_slice_new (shvarLine); - c_list_init (&line->lst); - line->line = value_escaped ?: g_strdup (value); - line->key_with_prefix = g_strdup (key); - line->key = line->key_with_prefix; + new_key = g_strdup (key), + *line = (shvarLine) { + .lst = C_LIST_INIT (line->lst), + .line = value_escaped ?: g_strdup (value), + .key_with_prefix = new_key, + .key = new_key, + .dirty = FALSE, + }; ASSERT_shvarLine (line); return line; } @@ -727,6 +783,8 @@ line_set (shvarLine *line, const char *value) ASSERT_shvarLine (line); nm_assert (line->key); + line->dirty = FALSE; + if (line->key != line->key_with_prefix) { memmove (line->key_with_prefix, line->key, strlen (line->key) + 1); line->key = line->key_with_prefix; @@ -753,14 +811,48 @@ static void line_free (shvarLine *line) { ASSERT_shvarLine (line); + c_list_unlink_stale (&line->lst); g_free (line->line); g_free (line->key_with_prefix); - c_list_unlink_stale (&line->lst); g_slice_free (shvarLine, line); } /*****************************************************************************/ +static void +_line_link_parse (shvarFile *s, const char *value, gsize len) +{ + shvarLine *line; + + line = line_new_parse (value, len); + if (!line->key) + goto do_link; + + if (G_UNLIKELY (!g_hash_table_insert (s->lst_idx, line, line))) { + shvarLine *existing_key; + shvarLine *existing_val; + + /* Slow-path: we have duplicate keys. Fix the mess we created. + * Unfortunately, g_hash_table_insert() now had to allocate an extra + * array to track the keys/values differently. I wish there was an + * GHashTable API to add a key only if it does not exist yet. */ + + if (!g_hash_table_lookup_extended (s->lst_idx, line, (gpointer *) &existing_key, (gpointer *) &existing_val)) + nm_assert_not_reached (); + + nm_assert (existing_val == line); + nm_assert (existing_key != line); + line->prev_shadowed = existing_key; + g_hash_table_replace (s->lst_idx, line, line); + } + +do_link: + c_list_link_tail (&s->lst_head, &line->lst); +} + +/*****************************************************************************/ + + /* Open the file <name>, returning a shvarFile on success and NULL on failure. * Add a wrinkle to let the caller specify whether or not to create the file * (actually, return a structure anyway) if it doesn't exist. @@ -768,11 +860,9 @@ line_free (shvarLine *line) static shvarFile * svOpenFileInternal (const char *name, gboolean create, GError **error) { - shvarFile *s; gboolean closefd = FALSE; int errsv = 0; - gs_free char *arena = NULL; - const char *p, *q; + gs_free char *content = NULL; gs_free_error GError *local = NULL; nm_auto_close int fd = -1; @@ -789,7 +879,7 @@ svOpenFileInternal (const char *name, gboolean create, GError **error) if (fd < 0) { if (create) - return svFile_new (name); + return svFile_new (name, -1, NULL); g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errsv), "Could not read file '%s': %s", @@ -801,12 +891,12 @@ svOpenFileInternal (const char *name, gboolean create, GError **error) closefd, 10 * 1024 * 1024, NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, - &arena, + &content, NULL, NULL, &local)) { if (create) - return svFile_new (name); + return svFile_new (name, -1, NULL); g_set_error (error, G_FILE_ERROR, local->domain == G_FILE_ERROR ? local->code : G_FILE_ERROR_FAILED, @@ -815,21 +905,14 @@ svOpenFileInternal (const char *name, gboolean create, GError **error) return NULL; } - s = svFile_new (name); - - for (p = arena; (q = strchr (p, '\n')) != NULL; p = q + 1) - c_list_link_tail (&s->lst_head, &line_new_parse (p, q - p)->lst); - if (p[0]) - c_list_link_tail (&s->lst_head, &line_new_parse (p, strlen (p))->lst); - /* closefd is set if we opened the file read-only, so go ahead and * close it, because we can't write to it anyway */ - if (!closefd) { - nm_assert (fd > 0); - s->fd = nm_steal_fd (&fd); - } - - return s; + nm_assert (closefd || fd >= 0); + return svFile_new (name, + !closefd + ? nm_steal_fd (&fd) + : -1, + content); } /* Open the file <name>, return shvarFile on success, NULL on failure */ @@ -851,54 +934,32 @@ svCreateFile (const char *name) /*****************************************************************************/ static gboolean -_is_all_digits (const char *str) +_svKeyMatchesType (const char *key, SvKeyType match_key_type) { - return str[0] - && NM_STRCHAR_ALL (str, ch, g_ascii_isdigit (ch)); -} - -#define IS_NUMBERED_TAG(key, tab_name) \ - ({ \ - const char *_key2 = (key); \ - \ - ( (strncmp (_key2, tab_name, NM_STRLEN (tab_name)) == 0) \ - && _is_all_digits (&_key2[NM_STRLEN (tab_name)])); \ - }) + if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ANY)) + return TRUE; -#define IS_NUMBERED_TAG_PARSE(key, tab_name, out_idx) \ +#define _IS_NUMBERED(key, tag) \ ({ \ - const char *_key = (key); \ gint64 _idx; \ - gboolean _good = FALSE; \ - gint64 *_out_idx = (out_idx); \ \ - if ( IS_NUMBERED_TAG (_key, ""tab_name"") \ - && (_idx = _nm_utils_ascii_str_to_int64 (&_key[NM_STRLEN (tab_name)], 10, 0, G_MAXINT64, -1)) != -1) { \ - NM_SET_OUT (_out_idx, _idx); \ - _good = TRUE; \ - } \ - _good; \ + NMS_IFCFG_RH_UTIL_IS_NUMBERED_TAG (key, tag, &_idx) \ + && _idx >= 0; \ }) -static gboolean -_svKeyMatchesType (const char *key, SvKeyType match_key_type) -{ - if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ANY)) - return TRUE; - if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ROUTE_SVFORMAT)) { - if ( IS_NUMBERED_TAG (key, "ADDRESS") - || IS_NUMBERED_TAG (key, "NETMASK") - || IS_NUMBERED_TAG (key, "GATEWAY") - || IS_NUMBERED_TAG (key, "METRIC") - || IS_NUMBERED_TAG (key, "OPTIONS")) + if ( _IS_NUMBERED (key, "ADDRESS") + || _IS_NUMBERED (key, "NETMASK") + || _IS_NUMBERED (key, "GATEWAY") + || _IS_NUMBERED (key, "METRIC") + || _IS_NUMBERED (key, "OPTIONS")) return TRUE; } if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_IP4_ADDRESS)) { - if ( IS_NUMBERED_TAG (key, "IPADDR") - || IS_NUMBERED_TAG (key, "PREFIX") - || IS_NUMBERED_TAG (key, "NETMASK") - || IS_NUMBERED_TAG (key, "GATEWAY")) + if ( _IS_NUMBERED (key, "IPADDR") + || _IS_NUMBERED (key, "PREFIX") + || _IS_NUMBERED (key, "NETMASK") + || _IS_NUMBERED (key, "GATEWAY")) return TRUE; } if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_USER)) { @@ -906,20 +967,20 @@ _svKeyMatchesType (const char *key, SvKeyType match_key_type) return TRUE; } if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_TC)) { - if ( IS_NUMBERED_TAG (key, "QDISC") - || IS_NUMBERED_TAG (key, "FILTER")) + if ( _IS_NUMBERED (key, "QDISC") + || _IS_NUMBERED (key, "FILTER")) return TRUE; } if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_SRIOV_VF)) { - if (IS_NUMBERED_TAG (key, "SRIOV_VF")) + if (_IS_NUMBERED (key, "SRIOV_VF")) return TRUE; } if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ROUTING_RULE4)) { - if (IS_NUMBERED_TAG_PARSE (key, "ROUTING_RULE_", NULL)) + if (_IS_NUMBERED (key, "ROUTING_RULE_")) return TRUE; } if (NM_FLAGS_HAS (match_key_type, SV_KEY_TYPE_ROUTING_RULE6)) { - if (IS_NUMBERED_TAG_PARSE (key, "ROUTING_RULE6_", NULL)) + if (_IS_NUMBERED (key, "ROUTING_RULE6_")) return TRUE; } @@ -931,9 +992,8 @@ svNumberedParseKey (const char *key) { gint64 idx; - if (IS_NUMBERED_TAG_PARSE (key, "ROUTING_RULE_", &idx)) - return idx; - if (IS_NUMBERED_TAG_PARSE (key, "ROUTING_RULE6_", &idx)) + if ( NMS_IFCFG_RH_UTIL_IS_NUMBERED_TAG (key, "ROUTING_RULE_", &idx) + || NMS_IFCFG_RH_UTIL_IS_NUMBERED_TAG (key, "ROUTING_RULE6_", &idx)) return idx; return -1; } @@ -1001,20 +1061,18 @@ svGetKeysSorted (shvarFile *s, /*****************************************************************************/ const char * -svFindFirstKeyWithPrefix (shvarFile *s, const char *key_prefix) +svFindFirstNumberedKey (shvarFile *s, const char *key_prefix) { - CList *current; - const shvarLine *l; + const shvarLine *line; g_return_val_if_fail (s, NULL); g_return_val_if_fail (key_prefix, NULL); - c_list_for_each (current, &s->lst_head) { - l = c_list_entry (current, shvarLine, lst); - if ( l->key - && l->line - && g_str_has_prefix (l->key, key_prefix)) - return l->key; + c_list_for_each_entry (line, &s->lst_head, lst) { + if ( line->key + && line->line + && nms_ifcfg_rh_utils_is_numbered_tag (line->key, key_prefix, NULL)) + return line->key; } return NULL; @@ -1025,20 +1083,16 @@ svFindFirstKeyWithPrefix (shvarFile *s, const char *key_prefix) static const char * _svGetValue (shvarFile *s, const char *key, char **to_free) { - CList *current; - const shvarLine *line, *l; + const shvarLine *line; const char *v; nm_assert (s); nm_assert (_shell_is_name (key, -1)); nm_assert (to_free); - line = NULL; - c_list_for_each (current, &s->lst_head) { - l = c_list_entry (current, shvarLine, lst); - if (l->key && nm_streq (l->key, key)) - line = l; - } + ASSERT_key_is_well_known (key); + + line = g_hash_table_lookup (s->lst_idx, &key); if (line && line->line) { v = svUnescape (line->line, to_free); @@ -1229,24 +1283,53 @@ svGetValueEnum (shvarFile *s, const char *key, gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type) { - CList *current; shvarLine *line; gboolean changed = FALSE; g_return_val_if_fail (s, FALSE); - c_list_for_each (current, &s->lst_head) { - line = c_list_entry (current, shvarLine, lst); + c_list_for_each_entry (line, &s->lst_head, lst) { ASSERT_shvarLine (line); - if (!line->key) - continue; + if ( line->key + && _svKeyMatchesType (line->key, match_key_type)) { + if (nm_clear_g_free (&line->line)) { + ASSERT_shvarLine (line); + changed = TRUE; + } + } + } - if (_svKeyMatchesType (line->key, match_key_type)) { + if (changed) + s->modified = TRUE; + return changed; +} + +gboolean +svUnsetDirtyWellknown (shvarFile *s, NMTernary new_dirty_value) +{ + shvarLine *line; + gboolean changed = FALSE; + + g_return_val_if_fail (s, FALSE); + + c_list_for_each_entry (line, &s->lst_head, lst) { + const NMSIfcfgKeyTypeInfo *ti; + + ASSERT_shvarLine (line); + + if ( line->dirty + && line->key + && line->line + && (ti = nms_ifcfg_rh_utils_is_well_known_key (line->key)) + && !NM_FLAGS_HAS (ti->key_flags, NMS_IFCFG_KEY_TYPE_KEEP_WHEN_DIRTY)) { if (nm_clear_g_free (&line->line)) { ASSERT_shvarLine (line); changed = TRUE; } } + + if (new_dirty_value != NM_TERNARY_DEFAULT) + line->dirty = (new_dirty_value != NM_TERNARY_FALSE); } if (changed) @@ -1259,8 +1342,8 @@ svUnsetAll (shvarFile *s, SvKeyType match_key_type) gboolean svSetValue (shvarFile *s, const char *key, const char *value) { - CList *current; - shvarLine *line, *l; + shvarLine *line; + shvarLine *l_shadowed; gboolean changed = FALSE; g_return_val_if_fail (s, FALSE); @@ -1268,29 +1351,37 @@ svSetValue (shvarFile *s, const char *key, const char *value) nm_assert (_shell_is_name (key, -1)); - line = NULL; - c_list_for_each (current, &s->lst_head) { - l = c_list_entry (current, shvarLine, lst); - if (l->key && nm_streq (l->key, key)) { - if (line) { - /* if we find multiple entries for the same key, we can - * delete all but the last. */ - line_free (line); - changed = TRUE; - } - line = l; - } + ASSERT_key_is_well_known (key); + + line = g_hash_table_lookup (s->lst_idx, &key); + if ( line + && (l_shadowed = line->prev_shadowed)) { + /* if we find multiple entries for the same key, we can + * delete the shadowed ones. */ + line->prev_shadowed = NULL; + changed = TRUE; + do { + shvarLine *l = l_shadowed; + + l_shadowed = l_shadowed->prev_shadowed; + line_free (l); + } while (l_shadowed); } if (!value) { if (line) { + /* We only clear the value, but leave the line entry. This way, if we + * happen to re-add the value, we write it to the same line again. */ if (nm_clear_g_free (&line->line)) { changed = TRUE; } } } else { if (!line) { - c_list_link_tail (&s->lst_head, &line_new_build (key, value)->lst); + line = line_new_build (key, value); + if (!g_hash_table_add (s->lst_idx, line)) + nm_assert_not_reached (); + c_list_link_tail (&s->lst_head, &line->lst); changed = TRUE; } else { if (line_set (line, value)) @@ -1442,14 +1533,15 @@ svWriteFile (shvarFile *s, int mode, GError **error) void svCloseFile (shvarFile *s) { - CList *current, *safe; + shvarLine *line; g_return_if_fail (s != NULL); if (s->fd >= 0) nm_close (s->fd); g_free (s->fileName); - c_list_for_each_safe (current, safe, &s->lst_head) - line_free (c_list_entry (current, shvarLine, lst)); + g_hash_table_destroy (s->lst_idx); + while ((line = c_list_first_entry (&s->lst_head, shvarLine, lst))) + line_free (line); g_slice_free (shvarFile, s); } diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index c3bbabab..410284f8 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -24,13 +24,21 @@ const char *svFileGetName (const shvarFile *s); void _nmtst_svFileSetName (shvarFile *s, const char *fileName); void _nmtst_svFileSetModified (shvarFile *s); +/*****************************************************************************/ + +shvarFile *svFile_new (const char *name, + int fd, + const char *content); + /* Create the file <name>, return a shvarFile (never fails) */ shvarFile *svCreateFile (const char *name); /* Open the file <name>, return shvarFile on success, NULL on failure */ shvarFile *svOpenFile (const char *name, GError **error); -const char *svFindFirstKeyWithPrefix (shvarFile *s, const char *key_prefix); +/*****************************************************************************/ + +const char *svFindFirstNumberedKey (shvarFile *s, const char *key_prefix); /* Get the value associated with the key, and leave the current pointer * pointing at the line containing the value. The char* returned MUST @@ -79,6 +87,7 @@ gboolean svSetValueEnum (shvarFile *s, const char *key, GType gtype, int value); gboolean svUnsetValue (shvarFile *s, const char *key); gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type); +gboolean svUnsetDirtyWellknown (shvarFile *s, NMTernary new_dirty_value); /* Write the current contents iff modified. Returns FALSE on error * and TRUE on success. Do not write if no values have been modified. @@ -88,6 +97,13 @@ gboolean svUnsetAll (shvarFile *s, SvKeyType match_key_type); */ gboolean svWriteFile (shvarFile *s, int mode, GError **error); +static inline gboolean +svWriteFileWithoutDirtyWellknown (shvarFile *s, int mode, GError **error) +{ + svUnsetDirtyWellknown (s, NM_TERNARY_FALSE); + return svWriteFile (s, mode, error); +} + /* Close the file descriptor (if open) and free the shvarFile. */ void svCloseFile (shvarFile *s); diff --git a/src/settings/plugins/ifcfg-rh/tests/meson.build b/src/settings/plugins/ifcfg-rh/tests/meson.build index 21699045..1ce61c90 100644 --- a/src/settings/plugins/ifcfg-rh/tests/meson.build +++ b/src/settings/plugins/ifcfg-rh/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_unit = 'test-ifcfg-rh' exe = executable( diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected index d4785ff5..2e69c5e7 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-System_test-bridge-component-b.cexpected @@ -1,6 +1,5 @@ HWADDR=00:22:15:59:62:97 TYPE=Ethernet -BRIDGING_OPTS="priority=28 hairpin_mode=1" NAME="System test-bridge-component" UUID=${UUID} DEVICE=eth0 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected index 36df7712..b288c04a 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bond_Main.cexpected @@ -1,4 +1,4 @@ -BONDING_OPTS="downdelay=5 miimon=100 mode=balance-rr updelay=10" +BONDING_OPTS="mode=balance-rr downdelay=5 miimon=100 updelay=10" TYPE=Bond BONDING_MASTER=yes HWADDR= diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected index 5dfdce4d..87493ac2 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-netmask-1.cexpected @@ -2,7 +2,6 @@ DNS1=192.0.2.1 IPADDR=102.0.2.2 GATEWAY=192.0.2.1 NETMASK=255.254.0.0 -BOOTPROTO="static" DEVICE=eth1 ONBOOT=yes IPV6INIT=yes diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-owe b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-owe new file mode 100644 index 00000000..354046ad --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-owe @@ -0,0 +1,5 @@ +TYPE=Wireless +DEVICE=wlan1 +ESSID=blahblah_owe +MODE=Managed +KEY_MGMT=OWE diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk index a78051aa..4ab45ae3 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-wpa-psk @@ -16,4 +16,4 @@ CIPHER_GROUP="TKIP CCMP WEP40 WEP104" KEY_MGMT=WPA-PSK WPA_ALLOW_WPA=yes WPA_ALLOW_WPA2=yes -LAST_ENTRY=no-newline \ No newline at end of file +CTCPROT=no-newline \ No newline at end of file diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-autoip b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-autoip index dc47126c..e683db3c 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-autoip +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-autoip @@ -3,3 +3,4 @@ DEVICE=eth0 BOOTPROTO=autoip IPV4_FAILURE_FATAL=yes PEERDNS=no +DEVTIMEOUT=2.6 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4 index 2c1b7fb4..f834464e 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4 +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4 @@ -5,32 +5,32 @@ # don't consider only line-by-line, thus this is # expected. # -# Also note that setting NAME will replace the last +# Also note that setting IPADDR will replace the last # occurrence, and delete all previous once. #L1 -NAME=l2 +IPADDR=l2 #L2 -NAME=l3 +IPADDR=l3 -some_key1='' -some_key2=$'\U0x' -some_key3=$'x\U0' +METRIC1='' +METRIC2=$'\U0x' +METRIC3=$'x\U0' #L4 -NAME=' -NAME=l4x +IPADDR=' +IPADDR=l4x ' #Lx-1 -NAME2=not-visible +IPADDR2=not-visible #Lx-2 -NAME2='invalid +IPADDR2='invalid #Lx-3 #Ly-1 -NAME3='invalid +IPADDR3='invalid #Ly-2 -NAME3=name3-value +IPADDR3=name3-value #Ly-3 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected index cf3f45bd..040ddc9d 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-write-unknown-4.expected @@ -5,27 +5,27 @@ # don't consider only line-by-line, thus this is # expected. # -# Also note that setting NAME will replace the last +# Also note that setting IPADDR will replace the last # occurrence, and delete all previous once. #L1 #L2 -some_key1='' -some_key2=$'\U0x' -some_key3=$'x\U0' +METRIC1='' +METRIC2=$'\U0x' +METRIC3=$'x\U0' #L4 -NAME=set-by-test1 +IPADDR=set-by-test1 #NM: ' #Lx-1 #Lx-2 -NAME2=set-by-test2 +IPADDR2=set-by-test2 #Lx-3 #Ly-1 #Ly-2 -NAME3=set-by-test3 +IPADDR3=set-by-test3 #Ly-3 diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index 675421d3..efa9ea9b 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -1738,6 +1738,7 @@ static void test_read_wired_autoip (void) { gs_unref_object NMConnection *connection = NULL; + NMSettingConnection *s_con; NMSettingIPConfig *s_ip4; char *unmanaged = NULL; @@ -1751,6 +1752,9 @@ test_read_wired_autoip (void) g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL); g_assert (!nm_setting_ip_config_get_may_fail (s_ip4)); g_assert (nm_setting_ip_config_get_ignore_auto_dns (s_ip4)); + + s_con = nm_connection_get_setting_connection (connection); + g_assert_cmpint (nm_setting_connection_get_wait_device_timeout (s_con), ==, 2600); } static void @@ -2094,7 +2098,7 @@ test_read_wired_aliases_good (gconstpointer test_data) g_assert (ip4_addr != NULL); addr = nm_ip_address_get_address (ip4_addr); - g_assert (nm_utils_ipaddr_valid (AF_INET, addr)); + g_assert (nm_utils_ipaddr_is_valid (AF_INET, addr)); for (j = 0; j < expected_num_addresses; j++) { if (!g_strcmp0 (addr, expected_address[j])) @@ -2868,7 +2872,7 @@ test_ifcfg_no_trailing_newline (void) shvarFile *sv; sv = _svOpenFile (TEST_IFCFG_DIR"/ifcfg-test-wifi-wpa-psk"); - _svGetValue_check (sv, "LAST_ENTRY", "no-newline"); + _svGetValue_check (sv, "CTCPROT", "no-newline"); svCloseFile (sv); } @@ -3035,6 +3039,45 @@ test_read_wifi_sae (void) } static void +test_read_wifi_owe (void) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingConnection *s_con; + NMSettingWireless *s_wireless; + NMSettingWirelessSecurity *s_wsec; + GBytes *ssid; + const char *expected_ssid = "blahblah_owe"; + + connection = _connection_from_file (TEST_IFCFG_DIR"/ifcfg-test-wifi-owe", + NULL, TYPE_WIRELESS, NULL); + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "System blahblah_owe (test-wifi-owe)"); + + g_assert_cmpint (nm_setting_connection_get_timestamp (s_con), ==, 0); + g_assert (nm_setting_connection_get_autoconnect (s_con)); + + s_wireless = nm_connection_get_setting_wireless (connection); + g_assert (s_wireless); + + g_assert_cmpint (nm_setting_wireless_get_mtu (s_wireless), ==, 0); + + ssid = nm_setting_wireless_get_ssid (s_wireless); + g_assert (ssid); + g_assert_cmpmem (g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid), expected_ssid, strlen (expected_ssid)); + + g_assert (!nm_setting_wireless_get_bssid (s_wireless)); + g_assert_cmpstr (nm_setting_wireless_get_mode (s_wireless), ==, "infrastructure"); + + s_wsec = nm_connection_get_setting_wireless_security (connection); + g_assert (s_wsec); + g_assert_cmpstr (nm_setting_wireless_security_get_key_mgmt (s_wsec), ==, "owe"); + g_assert (!nm_setting_wireless_security_get_psk (s_wsec)); + g_assert (!nm_setting_wireless_security_get_auth_alg (s_wsec)); +} + +static void test_read_wifi_wpa_psk_2 (void) { NMConnection *connection; @@ -9742,23 +9785,23 @@ test_write_unknown (gconstpointer test_data) _nmtst_svFileSetModified (sv); if (g_str_has_suffix (testfile, "ifcfg-test-write-unknown-4")) { - _svGetValue_check (sv, "NAME", "l4x"); - _svGetValue_check (sv, "NAME2", ""); - _svGetValue_check (sv, "NAME3", "name3-value"); - - svSetValue (sv, "NAME", "set-by-test1"); - svSetValue (sv, "NAME2", NULL); - svSetValue (sv, "NAME2", "set-by-test2"); - svSetValue (sv, "NAME3", "set-by-test3"); - - _svGetValue_check (sv, "some_key", NULL); - _svGetValue_check (sv, "some_key1", ""); - _svGetValue_check (sv, "some_key2", ""); - _svGetValue_check (sv, "some_key3", "x"); - - _svGetValue_check (sv, "NAME", "set-by-test1"); - _svGetValue_check (sv, "NAME2", "set-by-test2"); - _svGetValue_check (sv, "NAME3", "set-by-test3"); + _svGetValue_check (sv, "IPADDR", "l4x"); + _svGetValue_check (sv, "IPADDR2", ""); + _svGetValue_check (sv, "IPADDR3", "name3-value"); + + svSetValue (sv, "IPADDR", "set-by-test1"); + svSetValue (sv, "IPADDR2", NULL); + svSetValue (sv, "IPADDR2", "set-by-test2"); + svSetValue (sv, "IPADDR3", "set-by-test3"); + + _svGetValue_check (sv, "METRIC", NULL); + _svGetValue_check (sv, "METRIC1", ""); + _svGetValue_check (sv, "METRIC2", ""); + _svGetValue_check (sv, "METRIC3", "x"); + + _svGetValue_check (sv, "IPADDR", "set-by-test1"); + _svGetValue_check (sv, "IPADDR2", "set-by-test2"); + _svGetValue_check (sv, "IPADDR3", "set-by-test3"); } success = svWriteFile (sv, 0644, &error); @@ -10203,6 +10246,160 @@ test_tc_write (void) /*****************************************************************************/ +static void +test_well_known_keys (void) +{ + gsize i; + + for (i = 0; i < G_N_ELEMENTS (nms_ifcfg_well_known_keys); i++) { + const NMSIfcfgKeyTypeInfo *ti = &nms_ifcfg_well_known_keys[i]; + + g_assert (ti->key_name); + g_assert (ti->key_name[0]); + g_assert (NM_FLAGS_HAS (ti->key_flags, NMS_IFCFG_KEY_TYPE_WELL_KNOWN)); + g_assert (nm_utils_is_power_of_two (ti->key_flags & ( NMS_IFCFG_KEY_TYPE_IS_PLAIN + | NMS_IFCFG_KEY_TYPE_IS_NUMBERED + | NMS_IFCFG_KEY_TYPE_IS_PREFIX))); + } + + for (i = 1; i < G_N_ELEMENTS (nms_ifcfg_well_known_keys); i++) { + const NMSIfcfgKeyTypeInfo *ti_prev = &nms_ifcfg_well_known_keys[i - 1]; + const NMSIfcfgKeyTypeInfo *ti = &nms_ifcfg_well_known_keys[i]; + + g_assert_cmpstr (ti_prev->key_name, <, ti->key_name); + } + + for (i = 0; i < G_N_ELEMENTS (nms_ifcfg_well_known_keys); i++) { + const NMSIfcfgKeyTypeInfo *ti = &nms_ifcfg_well_known_keys[i]; + gs_free char *key_name = NULL; + gssize idx; + + g_assert (ti == nms_ifcfg_well_known_key_find_info (ti->key_name, &idx)); + g_assert_cmpint (i, ==, idx); + + key_name = g_strdup (ti->key_name); + g_assert (ti == nms_ifcfg_well_known_key_find_info (key_name, &idx)); + g_assert_cmpint (i, ==, idx); + } + +#define _test_well_known(key, expected) \ + G_STMT_START { \ + const NMSIfcfgKeyTypeInfo *_ti; \ + const char *_expected = (expected); \ + \ + _ti = nms_ifcfg_rh_utils_is_well_known_key (""key""); \ + if (!_expected) { \ + g_assert (!_ti); \ + } else { \ + g_assert (_ti); \ + g_assert_cmpstr (_ti->key_name, ==, _expected); \ + } \ + } G_STMT_END + +#define _test_well_known_plain(key) \ + _test_well_known (""key"", ""key"") + + _test_well_known_plain ("ONBOOT"); + _test_well_known ("NM_USER_", NULL); + _test_well_known ("NM_USER_x", "NM_USER_"); + _test_well_known ("IPADDR", "IPADDR"); + _test_well_known ("IPADDR1", "IPADDR"); + _test_well_known ("IPADDRx", NULL); +} + +/*****************************************************************************/ + +static void +_do_utils_has_route_file_new_syntax_size (gboolean has_new_syntax, + const char *content, + gssize content_len) +{ + nmtst_auto_unlinkfile char *testfile = g_strdup (TEST_SCRATCH_DIR"/utils-has-route-file-new-syntax-test.txt"); + gboolean val; + + nmtst_file_set_contents_size (testfile, content, content_len); + + val = utils_has_route_file_new_syntax (testfile); + + g_assert_cmpint (val, ==, has_new_syntax); +} +#define _do_utils_has_route_file_new_syntax(has_new_syntax, content) \ + _do_utils_has_route_file_new_syntax_size (has_new_syntax, (content), NM_STRLEN (content)) + +static void +test_utils_has_route_file_new_syntax (void) +{ + _do_utils_has_route_file_new_syntax (TRUE, ""); + _do_utils_has_route_file_new_syntax (FALSE, "\0"); + _do_utils_has_route_file_new_syntax (FALSE, "\n"); + _do_utils_has_route_file_new_syntax (FALSE, "ADDRESS=bogus"); + _do_utils_has_route_file_new_syntax (FALSE, "ADDRESS=bogus\0"); + _do_utils_has_route_file_new_syntax (TRUE, "ADDRESS1=b\0ogus\0"); + _do_utils_has_route_file_new_syntax (TRUE, "ADDRESS1=bogus\0"); + _do_utils_has_route_file_new_syntax (TRUE, "\n\n\tADDRESS1=bogus\0"); + _do_utils_has_route_file_new_syntax (FALSE, "\n\n\tADDRESS=bogus\n"); + _do_utils_has_route_file_new_syntax (TRUE, "\n\n\tADDRESS=bogus\n ADDRESS000=\n"); + _do_utils_has_route_file_new_syntax (FALSE, "\n\n\tROUTE1=bogus\n ADDRES=\n"); + _do_utils_has_route_file_new_syntax (FALSE, "\n\n\tADDRESS=bogus\n ADDRESS\000000=\n"); +} + +/*****************************************************************************/ + +static void +test_ethtool_names (void) +{ + static const struct { + NMEthtoolID ethtool_id; + const char *kernel_name; + } kernel_names[] = { + { NM_ETHTOOL_ID_FEATURE_GRO, "rx-gro" }, + { NM_ETHTOOL_ID_FEATURE_GSO, "tx-generic-segmentation" }, + { NM_ETHTOOL_ID_FEATURE_LRO, "rx-lro" }, + { NM_ETHTOOL_ID_FEATURE_NTUPLE, "rx-ntuple-filter" }, + { NM_ETHTOOL_ID_FEATURE_RX, "rx-checksum" }, + { NM_ETHTOOL_ID_FEATURE_RXHASH, "rx-hashing" }, + { NM_ETHTOOL_ID_FEATURE_RXVLAN, "rx-vlan-hw-parse" }, + { NM_ETHTOOL_ID_FEATURE_TXVLAN, "tx-vlan-hw-insert" }, + }; + const NMEthtoolData *data; + NMEthtoolID id; + int i; + + for (id = _NM_ETHTOOL_ID_FEATURE_FIRST; id <= _NM_ETHTOOL_ID_FEATURE_LAST; id++) { + const char *ifcfg_rh_name; + int idx; + + idx = id - _NM_ETHTOOL_ID_FEATURE_FIRST; + g_assert (idx >= 0); + g_assert (idx < G_N_ELEMENTS (_nm_ethtool_ifcfg_names)); + ifcfg_rh_name = _nm_ethtool_ifcfg_names[idx]; + g_assert (ifcfg_rh_name && ifcfg_rh_name[0]); + + for (i = 0; i < G_N_ELEMENTS (_nm_ethtool_ifcfg_names); i++) { + if (i != idx) + g_assert_cmpstr (ifcfg_rh_name, !=, _nm_ethtool_ifcfg_names[i]); + } + + g_assert_cmpstr (nms_ifcfg_rh_utils_get_ethtool_name (id), ==, ifcfg_rh_name); + + data = nms_ifcfg_rh_utils_get_ethtool_by_name (ifcfg_rh_name); + g_assert (data); + g_assert (data->id == id); + } + + for (i = 0; i < G_N_ELEMENTS (kernel_names); i++) { + const char *name = kernel_names[i].kernel_name; + + id = kernel_names[i].ethtool_id; + data = nms_ifcfg_rh_utils_get_ethtool_by_name (name); + g_assert (data); + g_assert (data->id == id); + g_assert_cmpstr (nms_ifcfg_rh_utils_get_ethtool_name (id), !=, name); + } +} + +/*****************************************************************************/ + #define TPATH "/settings/plugins/ifcfg-rh/" #define TEST_IFCFG_WIFI_OPEN_SSID_LONG_QUOTED TEST_IFCFG_DIR"/ifcfg-test-wifi-open-ssid-long-quoted" @@ -10322,6 +10519,7 @@ int main (int argc, char **argv) g_test_add_func (TPATH "wifi/read/wpa-psk/adhoc", test_read_wifi_wpa_psk_adhoc); g_test_add_func (TPATH "wifi/read/wpa-psk/hex", test_read_wifi_wpa_psk_hex); g_test_add_func (TPATH "wifi/read/sae", test_read_wifi_sae); + g_test_add_func (TPATH "wifi/read/owe", test_read_wifi_owe); g_test_add_func (TPATH "wifi/read/dynamic-wep/leap", test_read_wifi_dynamic_wep_leap); g_test_add_func (TPATH "wifi/read/wpa/eap/tls", test_read_wifi_wpa_eap_tls); g_test_add_func (TPATH "wifi/read/wpa/eap/ttls/tls", test_read_wifi_wpa_eap_ttls_tls); @@ -10498,6 +10696,10 @@ int main (int argc, char **argv) g_test_add_func (TPATH "tc/read", test_tc_read); g_test_add_func (TPATH "tc/write", test_tc_write); + g_test_add_func (TPATH "utils/test_well_known_keys", test_well_known_keys); + g_test_add_func (TPATH "utils/test_utils_has_route_file_new_syntax", test_utils_has_route_file_new_syntax); + + g_test_add_func (TPATH "utils/test_ethtool_names", test_ethtool_names); return g_test_run (); } diff --git a/src/settings/plugins/ifupdown/meson.build b/src/settings/plugins/ifupdown/meson.build index 0cabe771..7e2b44fb 100644 --- a/src/settings/plugins/ifupdown/meson.build +++ b/src/settings/plugins/ifupdown/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + sources = files( 'nms-ifupdown-interface-parser.c', 'nms-ifupdown-parser.c', diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c index 1db9ef15..ac3ed1ce 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-parser.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-parser.c @@ -484,7 +484,7 @@ update_ip4_setting_from_if_block (NMConnection *connection, /* gateway */ gateway_v = ifparser_getkey (block, "gateway"); if (gateway_v) { - if (!nm_utils_ipaddr_valid (AF_INET, gateway_v)) { + if (!nm_utils_ipaddr_is_valid (AF_INET, gateway_v)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IPv4 gateway '%s'", gateway_v); return FALSE; @@ -565,9 +565,8 @@ update_ip6_setting_from_if_block (NMConnection *connection, const char *nameserver_v; const char *nameservers_v; const char *search_v; - int prefix_int = 128; + guint prefix_int; - /* Address */ address_v = ifparser_getkey (block, "address"); if (!address_v) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, @@ -575,12 +574,12 @@ update_ip6_setting_from_if_block (NMConnection *connection, return FALSE; } - /* Prefix */ prefix_v = ifparser_getkey (block, "netmask"); if (prefix_v) - prefix_int = g_ascii_strtoll (prefix_v, NULL, 10); + prefix_int = _nm_utils_ascii_str_to_int64 (prefix_v, 10, 0, 128, G_MAXINT); + else + prefix_int = 128; - /* Add the new address to the setting */ addr = nm_ip_address_new (AF_INET6, address_v, prefix_int, error); if (!addr) return FALSE; @@ -593,10 +592,9 @@ update_ip6_setting_from_if_block (NMConnection *connection, } nm_ip_address_unref (addr); - /* gateway */ gateway_v = ifparser_getkey (block, "gateway"); if (gateway_v) { - if (!nm_utils_ipaddr_valid (AF_INET6, gateway_v)) { + if (!nm_utils_ipaddr_is_valid (AF_INET6, gateway_v)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid IPv6 gateway '%s'", gateway_v); return FALSE; @@ -614,7 +612,6 @@ update_ip6_setting_from_if_block (NMConnection *connection, if (!nm_setting_ip_config_get_num_dns (s_ip6)) _LOGI ("No dns-nameserver configured in /etc/network/interfaces"); - /* DNS searches */ search_v = ifparser_getkey (block, "dns-search"); if (search_v) { gs_free const char **list = NULL; diff --git a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c index d19db0fd..808df49f 100644 --- a/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c +++ b/src/settings/plugins/ifupdown/nms-ifupdown-plugin.c @@ -376,7 +376,7 @@ dispose (GObject *object) NMSIfupdownPlugin *plugin = NMS_IFUPDOWN_PLUGIN (object); NMSIfupdownPluginPrivate *priv = NMS_IFUPDOWN_PLUGIN_GET_PRIVATE (plugin); - g_clear_pointer (&priv->eni_ifaces, g_hash_table_destroy); + nm_clear_pointer (&priv->eni_ifaces, g_hash_table_destroy); G_OBJECT_CLASS (nms_ifupdown_plugin_parent_class)->dispose (object); } diff --git a/src/settings/plugins/ifupdown/tests/meson.build b/src/settings/plugins/ifupdown/tests/meson.build index 1ca094b5..a39e4e21 100644 --- a/src/settings/plugins/ifupdown/tests/meson.build +++ b/src/settings/plugins/ifupdown/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_unit = 'test-ifupdown' exe = executable( diff --git a/src/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/settings/plugins/keyfile/nms-keyfile-plugin.c index fdb88d2a..2906b399 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -23,7 +23,7 @@ #include "nm-utils.h" #include "nm-config.h" #include "nm-core-internal.h" -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" #include "systemd/nm-sd-utils-shared.h" diff --git a/src/settings/plugins/keyfile/nms-keyfile-reader.c b/src/settings/plugins/keyfile/nms-keyfile-reader.c index af9e6726..e8c9f9fe 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-reader.c +++ b/src/settings/plugins/keyfile/nms-keyfile-reader.c @@ -9,7 +9,7 @@ #include <sys/stat.h> -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" #include "NetworkManagerUtils.h" #include "nms-keyfile-utils.h" diff --git a/src/settings/plugins/keyfile/nms-keyfile-utils.c b/src/settings/plugins/keyfile/nms-keyfile-utils.c index f03c601a..bc8dfd12 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-utils.c +++ b/src/settings/plugins/keyfile/nms-keyfile-utils.c @@ -11,7 +11,7 @@ #include <sys/stat.h> #include "nm-glib-aux/nm-io-utils.h" -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" #include "nm-utils.h" #include "nm-setting-wired.h" #include "nm-setting-wireless.h" diff --git a/src/settings/plugins/keyfile/nms-keyfile-writer.c b/src/settings/plugins/keyfile/nms-keyfile-writer.c index fa95198c..7554becc 100644 --- a/src/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/settings/plugins/keyfile/nms-keyfile-writer.c @@ -12,7 +12,7 @@ #include <sys/stat.h> #include <unistd.h> -#include "nm-keyfile-internal.h" +#include "nm-keyfile/nm-keyfile-internal.h" #include "nms-keyfile-utils.h" #include "nms-keyfile-reader.h" @@ -60,7 +60,7 @@ cert_writer (NMConnection *connection, * that would be interpreted as legacy binary format by reader. */ tmp = nm_keyfile_detect_unqualified_path_scheme (info->keyfile_dir, p, -1, FALSE, NULL); if (tmp) { - g_clear_pointer (&tmp, g_free); + nm_clear_g_free (&tmp); accepted_path = p; } } @@ -71,7 +71,7 @@ cert_writer (NMConnection *connection, * Otherwise, add a file:// prefix */ tmp = nm_keyfile_detect_unqualified_path_scheme (info->keyfile_dir, path, -1, FALSE, NULL); if (tmp) { - g_clear_pointer (&tmp, g_free); + nm_clear_g_free (&tmp); accepted_path = path; } } diff --git a/src/settings/plugins/keyfile/tests/meson.build b/src/settings/plugins/keyfile/tests/meson.build index 7bf9fda0..cd1dc3aa 100644 --- a/src/settings/plugins/keyfile/tests/meson.build +++ b/src/settings/plugins/keyfile/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_unit = 'test-keyfile-settings' exe = executable( diff --git a/src/settings/plugins/meson.build b/src/settings/plugins/meson.build index 83981aab..cde0844b 100644 --- a/src/settings/plugins/meson.build +++ b/src/settings/plugins/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + if enable_ifcfg_rh subdir('ifcfg-rh') endif diff --git a/src/supplicant/nm-supplicant-config.c b/src/supplicant/nm-supplicant-config.c index dec4556d..53b6d360 100644 --- a/src/supplicant/nm-supplicant-config.c +++ b/src/supplicant/nm-supplicant-config.c @@ -14,7 +14,7 @@ #include "nm-supplicant-settings-verify.h" #include "nm-setting.h" -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-setting-ip4-config.h" @@ -30,13 +30,10 @@ typedef struct { typedef struct { GHashTable *config; GHashTable *blobs; - guint32 ap_scan; - gboolean fast_required; - gboolean dispose_has_run; - gboolean support_pmf; - gboolean support_fils; - gboolean support_ft; - gboolean support_sha384; + NMSupplCapMask capabilities; + guint32 ap_scan; + bool fast_required:1; + bool dispose_has_run:1; } NMSupplicantConfigPrivate; struct _NMSupplicantConfig { @@ -54,9 +51,15 @@ G_DEFINE_TYPE (NMSupplicantConfig, nm_supplicant_config, G_TYPE_OBJECT) /*****************************************************************************/ +static gboolean +_get_capability (NMSupplicantConfigPrivate *priv, + NMSupplCapType type) +{ + return NM_SUPPL_CAP_MASK_GET (priv->capabilities, type) == NM_TERNARY_TRUE; +} + NMSupplicantConfig * -nm_supplicant_config_new (gboolean support_pmf, gboolean support_fils, - gboolean support_ft, gboolean support_sha384) +nm_supplicant_config_new (NMSupplCapMask capabilities) { NMSupplicantConfigPrivate *priv; NMSupplicantConfig *self; @@ -64,10 +67,7 @@ nm_supplicant_config_new (gboolean support_pmf, gboolean support_fils, self = g_object_new (NM_TYPE_SUPPLICANT_CONFIG, NULL); priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); - priv->support_pmf = support_pmf; - priv->support_fils = support_fils; - priv->support_ft = support_ft; - priv->support_sha384 = support_sha384; + priv->capabilities = capabilities; return self; } @@ -88,10 +88,6 @@ nm_supplicant_config_init (NMSupplicantConfig * self) g_free, (GDestroyNotify) config_option_free); - priv->blobs = g_hash_table_new_full (nm_str_hash, g_str_equal, - g_free, - (GDestroyNotify) g_bytes_unref); - priv->ap_scan = 1; priv->dispose_has_run = FALSE; } @@ -224,6 +220,11 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self, nm_log_info (LOGD_SUPPLICANT, "Config: added '%s' value '%s'", key, opt->value); g_hash_table_insert (priv->config, g_strdup (key), opt); + if (!priv->blobs) { + priv->blobs = g_hash_table_new_full (nm_str_hash, g_str_equal, + g_free, + (GDestroyNotify) g_bytes_unref); + } g_hash_table_insert (priv->blobs, g_strdup (blobid), g_bytes_ref (value)); @@ -256,10 +257,10 @@ nm_supplicant_config_add_blob_for_connection (NMSupplicantConfig *self, static void nm_supplicant_config_finalize (GObject *object) { - NMSupplicantConfigPrivate *priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE ((NMSupplicantConfig *) object); + NMSupplicantConfigPrivate *priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (object); g_hash_table_destroy (priv->config); - g_hash_table_destroy (priv->blobs); + nm_clear_pointer (&priv->blobs, g_hash_table_destroy); G_OBJECT_CLASS (nm_supplicant_config_parent_class)->finalize (object); } @@ -768,7 +769,7 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, g_return_val_if_fail (!error || !*error, FALSE); /* Check if we actually support FILS */ - if (!priv->support_fils) { + if (!_get_capability (priv, NM_SUPPL_CAP_TYPE_FILS)) { if (fils == NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED) { g_set_error_literal (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, "Supplicant does not support FILS"); @@ -780,36 +781,40 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting); key_mgmt_conf = g_string_new (key_mgmt); if (nm_streq (key_mgmt, "wpa-psk")) { - if (priv->support_pmf) + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_PMF)) g_string_append (key_mgmt_conf, " wpa-psk-sha256"); - if (priv->support_ft) + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_FT)) g_string_append (key_mgmt_conf, " ft-psk"); } else if (nm_streq (key_mgmt, "wpa-eap")) { - if (priv->support_pmf) + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_PMF)) g_string_append (key_mgmt_conf, " wpa-eap-sha256"); - if (priv->support_ft) + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_FT)) g_string_append (key_mgmt_conf, " ft-eap"); - if (priv->support_ft && priv->support_sha384) + if ( _get_capability (priv, NM_SUPPL_CAP_TYPE_FT) + && _get_capability (priv, NM_SUPPL_CAP_TYPE_SHA384)) g_string_append (key_mgmt_conf, " ft-eap-sha384"); switch (fils) { case NM_SETTING_WIRELESS_SECURITY_FILS_REQUIRED: g_string_truncate (key_mgmt_conf, 0); - if (!priv->support_pmf) + if (!_get_capability (priv, NM_SUPPL_CAP_TYPE_PMF)) g_string_assign (key_mgmt_conf, "fils-sha256 fils-sha384"); /* fall-through */ case NM_SETTING_WIRELESS_SECURITY_FILS_OPTIONAL: - if (priv->support_pmf) + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_PMF)) g_string_append (key_mgmt_conf, " fils-sha256 fils-sha384"); - if (priv->support_pmf && priv->support_ft) + if ( _get_capability (priv, NM_SUPPL_CAP_TYPE_PMF) + && _get_capability (priv, NM_SUPPL_CAP_TYPE_FT)) g_string_append (key_mgmt_conf, " ft-fils-sha256"); - if (priv->support_pmf && priv->support_ft & priv->support_sha384) + if ( _get_capability (priv, NM_SUPPL_CAP_TYPE_PMF) + && _get_capability (priv, NM_SUPPL_CAP_TYPE_FT) + && _get_capability (priv, NM_SUPPL_CAP_TYPE_SHA384)) g_string_append (key_mgmt_conf, " ft-fils-sha384"); break; default: break; } } else if (nm_streq (key_mgmt, "sae")) { - if (priv->support_ft) + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_FT)) g_string_append (key_mgmt_conf, " ft-sae"); } @@ -867,13 +872,13 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, } } - /* Don't try to enable PMF on non-WPA/SAE networks */ - if (!NM_IN_STRSET (key_mgmt, "wpa-eap", "wpa-psk", "sae")) + /* Don't try to enable PMF on non-WPA/SAE/OWE networks */ + if (!NM_IN_STRSET (key_mgmt, "wpa-eap", "wpa-psk", "sae", "owe")) pmf = NM_SETTING_WIRELESS_SECURITY_PMF_DISABLE; /* Check if we actually support PMF */ set_pmf = TRUE; - if (!priv->support_pmf) { + if (!_get_capability (priv, NM_SUPPL_CAP_TYPE_PMF)) { if (pmf == NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) { g_set_error_literal (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, "Supplicant does not support PMF"); @@ -885,7 +890,8 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, /* Only WPA-specific things when using WPA */ if ( !strcmp (key_mgmt, "wpa-psk") || !strcmp (key_mgmt, "wpa-eap") - || !strcmp (key_mgmt, "sae")) { + || !strcmp (key_mgmt, "sae") + || !strcmp (key_mgmt, "owe")) { if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, proto, protos, "proto", ' ', TRUE, NULL, error)) return FALSE; if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, pairwise, pairwise, "pairwise", ' ', TRUE, NULL, error)) @@ -1323,6 +1329,14 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, if (!add_string_val (self, value, "domain_suffix_match2", FALSE, NULL, error)) return FALSE; + /* domain match */ + value = nm_setting_802_1x_get_domain_match (setting); + if (!add_string_val (self, value, "domain_match", FALSE, NULL, error)) + return FALSE; + value = nm_setting_802_1x_get_phase2_domain_match (setting); + if (!add_string_val (self, value, "domain_match2", FALSE, NULL, error)) + return FALSE; + /* Private key */ added = FALSE; switch (nm_setting_802_1x_get_private_key_scheme (setting)) { diff --git a/src/supplicant/nm-supplicant-config.h b/src/supplicant/nm-supplicant-config.h index 361f9ac6..e1da9a1e 100644 --- a/src/supplicant/nm-supplicant-config.h +++ b/src/supplicant/nm-supplicant-config.h @@ -25,8 +25,7 @@ typedef struct _NMSupplicantConfigClass NMSupplicantConfigClass; GType nm_supplicant_config_get_type (void); -NMSupplicantConfig *nm_supplicant_config_new (gboolean support_pmf, gboolean support_fils, - gboolean support_ft, gboolean support_sha384); +NMSupplicantConfig *nm_supplicant_config_new (NMSupplCapMask capabilities); guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self); diff --git a/src/supplicant/nm-supplicant-interface.c b/src/supplicant/nm-supplicant-interface.c index c19da11c..cc3d109e 100644 --- a/src/supplicant/nm-supplicant-interface.c +++ b/src/supplicant/nm-supplicant-interface.c @@ -7,49 +7,35 @@ #include "nm-default.h" #include "nm-supplicant-interface.h" -#include "nm-supplicant-manager.h" #include <stdio.h> #include "NetworkManagerUtils.h" -#include "nm-supplicant-config.h" #include "nm-core-internal.h" +#include "nm-glib-aux/nm-c-list.h" +#include "nm-glib-aux/nm-ref-string.h" #include "nm-std-aux/nm-dbus-compat.h" +#include "nm-supplicant-config.h" +#include "nm-supplicant-manager.h" +#include "shared/nm-glib-aux/nm-dbus-aux.h" -#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" -#define WPAS_DBUS_IFACE_INTERFACE_WPS WPAS_DBUS_INTERFACE ".Interface.WPS" -#define WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE WPAS_DBUS_INTERFACE ".Interface.P2PDevice" -#define WPAS_DBUS_IFACE_BSS WPAS_DBUS_INTERFACE ".BSS" -#define WPAS_DBUS_IFACE_PEER WPAS_DBUS_INTERFACE ".Peer" -#define WPAS_DBUS_IFACE_GROUP WPAS_DBUS_INTERFACE ".Group" -#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network" -#define WPAS_ERROR_INVALID_IFACE WPAS_DBUS_INTERFACE ".InvalidInterface" -#define WPAS_ERROR_EXISTS_ERROR WPAS_DBUS_INTERFACE ".InterfaceExists" +#define DBUS_TIMEOUT_MSEC 20000 /*****************************************************************************/ typedef struct { - GDBusProxy *proxy; - gulong change_id; -} BssData; - -typedef struct { - GDBusProxy *proxy; - gulong change_id; -} PeerData; - -struct _AddNetworkData; - -typedef struct { NMSupplicantInterface *self; char *type; char *bssid; char *pin; - GDBusProxy *proxy; + guint signal_id; GCancellable *cancellable; - bool is_cancelling; + bool needs_cancelling:1; + bool is_cancelling:1; } WpsData; +struct _AddNetworkData; + typedef struct { NMSupplicantInterface *self; NMSupplicantConfig *cfg; @@ -64,34 +50,27 @@ typedef struct { typedef struct _AddNetworkData { /* the assoc_data at the time when doing the call. */ AssocData *assoc_data; + NMRefString *name_owner; + NMRefString *object_path; + GObject *shutdown_wait_obj; } AddNetworkData; -typedef struct { - NMSupplicantInterface *self; - NMSupplicantInterfaceDisconnectCb callback; - gpointer user_data; -} DisconnectData; - enum { STATE, /* change in the interface's state */ - REMOVED, /* interface was removed by the supplicant */ - BSS_UPDATED, /* a new BSS appeared or an existing had properties changed */ - BSS_REMOVED, /* supplicant removed BSS from its scan list */ - PEER_UPDATED, /* a new Peer appeared or an existing had properties changed */ - PEER_REMOVED, /* supplicant removed Peer from its scan list */ - SCAN_DONE, /* wifi scan is complete */ - CREDENTIALS_REQUEST, /* 802.1x identity or password requested */ + BSS_CHANGED, /* a new BSS appeared, was updated, or was removed. */ + PEER_CHANGED, /* a new Peer appeared, was updated, or was removed */ WPS_CREDENTIALS, /* WPS credentials received */ GROUP_STARTED, /* a new Group (interface) was created */ GROUP_FINISHED, /* a Group (interface) has been finished */ - GROUP_FORMATION_FAILURE, /* P2P Group formation failed */ LAST_SIGNAL }; + static guint signals[LAST_SIGNAL] = { 0 }; NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, - PROP_IFACE, - PROP_OBJECT_PATH, + PROP_SUPPLICANT_MANAGER, + PROP_DBUS_OBJECT_PATH, + PROP_IFINDEX, PROP_P2P_GROUP_JOINED, PROP_P2P_GROUP_PATH, PROP_P2P_GROUP_OWNER, @@ -99,76 +78,83 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSupplicantInterface, PROP_CURRENT_BSS, PROP_DRIVER, PROP_P2P_AVAILABLE, - PROP_FAST_SUPPORT, - PROP_AP_SUPPORT, - PROP_PMF_SUPPORT, - PROP_FILS_SUPPORT, - PROP_P2P_SUPPORT, - PROP_MESH_SUPPORT, - PROP_WFD_SUPPORT, - PROP_FT_SUPPORT, - PROP_SHA384_SUPPORT, PROP_AUTH_STATE, ); -typedef struct { - char * dev; - NMSupplicantDriver driver; - gboolean has_credreq; /* Whether querying 802.1x credentials is supported */ - NMSupplicantFeature fast_support; - NMSupplicantFeature ap_support; /* Lightweight AP mode support */ - NMSupplicantFeature pmf_support; - NMSupplicantFeature fils_support; - NMSupplicantFeature p2p_support; - NMSupplicantFeature mesh_support; - NMSupplicantFeature wfd_support; - NMSupplicantFeature ft_support_global; - NMSupplicantFeature ft_support_per_iface; - NMSupplicantFeature sha384_support; - guint32 max_scan_ssids; - guint32 ready_count; +typedef struct _NMSupplicantInterfacePrivate { - char * object_path; - NMSupplicantInterfaceState state; - int disconnect_reason; + NMSupplicantManager *supplicant_manager; - bool scanning:1; + GDBusConnection *dbus_connection; + NMRefString *name_owner; + NMRefString *object_path; - bool scan_done_pending:1; - bool scan_done_success:1; + char *ifname; - GDBusProxy * wpas_proxy; - GCancellable * init_cancellable; - GDBusProxy * iface_proxy; - GCancellable * other_cancellable; - GDBusProxy * p2p_proxy; - GDBusProxy * group_proxy; + GCancellable *main_cancellable; - gboolean p2p_proxy_acquired; - gboolean group_proxy_acquired; - gboolean p2p_capable; + NMRefString *p2p_group_path; - gboolean p2p_group_owner; + GCancellable *p2p_group_properties_cancellable; - WpsData *wps_data; + WpsData *wps_data; + + AssocData *assoc_data; + + char *net_path; - AssocData * assoc_data; + char *driver; - char * net_path; - GHashTable * bss_proxies; - char * current_bss; + GHashTable *bss_idx; + CList bss_lst_head; + CList bss_initializing_lst_head; - GHashTable * peer_proxies; + NMRefString *current_bss; - gint64 last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_ms() */ + GHashTable *peer_idx; + CList peer_lst_head; + CList peer_initializing_lst_head; + + gint64 last_scan_msec; NMSupplicantAuthState auth_state; -} NMSupplicantInterfacePrivate; -struct _NMSupplicantInterface { - GObject parent; - NMSupplicantInterfacePrivate _priv; -}; + NMSupplicantDriver requested_driver; + NMSupplCapMask global_capabilities; + NMSupplCapMask iface_capabilities; + + guint properties_changed_id; + guint signal_id; + guint bss_properties_changed_id; + guint peer_properties_changed_id; + guint p2p_group_properties_changed_id; + + int ifindex; + + int starting_pending_count; + + guint32 max_scan_ssids; + + gint32 disconnect_reason; + + NMSupplicantInterfaceState state; + NMSupplicantInterfaceState supp_state; + + bool scanning_property:1; + bool scanning_cached:1; + + bool p2p_capable_property:1; + bool p2p_capable_cached:1; + + bool p2p_group_owner_property:1; + bool p2p_group_owner_cached:1; + + bool p2p_group_joined_cached:1; + + bool is_ready_main:1; + bool is_ready_p2p_device:1; + +} NMSupplicantInterfacePrivate; struct _NMSupplicantInterfaceClass { GObjectClass parent; @@ -176,420 +162,1003 @@ struct _NMSupplicantInterfaceClass { G_DEFINE_TYPE (NMSupplicantInterface, nm_supplicant_interface, G_TYPE_OBJECT) -#define NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSupplicantInterface, NM_IS_SUPPLICANT_INTERFACE) +#define NM_SUPPLICANT_INTERFACE_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR (self, NMSupplicantInterface, NM_IS_SUPPLICANT_INTERFACE) /*****************************************************************************/ +static const char * +_log_pretty_object_path (NMSupplicantInterfacePrivate *priv) +{ + const char *s; + + nm_assert (priv); + nm_assert (NM_IS_REF_STRING (priv->object_path)); + + s = priv->object_path->str; + if (NM_STR_HAS_PREFIX (s, "/fi/w1/wpa_supplicant1/Interfaces/")) { + s += NM_STRLEN ("/fi/w1/wpa_supplicant1/Interfaces/"); + if ( s[0] + && s[0] != '/') + return s; + } + return priv->object_path->str; +} + #define _NMLOG_DOMAIN LOGD_SUPPLICANT #define _NMLOG_PREFIX_NAME "sup-iface" #define _NMLOG(level, ...) \ G_STMT_START { \ - char _sbuf[64]; \ - const char *__ifname = self ? NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev : NULL; \ + NMSupplicantInterface *_self = (self); \ + NMSupplicantInterfacePrivate *_priv = _self ? NM_SUPPLICANT_INTERFACE_GET_PRIVATE (_self) : NULL; \ + char _sbuf[255]; \ + const char *_ifname = _priv ? _priv->ifname : NULL; \ \ - nm_log ((level), _NMLOG_DOMAIN, __ifname, NULL, \ + nm_log ((level), _NMLOG_DOMAIN, _ifname, NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ - ((self) ? nm_sprintf_buf (_sbuf, "[%p,%s]", (self), __ifname) : "") \ + ( _self \ + ? nm_sprintf_buf (_sbuf, \ + "["NM_HASH_OBFUSCATE_PTR_FMT",%s,%s]", \ + NM_HASH_OBFUSCATE_PTR (_self), \ + _log_pretty_object_path (_priv), \ + _ifname ?: "???") \ + : "") \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ } G_STMT_END /*****************************************************************************/ -static void scan_done_emit_signal (NMSupplicantInterface *self); +static void _starting_check_ready (NMSupplicantInterface *self); + +static void assoc_return (NMSupplicantInterface *self, + GError *error, + const char *message); /*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE (nm_supplicant_interface_state_to_string, NMSupplicantInterfaceState, - NM_UTILS_LOOKUP_DEFAULT_WARN ("unknown"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INVALID, "invalid"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INIT, "init"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_STARTING, "starting"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_READY, "ready"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DISABLED, "disabled"), + NM_UTILS_LOOKUP_DEFAULT_WARN ("internal-unknown"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INVALID, "internal-invalid"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_STARTING, "internal-starting"), + + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, "4way_handshake"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED, "associated"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING, "associating"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING, "authenticating"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_COMPLETED, "completed"), NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, "disconnected"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE, "group_handshake"), NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_INACTIVE, "inactive"), + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DISABLED, "interface_disabled"), NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_SCANNING, "scanning"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING, "authenticating"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING, "associating"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED, "associated"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, "4-way handshake"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE, "group handshake"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_COMPLETED, "completed"), - NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DOWN, "down"), + + NM_UTILS_LOOKUP_STR_ITEM (NM_SUPPLICANT_INTERFACE_STATE_DOWN, "internal-down"), +); + +static +NM_UTILS_STRING_TABLE_LOOKUP_DEFINE ( + wpas_state_string_to_enum, + NMSupplicantInterfaceState, + { nm_assert (name); }, + { return NM_SUPPLICANT_INTERFACE_STATE_INVALID; }, + { "4way_handshake", NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE }, + { "associated", NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED }, + { "associating", NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING }, + { "authenticating", NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING }, + { "completed", NM_SUPPLICANT_INTERFACE_STATE_COMPLETED }, + { "disconnected", NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED }, + { "group_handshake", NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE }, + { "inactive", NM_SUPPLICANT_INTERFACE_STATE_INACTIVE }, + { "interface_disabled", NM_SUPPLICANT_INTERFACE_STATE_DISABLED }, + { "scanning", NM_SUPPLICANT_INTERFACE_STATE_SCANNING }, ); /*****************************************************************************/ +static NM80211ApSecurityFlags +security_from_vardict (GVariant *security) +{ + NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; + const char **array; + const char *tmp; + + nm_assert (g_variant_is_of_type (security, G_VARIANT_TYPE_VARDICT)); + + if (g_variant_lookup (security, "KeyMgmt", "^a&s", &array)) { + if (g_strv_contains (array, "wpa-psk") || + g_strv_contains (array, "wpa-ft-psk")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; + if (g_strv_contains (array, "wpa-eap") || + g_strv_contains (array, "wpa-ft-eap") || + g_strv_contains (array, "wpa-fils-sha256") || + g_strv_contains (array, "wpa-fils-sha384")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; + if (g_strv_contains (array, "sae")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_SAE; + if (g_strv_contains (array, "owe")) + flags |= NM_802_11_AP_SEC_KEY_MGMT_OWE; + g_free (array); + } + + if (g_variant_lookup (security, "Pairwise", "^a&s", &array)) { + if (g_strv_contains (array, "tkip")) + flags |= NM_802_11_AP_SEC_PAIR_TKIP; + if (g_strv_contains (array, "ccmp")) + flags |= NM_802_11_AP_SEC_PAIR_CCMP; + g_free (array); + } + + if (g_variant_lookup (security, "Group", "&s", &tmp)) { + if (nm_streq (tmp, "wep40")) + flags |= NM_802_11_AP_SEC_GROUP_WEP40; + else if (nm_streq (tmp, "wep104")) + flags |= NM_802_11_AP_SEC_GROUP_WEP104; + else if (nm_streq (tmp, "tkip")) + flags |= NM_802_11_AP_SEC_GROUP_TKIP; + else if (nm_streq (tmp, "ccmp")) + flags |= NM_802_11_AP_SEC_GROUP_CCMP; + } + + return flags; +} + +/*****************************************************************************/ + +/* Various conditions prevent _starting_check_ready() from completing. For example, + * bss_initializing_lst_head, peer_initializing_lst_head and p2p_group_properties_cancellable. + * At some places, these conditions might toggle, and it would seems we would have + * to call _starting_check_ready() at that point, to ensure we don't miss a state + * change that we are ready. However, these places are deep in the call stack and + * not suitable to perform this state change. Instead, the callers *MUST* have + * added their own starting_pending_count to delay _starting_check_ready(). + * + * Assert that is the case. */ +#define nm_assert_starting_has_pending_count(v) nm_assert ((v) > 0) + +/*****************************************************************************/ + static void -bss_data_destroy (gpointer user_data) +_dbus_connection_call (NMSupplicantInterface *self, + const char *interface_name, + const char *method_name, + GVariant *parameters, + const GVariantType *reply_type, + GDBusCallFlags flags, + int timeout_msec, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - BssData *bss_data = user_data; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - nm_clear_g_signal_handler (bss_data->proxy, &bss_data->change_id); - g_object_unref (bss_data->proxy); - g_slice_free (BssData, bss_data); + g_dbus_connection_call (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + interface_name, + method_name, + parameters, + reply_type, + flags, + timeout_msec, + cancellable, + callback, + user_data); } static void -bss_proxy_properties_changed_cb (GDBusProxy *proxy, - GVariant *changed_properties, - char **invalidated_properties, +_dbus_connection_call_simple_cb (GObject *source, + GAsyncResult *result, gpointer user_data) { - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantInterface *self; + gs_unref_variant GVariant *res = NULL; + gs_free_error GError *error = NULL; + const char *log_reason; + gs_free char *remote_error = NULL; + + nm_utils_user_data_unpack (user_data, &self, &log_reason); + + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (nm_utils_error_is_cancelled (error)) + return; + + if (res) { + _LOGT ("call-%s: success", log_reason); + return; + } - if (priv->scanning) - priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); + remote_error = g_dbus_error_get_remote_error (error); + if (!nm_streq0 (remote_error, "fi.w1.wpa_supplicant1.NotConnected")) { + g_dbus_error_strip_remote_error (error); + _LOGW ("call-%s: failed with %s", log_reason, error->message); + return; + } - g_signal_emit (self, signals[BSS_UPDATED], 0, - g_dbus_proxy_get_object_path (proxy), - changed_properties); + _LOGT ("call-%s: failed with %s", log_reason, error->message); } -static GVariant * -bss_proxy_get_properties (NMSupplicantInterface *self, GDBusProxy *proxy) +static void +_dbus_connection_call_simple (NMSupplicantInterface *self, + const char *interface_name, + const char *method_name, + GVariant *parameters, + const GVariantType *reply_type, + const char *log_reason) { - gs_strfreev char **properties = NULL; - GVariantBuilder builder; - char **iter; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - iter = properties = g_dbus_proxy_get_cached_property_names (proxy); + _dbus_connection_call (self, + interface_name, + method_name, + parameters, + reply_type, + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_MSEC, + priv->main_cancellable, + _dbus_connection_call_simple_cb, + nm_utils_user_data_pack (self, log_reason)); +} - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - if (iter) { - while (*iter) { - GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter); +/*****************************************************************************/ - g_variant_builder_add (&builder, "{sv}", *iter++, copy); - g_variant_unref (copy); - } - } - return g_variant_builder_end (&builder); +static void +_emit_signal_state (NMSupplicantInterface *self, + NMSupplicantInterfaceState new_state, + NMSupplicantInterfaceState old_state, + gint32 disconnect_reason) +{ + g_signal_emit (self, + signals[STATE], + 0, + (int) new_state, + (int) old_state, + (int) disconnect_reason); } +/*****************************************************************************/ + static void -bss_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +_remove_network (NMSupplicantInterface *self) { - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; - gs_free_error GError *error = NULL; - GVariant *props = NULL; - const char *object_path; - BssData *bss_data; - gboolean success; - - success = g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error); - if ( !success - && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + gs_free char *net_path = NULL; + + if (!priv->net_path) return; - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + net_path = g_steal_pointer (&priv->net_path); + _dbus_connection_call_simple (self, + NM_WPAS_DBUS_IFACE_INTERFACE, + "RemoveNetwork", + g_variant_new ("(o)", net_path), + G_VARIANT_TYPE ("()"), + "remove-network"); +} - if (!success) { - _LOGD ("failed to acquire BSS proxy: (%s)", error->message); - g_hash_table_remove (priv->bss_proxies, - g_dbus_proxy_get_object_path (proxy)); - return; - } +/*****************************************************************************/ + +static void +_notify_maybe_scanning (NMSupplicantInterface *self) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + gboolean scanning; + + scanning = nm_supplicant_interface_state_is_operational (priv->state) + && ( priv->scanning_property + || priv->supp_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING); - object_path = g_dbus_proxy_get_object_path (proxy); - bss_data = g_hash_table_lookup (priv->bss_proxies, object_path); - if (!bss_data) + if (priv->scanning_cached == scanning) return; - bss_data->change_id = g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (bss_proxy_properties_changed_cb), self); + if ( !scanning + && !c_list_is_empty (&priv->bss_initializing_lst_head)) { + /* we would change state to indicate we no longer scan. However, + * we still have BSS instances to be initialized. Delay the + * state change further. */ + return; + } - props = bss_proxy_get_properties (self, proxy); - g_signal_emit (self, signals[BSS_UPDATED], 0, - g_dbus_proxy_get_object_path (proxy), - g_variant_ref_sink (props)); - g_variant_unref (props); + _LOGT ("scanning: %s", scanning ? "yes" : "no"); - if (priv->scan_done_pending) - scan_done_emit_signal (self); + if (!scanning) + priv->last_scan_msec = nm_utils_get_monotonic_timestamp_msec (); + else { + /* while we are scanning, we set the timestamp to -1. */ + priv->last_scan_msec = -1; + } + priv->scanning_cached = scanning; + _notify (self, PROP_SCANNING); } static void -bss_add_new (NMSupplicantInterface *self, const char *object_path) +_notify_maybe_p2p_available (NMSupplicantInterface *self) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - GDBusProxy *bss_proxy; - BssData *bss_data; + gboolean value; - g_return_if_fail (object_path != NULL); + value = priv->is_ready_p2p_device + && priv->p2p_capable_property; - if (g_hash_table_lookup (priv->bss_proxies, object_path)) + if (priv->p2p_capable_cached == value) return; - bss_proxy = g_object_new (G_TYPE_DBUS_PROXY, - "g-bus-type", G_BUS_TYPE_SYSTEM, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-name", WPAS_DBUS_SERVICE, - "g-object-path", object_path, - "g-interface-name", WPAS_DBUS_IFACE_BSS, - NULL); - bss_data = g_slice_new0 (BssData); - bss_data->proxy = bss_proxy; - g_hash_table_insert (priv->bss_proxies, - (char *) g_dbus_proxy_get_object_path (bss_proxy), - bss_data); - g_async_initable_init_async (G_ASYNC_INITABLE (bss_proxy), - G_PRIORITY_DEFAULT, - priv->other_cancellable, - (GAsyncReadyCallback) bss_proxy_acquired_cb, - self); + priv->p2p_capable_cached = value; + _notify (self, PROP_P2P_AVAILABLE); } static void -peer_data_destroy (gpointer user_data) +_notify_maybe_p2p_group (NMSupplicantInterface *self) { - PeerData *peer_data = user_data; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + gboolean value_joined; + gboolean value_owner; + gboolean joined_changed; + gboolean owner_changed; + + value_joined = priv->p2p_group_path + && !priv->p2p_group_properties_cancellable; + value_owner = value_joined + && priv->p2p_group_owner_property; + + if ((joined_changed = (priv->p2p_group_joined_cached != value_joined))) + priv->p2p_group_joined_cached = value_joined; - nm_clear_g_signal_handler (peer_data->proxy, &peer_data->change_id); - g_object_unref (peer_data->proxy); - g_slice_free (PeerData, peer_data); + if ((owner_changed = (priv->p2p_group_owner_cached != value_owner))) + priv->p2p_group_owner_cached = value_owner; + + if (joined_changed) + _notify (self, PROP_P2P_GROUP_JOINED); + if (owner_changed) + _notify (self, PROP_P2P_GROUP_OWNER); } +/*****************************************************************************/ + static void -peer_proxy_properties_changed_cb (GDBusProxy *proxy, - GVariant *changed_properties, - char **invalidated_properties, - gpointer user_data) +_bss_info_destroy (NMSupplicantBssInfo *bss_info) { - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - - g_signal_emit (self, signals[PEER_UPDATED], 0, - g_dbus_proxy_get_object_path (proxy), - changed_properties); + c_list_unlink_stale (&bss_info->_bss_lst); + nm_clear_g_cancellable (&bss_info->_init_cancellable); + g_bytes_unref (bss_info->ssid); + nm_ref_string_unref (bss_info->bss_path); + nm_g_slice_free (bss_info); } -static GVariant * -peer_proxy_get_properties (NMSupplicantInterface *self, GDBusProxy *proxy) +static void +_bss_info_changed_emit (NMSupplicantInterface *self, + NMSupplicantBssInfo *bss_info, + gboolean is_present) { - gs_strfreev char **properties = NULL; - GVariantBuilder builder; - char **iter; + _LOGT ("BSS %s %s", + bss_info->bss_path->str, + is_present ? "updated" : "deleted"); + g_signal_emit (self, + signals[BSS_CHANGED], + 0, + bss_info, + is_present); +} - iter = properties = g_dbus_proxy_get_cached_property_names (proxy); +static void +_bss_info_properties_changed (NMSupplicantInterface *self, + NMSupplicantBssInfo *bss_info, + GVariant *properties, + gboolean initial) +{ + gboolean v_b; + GVariant *v_v; + const char *v_s; + gint16 v_i16; + guint16 v_u16; + guint32 v_u32; + NM80211ApFlags p_ap_flags; + NM80211Mode p_mode; + guint8 p_signal_percent; + const guint8 *arr_data; + gsize arr_len; + guint32 p_max_rate; + gboolean p_max_rate_has; + gint64 now_msec = 0; + + if (nm_g_variant_lookup (properties, "Age", "u", &v_u32)) { + bss_info->last_seen_msec = nm_utils_get_monotonic_timestamp_msec_cached (&now_msec) + - (((gint64) v_u32) * 1000); + } else if (initial) { + /* Unknown Age. Assume we just received it. */ + bss_info->last_seen_msec = nm_utils_get_monotonic_timestamp_msec_cached (&now_msec); + } + + p_ap_flags = bss_info->ap_flags; + if (nm_g_variant_lookup (properties, "Privacy", "b", &v_b)) + p_ap_flags = NM_FLAGS_ASSIGN (p_ap_flags, NM_802_11_AP_FLAGS_PRIVACY, v_b); + else { + nm_assert ( !initial + || !NM_FLAGS_HAS (p_ap_flags, NM_802_11_AP_FLAGS_PRIVACY)); + } + v_v = nm_g_variant_lookup_value (properties, "WPS", G_VARIANT_TYPE_VARDICT); + if ( v_v + || initial) { + NM80211ApFlags f = NM_802_11_AP_FLAGS_NONE; + + if (v_v) { + if (g_variant_lookup (v_v, "Type", "&s", &v_s)) { + p_ap_flags = NM_802_11_AP_FLAGS_WPS; + if (nm_streq (v_s, "pcb")) + f |= NM_802_11_AP_FLAGS_WPS_PBC; + else if (nm_streq (v_s, "pin")) + f |= NM_802_11_AP_FLAGS_WPS_PIN; + } + g_variant_unref (v_v); + } + p_ap_flags = NM_FLAGS_ASSIGN_MASK (p_ap_flags, + NM_802_11_AP_FLAGS_WPS + | NM_802_11_AP_FLAGS_WPS_PBC + | NM_802_11_AP_FLAGS_WPS_PIN, + f); + } + if (bss_info->ap_flags != p_ap_flags) { + bss_info->ap_flags = p_ap_flags; + nm_assert (bss_info->ap_flags == p_ap_flags); + } + + if (nm_g_variant_lookup (properties, "Mode", "&s", &v_s)) { + if (nm_streq (v_s, "infrastructure")) + p_mode = NM_802_11_MODE_INFRA; + else if (nm_streq (v_s, "ad-hoc")) + p_mode = NM_802_11_MODE_ADHOC; + else if (nm_streq (v_s, "mesh")) + p_mode = NM_802_11_MODE_MESH; + else + p_mode = NM_802_11_MODE_UNKNOWN; + } else if (initial) + p_mode = NM_802_11_MODE_UNKNOWN; + else + p_mode = bss_info->mode; + if (bss_info->mode != p_mode) { + bss_info->mode = p_mode; + nm_assert (bss_info->mode == p_mode); + } + + if (nm_g_variant_lookup (properties, "Signal", "n", &v_i16)) + p_signal_percent = nm_wifi_utils_level_to_quality (v_i16); + else if (initial) + p_signal_percent = 0; + else + p_signal_percent = bss_info->signal_percent; + bss_info->signal_percent = p_signal_percent; + + if (nm_g_variant_lookup (properties, "Frequency", "q", &v_u16)) + bss_info->frequency = v_u16; + + v_v = nm_g_variant_lookup_value (properties, "SSID", G_VARIANT_TYPE_BYTESTRING); + if (v_v) { + arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1); + arr_len = MIN (32, arr_len); + + /* Stupid ieee80211 layer uses <hidden> */ + if ( arr_data + && arr_len + && !( NM_IN_SET (arr_len, 8, 9) + && memcmp (arr_data, "<hidden>", arr_len) == 0) + && !nm_utils_is_empty_ssid (arr_data, arr_len)) { + /* good */ + } else + arr_len = 0; - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - if (iter) { - while (*iter) { - GVariant *copy = g_dbus_proxy_get_cached_property (proxy, *iter); + if (!nm_utils_gbytes_equal_mem (bss_info->ssid, arr_data, arr_len)) { + _nm_unused gs_unref_bytes GBytes *old_free = g_steal_pointer (&bss_info->ssid); - g_variant_builder_add (&builder, "{sv}", *iter++, copy); - g_variant_unref (copy); + bss_info->ssid = (arr_len == 0) + ? NULL + : g_bytes_new (arr_data, arr_len); } + + g_variant_unref (v_v); + } else { + nm_assert ( !initial + || !bss_info->ssid); + } + + v_v = nm_g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING); + if (v_v) { + arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1); + if ( arr_len == ETH_ALEN + && memcmp (arr_data, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 + && memcmp (arr_data, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) { + /* pass */ + } else + arr_len = 0; + + if (arr_len != 0) { + nm_assert (arr_len == sizeof (bss_info->bssid)); + bss_info->bssid_valid = TRUE; + memcpy (bss_info->bssid, arr_data, sizeof (bss_info->bssid)); + } else if (bss_info->bssid_valid) { + bss_info->bssid_valid = FALSE; + memset (bss_info->bssid, 0, sizeof (bss_info->bssid)); + } + g_variant_unref (v_v); + } else { + nm_assert ( !initial + || !bss_info->bssid_valid); + } + nm_assert ( ( bss_info->bssid_valid + && !nm_utils_memeqzero (bss_info->bssid, sizeof (bss_info->bssid))) + || ( !bss_info->bssid_valid + && nm_utils_memeqzero (bss_info->bssid, sizeof (bss_info->bssid)))); + + p_max_rate_has = FALSE; + p_max_rate = 0; + v_v = nm_g_variant_lookup_value (properties, "Rates", G_VARIANT_TYPE ("au")); + if (v_v) { + const guint32 *rates = g_variant_get_fixed_array (v_v, &arr_len, sizeof (guint32)); + gsize i; + + for (i = 0; i < arr_len; i++) + p_max_rate = NM_MAX (p_max_rate, rates[i]); + p_max_rate_has = TRUE; + g_variant_unref (v_v); + } + v_v = nm_g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); + if (v_v) { + gboolean p_owe_transition_mode; + gboolean p_metered; + guint32 rate; + + arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1); + nm_wifi_utils_parse_ies (arr_data, arr_len, &rate, &p_metered, &p_owe_transition_mode); + p_max_rate = NM_MAX (p_max_rate, rate); + p_max_rate_has = TRUE; + g_variant_unref (v_v); + + if (p_owe_transition_mode) + bss_info->rsn_flags |= NM_802_11_AP_SEC_KEY_MGMT_OWE; + else + bss_info->rsn_flags &= ~NM_802_11_AP_SEC_KEY_MGMT_OWE; + + bss_info->metered = p_metered; } - return g_variant_builder_end (&builder); + if (p_max_rate_has) + bss_info->max_rate = p_max_rate / 1000u; + + v_v = nm_g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); + if (v_v) { + bss_info->wpa_flags = security_from_vardict (v_v); + g_variant_unref (v_v); + } + + v_v = nm_g_variant_lookup_value (properties, "RSN", G_VARIANT_TYPE_VARDICT); + if (v_v) { + bss_info->rsn_flags = security_from_vardict (v_v); + g_variant_unref (v_v); + } + + _bss_info_changed_emit (self, bss_info, TRUE); } static void -peer_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +_bss_info_get_all_cb (GVariant *result, + GError *error, + gpointer user_data) { + NMSupplicantBssInfo *bss_info; NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; - gs_free_error GError *error = NULL; - GVariant *props = NULL; - const char *object_path; - PeerData *peer_data; - gboolean success; - - success = g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error); - if ( !success - && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + gs_unref_variant GVariant *properties = NULL; + + if (nm_utils_error_is_cancelled (error)) return; - self = NM_SUPPLICANT_INTERFACE (user_data); + bss_info = user_data; + self = bss_info->_self; priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (!success) { - _LOGD ("failed to acquire Peer proxy: (%s)", error->message); - g_hash_table_remove (priv->peer_proxies, - g_dbus_proxy_get_object_path (proxy)); - return; - } + g_clear_object (&bss_info->_init_cancellable); + nm_c_list_move_tail (&priv->bss_lst_head, &bss_info->_bss_lst); - object_path = g_dbus_proxy_get_object_path (proxy); - peer_data = g_hash_table_lookup (priv->peer_proxies, object_path); - if (!peer_data) - return; + if (result) + g_variant_get (result, "(@a{sv})", &properties); - peer_data->change_id = g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (peer_proxy_properties_changed_cb), self); + _bss_info_properties_changed (self, bss_info, properties, TRUE); - props = peer_proxy_get_properties (self, proxy); + _starting_check_ready (self); - g_signal_emit (self, signals[PEER_UPDATED], 0, - g_dbus_proxy_get_object_path (proxy), - g_variant_ref_sink (props)); - g_variant_unref (props); + _notify_maybe_scanning (self); } static void -peer_add_new (NMSupplicantInterface *self, const char *object_path) +_bss_info_add (NMSupplicantInterface *self, const char *object_path) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - GDBusProxy *peer_proxy; - PeerData *peer_data; + nm_auto_ref_string NMRefString *bss_path = NULL; + NMSupplicantBssInfo *bss_info; - g_return_if_fail (object_path != NULL); + bss_path = nm_ref_string_new (nm_dbus_path_not_empty (object_path)); + if (!bss_path) + return; - if (g_hash_table_lookup (priv->peer_proxies, object_path)) + bss_info = g_hash_table_lookup (priv->bss_idx, &bss_path); + if (bss_info) { + bss_info->_bss_dirty = FALSE; return; + } - peer_proxy = g_object_new (G_TYPE_DBUS_PROXY, - "g-bus-type", G_BUS_TYPE_SYSTEM, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-name", WPAS_DBUS_SERVICE, - "g-object-path", object_path, - "g-interface-name", WPAS_DBUS_IFACE_PEER, - NULL); - peer_data = g_slice_new0 (PeerData); - peer_data->proxy = peer_proxy; - g_hash_table_insert (priv->peer_proxies, - (char *) g_dbus_proxy_get_object_path (peer_proxy), - peer_data); - g_async_initable_init_async (G_ASYNC_INITABLE (peer_proxy), - G_PRIORITY_DEFAULT, - priv->other_cancellable, - (GAsyncReadyCallback) peer_proxy_acquired_cb, - self); + bss_info = g_slice_new (NMSupplicantBssInfo); + *bss_info = (NMSupplicantBssInfo) { + ._self = self, + .bss_path = g_steal_pointer (&bss_path), + ._init_cancellable = g_cancellable_new (), + }; + c_list_link_tail (&priv->bss_initializing_lst_head, &bss_info->_bss_lst); + g_hash_table_add (priv->bss_idx, bss_info); + + nm_dbus_connection_call_get_all (priv->dbus_connection, + priv->name_owner->str, + bss_info->bss_path->str, + NM_WPAS_DBUS_IFACE_BSS, + 5000, + bss_info->_init_cancellable, + _bss_info_get_all_cb, + bss_info); +} + +static gboolean +_bss_info_remove (NMSupplicantInterface *self, + NMRefString **p_bss_path) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantBssInfo *bss_info; + gpointer unused_but_required; + + if (!g_hash_table_steal_extended (priv->bss_idx, + p_bss_path, + (gpointer *) &bss_info, + &unused_but_required)) + return FALSE; + + c_list_unlink (&bss_info->_bss_lst); + if (!bss_info->_init_cancellable) + _bss_info_changed_emit (self, bss_info, FALSE); + _bss_info_destroy (bss_info); + + nm_assert_starting_has_pending_count (priv->starting_pending_count); + + return TRUE; } /*****************************************************************************/ static void -set_state (NMSupplicantInterface *self, NMSupplicantInterfaceState new_state) +_peer_info_destroy (NMSupplicantPeerInfo *peer_info) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - NMSupplicantInterfaceState old_state = priv->state; + c_list_unlink (&peer_info->_peer_lst); + nm_clear_g_cancellable (&peer_info->_init_cancellable); - if (new_state == priv->state) - return; + g_free (peer_info->device_name); + g_free (peer_info->manufacturer); + g_free (peer_info->model); + g_free (peer_info->model_number); + g_free (peer_info->serial); + g_bytes_unref (peer_info->ies); + + nm_g_slice_free (peer_info); +} + +static void +_peer_info_changed_emit (NMSupplicantInterface *self, + NMSupplicantPeerInfo *peer_info, + gboolean is_present) +{ + g_signal_emit (self, + signals[PEER_CHANGED], + 0, + peer_info, + is_present); +} + +static void +_peer_info_properties_changed (NMSupplicantInterface *self, + NMSupplicantPeerInfo *peer_info, + GVariant *properties, + gboolean initial) +{ + GVariant *v_v; + const char *v_s; + gint32 v_i32; + const guint8 *arr_data; + gsize arr_len; + + peer_info->last_seen_msec = nm_utils_get_monotonic_timestamp_msec (); - /* DOWN is a terminal state */ - g_return_if_fail (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN); + if (nm_g_variant_lookup (properties, "level", "i", &v_i32)) + peer_info->signal_percent = nm_wifi_utils_level_to_quality (v_i32); - /* Cannot regress to READY, STARTING, or INIT from higher states */ - if (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY) - g_return_if_fail (new_state > NM_SUPPLICANT_INTERFACE_STATE_READY); + if (nm_g_variant_lookup (properties, "DeviceName", "&s", &v_s)) + nm_utils_strdup_reset (&peer_info->device_name, v_s); - if (new_state == NM_SUPPLICANT_INTERFACE_STATE_READY) { - nm_clear_g_cancellable (&priv->other_cancellable); - priv->other_cancellable = g_cancellable_new (); - } else if (new_state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { - nm_clear_g_cancellable (&priv->init_cancellable); - nm_clear_g_cancellable (&priv->other_cancellable); + if (nm_g_variant_lookup (properties, "Manufacturer", "&s", &v_s)) + nm_utils_strdup_reset (&peer_info->manufacturer, v_s); - if (priv->iface_proxy) - g_signal_handlers_disconnect_by_data (priv->iface_proxy, self); + if (nm_g_variant_lookup (properties, "Model", "&s", &v_s)) + nm_utils_strdup_reset (&peer_info->model, v_s); + + if (nm_g_variant_lookup (properties, "ModelNumber", "&s", &v_s)) + nm_utils_strdup_reset (&peer_info->model_number, v_s); + + if (nm_g_variant_lookup (properties, "Serial", "&s", &v_s)) + nm_utils_strdup_reset (&peer_info->serial, v_s); + + v_v = nm_g_variant_lookup_value (properties, "DeviceAddress", G_VARIANT_TYPE_BYTESTRING); + if (v_v) { + arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1); + if ( arr_len == ETH_ALEN + && memcmp (arr_data, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 + && memcmp (arr_data, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) { + /* pass */ + } else + arr_len = 0; + + if (arr_len != 0) { + nm_assert (arr_len == sizeof (peer_info->address)); + peer_info->address_valid = TRUE; + memcpy (peer_info->address, arr_data, sizeof (peer_info->address)); + } else if (peer_info->address_valid) { + peer_info->address_valid = FALSE; + memset (peer_info->address, 0, sizeof (peer_info->address)); + } + g_variant_unref (v_v); + } else { + nm_assert ( !initial + || !peer_info->address_valid); } + nm_assert ( ( peer_info->address_valid + && !nm_utils_memeqzero (peer_info->address, sizeof (peer_info->address))) + || ( !peer_info->address_valid + && nm_utils_memeqzero (peer_info->address, sizeof (peer_info->address)))); - priv->state = new_state; + /* The IEs property contains the WFD R1 subelements */ + v_v = nm_g_variant_lookup_value (properties, "IEs", G_VARIANT_TYPE_BYTESTRING); + if (v_v) { + arr_data = g_variant_get_fixed_array (v_v, &arr_len, 1); + if (!nm_utils_gbytes_equal_mem (peer_info->ies, arr_data, arr_len)) { + _nm_unused gs_unref_bytes GBytes *old_free = g_steal_pointer (&peer_info->ies); - if ( priv->state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING - || old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING) - priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); + peer_info->ies = g_bytes_new (arr_data, arr_len); + } else if ( arr_len == 0 + && !peer_info->ies) + peer_info->ies = g_bytes_new (NULL, 0); + g_variant_unref (v_v); + } - /* Disconnect reason is no longer relevant when not in the DISCONNECTED state */ - if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED) - priv->disconnect_reason = 0; + _peer_info_changed_emit (self, peer_info, TRUE); +} - g_signal_emit (self, signals[STATE], 0, - (int) priv->state, - (int) old_state, - (int) priv->disconnect_reason); -} - -static NMSupplicantInterfaceState -wpas_state_string_to_enum (const char *str_state) -{ - if (!strcmp (str_state, "interface_disabled")) - return NM_SUPPLICANT_INTERFACE_STATE_DISABLED; - else if (!strcmp (str_state, "disconnected")) - return NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED; - else if (!strcmp (str_state, "inactive")) - return NM_SUPPLICANT_INTERFACE_STATE_INACTIVE; - else if (!strcmp (str_state, "scanning")) - return NM_SUPPLICANT_INTERFACE_STATE_SCANNING; - else if (!strcmp (str_state, "authenticating")) - return NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING; - else if (!strcmp (str_state, "associating")) - return NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATING; - else if (!strcmp (str_state, "associated")) - return NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED; - else if (!strcmp (str_state, "4way_handshake")) - return NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE; - else if (!strcmp (str_state, "group_handshake")) - return NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE; - else if (!strcmp (str_state, "completed")) - return NM_SUPPLICANT_INTERFACE_STATE_COMPLETED; - - return NM_SUPPLICANT_INTERFACE_STATE_INVALID; +static void +_peer_info_get_all_cb (GVariant *result, + GError *error, + gpointer user_data) +{ + NMSupplicantPeerInfo *peer_info; + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + gs_unref_variant GVariant *properties = NULL; + + if (nm_utils_error_is_cancelled (error)) + return; + + peer_info = user_data; + self = peer_info->_self; + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + g_clear_object (&peer_info->_init_cancellable); + nm_c_list_move_tail (&priv->peer_lst_head, &peer_info->_peer_lst); + + if (result) + g_variant_get (result, "(@a{sv})", &properties); + + _peer_info_properties_changed (self, peer_info, properties, TRUE); + + _starting_check_ready (self); } static void -set_state_from_string (NMSupplicantInterface *self, const char *new_state) +_peer_info_add (NMSupplicantInterface *self, const char *object_path) { - NMSupplicantInterfaceState state; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + nm_auto_ref_string NMRefString *peer_path = NULL; + NMSupplicantPeerInfo *peer_info; - state = wpas_state_string_to_enum (new_state); - if (state == NM_SUPPLICANT_INTERFACE_STATE_INVALID) { - _LOGW ("unknown supplicant state '%s'", new_state); + peer_path = nm_ref_string_new (nm_dbus_path_not_empty (object_path)); + if (!peer_path) + return; + + peer_info = g_hash_table_lookup (priv->peer_idx, &peer_path); + + if (peer_info) { + peer_info->_peer_dirty = FALSE; return; } - set_state (self, state); + + peer_info = g_slice_new (NMSupplicantPeerInfo); + *peer_info = (NMSupplicantPeerInfo) { + ._self = self, + .peer_path = g_steal_pointer (&peer_path), + ._init_cancellable = g_cancellable_new (), + }; + c_list_link_tail (&priv->peer_initializing_lst_head, &peer_info->_peer_lst); + g_hash_table_add (priv->peer_idx, peer_info); + + nm_dbus_connection_call_get_all (priv->dbus_connection, + priv->name_owner->str, + peer_info->peer_path->str, + NM_WPAS_DBUS_IFACE_PEER, + 5000, + peer_info->_init_cancellable, + _peer_info_get_all_cb, + peer_info); } +static gboolean +_peer_info_remove (NMSupplicantInterface *self, + NMRefString **p_peer_path) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantPeerInfo *peer_info; + gpointer unused_but_required; + + if (!g_hash_table_steal_extended (priv->peer_idx, + p_peer_path, + (gpointer *) &peer_info, + &unused_but_required)) + return FALSE; + + c_list_unlink (&peer_info->_peer_lst); + if (!peer_info->_init_cancellable) + _peer_info_changed_emit (self, peer_info, FALSE); + _peer_info_destroy (peer_info); + + nm_assert_starting_has_pending_count (priv->starting_pending_count); + + return TRUE; +} + +/*****************************************************************************/ + static void -set_scanning (NMSupplicantInterface *self, gboolean new_scanning) +set_state_down (NMSupplicantInterface *self, + gboolean force_remove_from_supplicant, + const char *reason) { + _nm_unused gs_unref_object NMSupplicantInterface *self_keep_alive = g_object_ref (self); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantBssInfo *bss_info; + NMSupplicantPeerInfo *peer_info; + NMSupplicantInterfaceState old_state; + + nm_assert (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN); + nm_assert (!c_list_is_empty (&self->supp_lst)); + + _LOGD ("remove interface \"%s\" on %s (%s)%s", + priv->object_path->str, + priv->name_owner->str, + reason, + force_remove_from_supplicant ? " (remove in wpa_supplicant)" : ""); + + old_state = priv->state; + + priv->state = NM_SUPPLICANT_INTERFACE_STATE_DOWN; + + _nm_supplicant_manager_unregister_interface (priv->supplicant_manager, self); + + nm_assert (c_list_is_empty (&self->supp_lst)); + + if (force_remove_from_supplicant) { + _nm_supplicant_manager_dbus_call_remove_interface (priv->supplicant_manager, + priv->name_owner->str, + priv->object_path->str); + } + + _emit_signal_state (self, priv->state, old_state, 0); + + nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->properties_changed_id); + nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->signal_id); + nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->bss_properties_changed_id); + nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->peer_properties_changed_id); + nm_clear_g_dbus_connection_signal (priv->dbus_connection, &priv->p2p_group_properties_changed_id); + + nm_supplicant_interface_cancel_wps (self); - if (priv->scanning != new_scanning) { - priv->scanning = new_scanning; + if (priv->assoc_data) { + gs_free_error GError *error = NULL; + + nm_utils_error_set_cancelled (&error, TRUE, "NMSupplicantInterface"); + assoc_return (self, error, "cancelled because supplicant interface is going down"); + } - /* Cache time of last scan completion */ - if (priv->scanning == FALSE) - priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); + while ((bss_info = c_list_first_entry (&priv->bss_initializing_lst_head, NMSupplicantBssInfo, _bss_lst))) { + g_hash_table_remove (priv->bss_idx, bss_info); + _bss_info_destroy (bss_info); + } + while ((bss_info = c_list_first_entry (&priv->bss_lst_head, NMSupplicantBssInfo, _bss_lst))) { + g_hash_table_remove (priv->bss_idx, bss_info); + _bss_info_destroy (bss_info); + } + nm_assert (g_hash_table_size (priv->bss_idx) == 0); - _notify (self, PROP_SCANNING); + while ((peer_info = c_list_first_entry (&priv->peer_initializing_lst_head, NMSupplicantPeerInfo, _peer_lst))) { + g_hash_table_remove (priv->peer_idx, peer_info); + _peer_info_destroy (peer_info); } + while ((peer_info = c_list_first_entry (&priv->peer_lst_head, NMSupplicantPeerInfo, _peer_lst))) { + g_hash_table_remove (priv->peer_idx, peer_info); + _peer_info_destroy (peer_info); + } + nm_assert (g_hash_table_size (priv->peer_idx) == 0); + + nm_clear_g_cancellable (&priv->main_cancellable); + nm_clear_g_cancellable (&priv->p2p_group_properties_cancellable); + + nm_clear_pointer (&priv->p2p_group_path, nm_ref_string_unref); + + _remove_network (self); + + nm_clear_pointer (&priv->current_bss, nm_ref_string_unref); + + _notify_maybe_scanning (self); } -gboolean -nm_supplicant_interface_get_scanning (NMSupplicantInterface *self) +static void +set_state (NMSupplicantInterface *self, NMSupplicantInterfaceState new_state) { - NMSupplicantInterfacePrivate *priv; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantInterfaceState old_state = priv->state; - g_return_val_if_fail (self, FALSE); + nm_assert (new_state > NM_SUPPLICANT_INTERFACE_STATE_STARTING); + nm_assert (new_state < NM_SUPPLICANT_INTERFACE_STATE_DOWN); + nm_assert (nm_supplicant_interface_state_is_operational (new_state)); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (priv->scanning) - return TRUE; - if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING) - return TRUE; - return FALSE; + nm_assert (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_STARTING); + nm_assert (priv->state < NM_SUPPLICANT_INTERFACE_STATE_DOWN); + + if (new_state == priv->state) + return; + + _LOGT ("set state \"%s\" (was \"%s\")", + nm_supplicant_interface_state_to_string (new_state), + nm_supplicant_interface_state_to_string (priv->state)); + + priv->state = new_state; + + _emit_signal_state (self, + priv->state, + old_state, + priv->state != NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED + ? 0u + : priv->disconnect_reason); } -const char * +NMRefString * nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self) { - NMSupplicantInterfacePrivate *priv; - g_return_val_if_fail (self != NULL, FALSE); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - return priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY ? priv->current_bss : NULL; + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->current_bss; +} + +gboolean +nm_supplicant_interface_get_scanning (NMSupplicantInterface *self) +{ + g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE); + + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->scanning_cached; } gint64 nm_supplicant_interface_get_last_scan (NMSupplicantInterface *self) { - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->last_scan; + g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE); + + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->last_scan_msec; } #define MATCH_PROPERTY(p, n, v, t) (!strcmp (p, n) && g_variant_is_of_type (v, t)) @@ -600,33 +1169,31 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities) NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); gboolean have_active = FALSE; gboolean have_ssid = FALSE; - gboolean have_p2p = FALSE; gboolean have_ft = FALSE; gint32 max_scan_ssids = -1; const char **array; - g_return_if_fail (capabilities && g_variant_is_of_type (capabilities, G_VARIANT_TYPE_VARDICT)); + nm_assert (capabilities && g_variant_is_of_type (capabilities, G_VARIANT_TYPE_VARDICT)); if (g_variant_lookup (capabilities, "KeyMgmt", "^a&s", &array)) { have_ft = g_strv_contains (array, "wpa-ft-psk"); g_free (array); } - priv->ft_support_per_iface = have_ft - ? NM_SUPPLICANT_FEATURE_YES - : NM_SUPPLICANT_FEATURE_NO; + priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET (priv->iface_capabilities, + NM_SUPPL_CAP_TYPE_FT, + have_ft + ? NM_TERNARY_TRUE + : NM_TERNARY_FALSE); if (g_variant_lookup (capabilities, "Modes", "^a&s", &array)) { - if (g_strv_contains (array, "p2p")) - have_p2p = TRUE; + /* Setting p2p_capable might toggle _prop_p2p_available_get(). However, + * we don't need to check for a property changed notification, because + * the caller did g_object_freeze_notify() and will perform the check. */ + priv->p2p_capable_property = g_strv_contains (array, "p2p"); g_free (array); } - if (priv->p2p_capable != have_p2p) { - priv->p2p_capable = have_p2p; - _notify (self, PROP_P2P_AVAILABLE); - } - if (g_variant_lookup (capabilities, "Scan", "^a&s", &array)) { if (g_strv_contains (array, "active")) have_active = TRUE; @@ -638,187 +1205,116 @@ parse_capabilities (NMSupplicantInterface *self, GVariant *capabilities) if (g_variant_lookup (capabilities, "MaxScanSSID", "i", &max_scan_ssids)) { /* We need active scan and SSID probe capabilities to care about MaxScanSSIDs */ if (max_scan_ssids > 0 && have_active && have_ssid) { - /* wpa_supplicant's WPAS_MAX_SCAN_SSIDS value is 16, but for speed + /* wpa_supplicant's NM_WPAS_MAX_SCAN_SSIDS value is 16, but for speed * and to ensure we don't disclose too many SSIDs from the hidden * list, we'll limit to 5. */ priv->max_scan_ssids = CLAMP (max_scan_ssids, 0, 5); - _LOGI ("supports %d scan SSIDs", priv->max_scan_ssids); + _LOGD ("supports %d scan SSIDs", priv->max_scan_ssids); } } } static void -iface_check_ready (NMSupplicantInterface *self) +_starting_check_ready (NMSupplicantInterface *self) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (priv->ready_count && priv->state < NM_SUPPLICANT_INTERFACE_STATE_READY) { - priv->ready_count--; - if (priv->ready_count == 0) - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_READY); - } -} - -gboolean -nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, - const char *field, - const char *value, - GError **error) -{ - NMSupplicantInterfacePrivate *priv; - gs_unref_variant GVariant *reply = NULL; - - g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), FALSE); - g_return_val_if_fail (field != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); - - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - g_return_val_if_fail (priv->has_credreq == TRUE, FALSE); - - /* Need a network block object path */ - g_return_val_if_fail (priv->net_path, FALSE); - reply = g_dbus_proxy_call_sync (priv->iface_proxy, - "NetworkReply", - g_variant_new ("(oss)", - priv->net_path, - field, - value), - G_DBUS_CALL_FLAGS_NONE, - 5000, - NULL, - error); - if (error && *error) - g_dbus_error_strip_remote_error (*error); - - return !!reply; -} - -static void -iface_check_netreply_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; - - /* We know NetworkReply is supported if the NetworkReply method returned - * successfully (which is unexpected since we sent a bogus network - * object path) or if we got an "InvalidArgs" (which indicates NetworkReply - * is supported). We know it's not supported if we get an - * "UnknownMethod" error. - */ - - variant = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_STARTING) return; - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - if (variant || _nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs")) - priv->has_credreq = TRUE; - - _LOGD ("supplicant %s network credentials requests", - priv->has_credreq ? "supports" : "does not support"); - - iface_check_ready (self); -} + if (priv->starting_pending_count > 0) + return; -static void -iface_set_pmf_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMSupplicantInterface *self; - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; + if (!c_list_is_empty (&priv->bss_initializing_lst_head)) + return; - variant = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (!c_list_is_empty (&priv->peer_initializing_lst_head)) return; - self = NM_SUPPLICANT_INTERFACE (user_data); + if (priv->p2p_group_properties_cancellable) + return; - if (error) - _LOGW ("failed to set Pmf=1: %s", error->message); + nm_assert (priv->state == NM_SUPPLICANT_INTERFACE_STATE_STARTING); - iface_check_ready (self); -} + if (!nm_supplicant_interface_state_is_operational (priv->supp_state)) { + _LOGW ("Supplicant state is unknown during initialization. Destroy the interface"); + set_state_down (self, TRUE, "failure to get valid interface state"); + return; + } -gboolean -nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self) -{ - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->group_proxy_acquired; + set_state (self, priv->supp_state); } -const char* -nm_supplicant_interface_get_p2p_group_path (NMSupplicantInterface *self) +static NMTernary +_get_capability (NMSupplicantInterfacePrivate *priv, + NMSupplCapType type) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMTernary value; + NMTernary iface_value; - if (priv->group_proxy_acquired) - return g_dbus_proxy_get_object_path (priv->group_proxy); - else - return NULL; + switch (type) { + case NM_SUPPL_CAP_TYPE_AP: + iface_value = NM_SUPPL_CAP_MASK_GET (priv->iface_capabilities, type); + value = NM_SUPPL_CAP_MASK_GET (priv->global_capabilities, type); + value = MAX (iface_value, value); + break; + case NM_SUPPL_CAP_TYPE_FT: + value = NM_SUPPL_CAP_MASK_GET (priv->global_capabilities, type); + if (value != NM_TERNARY_FALSE) { + iface_value = NM_SUPPL_CAP_MASK_GET (priv->iface_capabilities, type); + if (iface_value != NM_TERNARY_DEFAULT) + value = iface_value; + } + break; + default: + nm_assert (NM_SUPPL_CAP_MASK_GET (priv->iface_capabilities, type) == NM_TERNARY_DEFAULT); + value = NM_SUPPL_CAP_MASK_GET (priv->global_capabilities, type); + break; + } + return value; } -gboolean -nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self) +NMTernary +nm_supplicant_interface_get_capability (NMSupplicantInterface *self, + NMSupplCapType type) { - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_group_owner; + return _get_capability (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self), type); } -NMSupplicantFeature -nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self) +NMSupplCapMask +nm_supplicant_interface_get_capabilities (NMSupplicantInterface *self) { - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->ap_support; -} + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplCapMask caps; -NMSupplicantFeature -nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self) -{ - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->pmf_support; -} + caps = priv->global_capabilities; + caps = NM_SUPPL_CAP_MASK_SET (caps, NM_SUPPL_CAP_TYPE_AP, _get_capability (priv, NM_SUPPL_CAP_TYPE_AP)); + caps = NM_SUPPL_CAP_MASK_SET (caps, NM_SUPPL_CAP_TYPE_FT, _get_capability (priv, NM_SUPPL_CAP_TYPE_FT)); -NMSupplicantFeature -nm_supplicant_interface_get_fils_support (NMSupplicantInterface *self) -{ - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->fils_support; -} + nm_assert (!NM_FLAGS_ANY (priv->iface_capabilities, + ~( NM_SUPPL_CAP_MASK_T_AP_MASK + | NM_SUPPL_CAP_MASK_T_FT_MASK))); -NMSupplicantFeature -nm_supplicant_interface_get_p2p_support (NMSupplicantInterface *self) -{ - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_support; -} +#if NM_MORE_ASSERTS > 10 + { + NMSupplCapType type; -NMSupplicantFeature -nm_supplicant_interface_get_mesh_support (NMSupplicantInterface *self) -{ - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->mesh_support; -} + for (type = 0; type < _NM_SUPPL_CAP_TYPE_NUM; type++) + nm_assert (NM_SUPPL_CAP_MASK_GET (caps, type) == _get_capability (priv, type)); + } +#endif -NMSupplicantFeature -nm_supplicant_interface_get_wfd_support (NMSupplicantInterface *self) -{ - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->wfd_support; + return caps; } -NMSupplicantFeature -nm_supplicant_interface_get_ft_support (NMSupplicantInterface *self) +void +nm_supplicant_interface_set_global_capabilities (NMSupplicantInterface *self, + NMSupplCapMask value) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (priv->ft_support_global == NM_SUPPLICANT_FEATURE_NO) - return NM_SUPPLICANT_FEATURE_NO; - if (priv->ft_support_per_iface != NM_SUPPLICANT_FEATURE_UNKNOWN) - return priv->ft_support_per_iface; - return priv->ft_support_global; -} - -NMSupplicantFeature -nm_supplicant_interface_get_sha384_support (NMSupplicantInterface *self) -{ - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->sha384_support; + priv->global_capabilities = value; } NMSupplicantAuthState @@ -827,270 +1323,296 @@ nm_supplicant_interface_get_auth_state (NMSupplicantInterface *self) return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->auth_state; } -void -nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, - NMSupplicantFeature ap_support) +/*****************************************************************************/ + +static void +_p2p_group_properties_changed (NMSupplicantInterface *self, + GVariant *properties) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + const char *s; - /* Use the best indicator of support between the supplicant global - * Capabilities property and the interface's introspection data. - */ - if (ap_support > priv->ap_support) - priv->ap_support = ap_support; + if (!properties) + priv->p2p_group_owner_property = FALSE; + else if (g_variant_lookup (properties, "Role", "&s", &s)) + priv->p2p_group_owner_property = nm_streq (s, "GO"); + + _notify_maybe_p2p_group (self); } -void -nm_supplicant_interface_set_fast_support (NMSupplicantInterface *self, - NMSupplicantFeature fast_support) +static void +_p2p_group_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) { + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + gs_unref_variant GVariant *changed_properties = NULL; - priv->fast_support = fast_support; -} + if (priv->p2p_group_properties_cancellable) + return; + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)"))) + return; -void -nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self, - NMSupplicantFeature pmf_support) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + g_variant_get (parameters, + "(&s@a{sv}^a&s)", + NULL, + &changed_properties, + NULL); - priv->pmf_support = pmf_support; + _p2p_group_properties_changed (self, changed_properties); } -void -nm_supplicant_interface_set_fils_support (NMSupplicantInterface *self, - NMSupplicantFeature fils_support) +static void +_p2p_group_properties_get_all_cb (GVariant *result, + GError *error, + gpointer user_data) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + gs_unref_variant GVariant *properties = NULL; - priv->fils_support = fils_support; -} + if (nm_utils_error_is_cancelled (error)) + return; -void -nm_supplicant_interface_set_p2p_support (NMSupplicantInterface *self, - NMSupplicantFeature p2p_support) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - priv->p2p_support = p2p_support; -} + g_object_freeze_notify (G_OBJECT (self)); -void -nm_supplicant_interface_set_mesh_support (NMSupplicantInterface *self, - NMSupplicantFeature mesh_support) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + nm_clear_g_cancellable (&priv->p2p_group_properties_cancellable); - priv->mesh_support = mesh_support; -} + if (result) + g_variant_get (result, "(@a{sv})", &properties); -void -nm_supplicant_interface_set_wfd_support (NMSupplicantInterface *self, - NMSupplicantFeature wfd_support) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + _p2p_group_properties_changed (self, properties); - priv->wfd_support = wfd_support; -} + _starting_check_ready (self); -void -nm_supplicant_interface_set_ft_support (NMSupplicantInterface *self, - NMSupplicantFeature ft_support) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + _notify_maybe_p2p_group (self); - priv->ft_support_global = ft_support; + g_object_thaw_notify (G_OBJECT (self)); } -void -nm_supplicant_interface_set_sha384_support (NMSupplicantInterface *self, - NMSupplicantFeature sha384_support) +static void +_p2p_group_set_path (NMSupplicantInterface *self, + const char *path) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + nm_auto_ref_string NMRefString *group_path = NULL; + + group_path = nm_ref_string_new (nm_dbus_path_not_empty (path)); - priv->sha384_support = sha384_support; + if (priv->p2p_group_path == group_path) + return; + + nm_clear_g_dbus_connection_signal (priv->dbus_connection, + &priv->p2p_group_properties_changed_id); + nm_clear_g_cancellable (&priv->p2p_group_properties_cancellable); + + nm_ref_string_unref (priv->p2p_group_path); + priv->p2p_group_path = g_steal_pointer (&group_path); + + if (priv->p2p_group_path) { + priv->p2p_group_properties_cancellable = g_cancellable_new (); + priv->p2p_group_properties_changed_id = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection, + priv->name_owner->str, + priv->p2p_group_path->str, + NM_WPAS_DBUS_IFACE_GROUP, + _p2p_group_properties_changed_cb, + self, + NULL); + nm_dbus_connection_call_get_all (priv->dbus_connection, + priv->name_owner->str, + priv->p2p_group_path->str, + NM_WPAS_DBUS_IFACE_GROUP, + 5000, + priv->p2p_group_properties_cancellable, + _p2p_group_properties_get_all_cb, + self); + } + + _notify (self, PROP_P2P_GROUP_PATH); + _notify_maybe_p2p_group (self); + + nm_assert_starting_has_pending_count (priv->starting_pending_count); } /*****************************************************************************/ static void -_wps_data_free (WpsData *data) +_wps_data_free (WpsData *wps_data, + GDBusConnection *dbus_connection) { - g_free (data->type); - g_free (data->pin); - g_free (data->bssid); - g_clear_object (&data->cancellable); - if (data->proxy && data->self) - g_signal_handlers_disconnect_by_data (data->proxy, data->self); - g_clear_object (&data->proxy); - g_slice_free (WpsData, data); + nm_clear_g_dbus_connection_signal (dbus_connection, + &wps_data->signal_id); + nm_clear_g_cancellable (&wps_data->cancellable); + g_free (wps_data->type); + g_free (wps_data->pin); + g_free (wps_data->bssid); + nm_g_slice_free (wps_data); } static void -_wps_credentials_changed_cb (GDBusProxy *proxy, - GVariant *props, +_wps_credentials_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) { - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterface *self = user_data; + gs_unref_variant GVariant *props = NULL; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) + return; + + g_variant_get (parameters, "(@a{sv})", &props); _LOGT ("wps: new credentials"); g_signal_emit (self, signals[WPS_CREDENTIALS], 0, props); } static void -_wps_handle_start_cb (GObject *source_object, - GAsyncResult *res, +_wps_handle_start_cb (GObject *source, + GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; - WpsData *data; - gs_unref_variant GVariant *result = NULL; + WpsData *wps_data; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; - result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); - if ( !result - && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (nm_utils_error_is_cancelled (error)) return; - data = user_data; - self = data->self; + wps_data = user_data; + self = wps_data->self; - if (result) + if (res) _LOGT ("wps: started with success"); else _LOGW ("wps: start failed with %s", error->message); - g_clear_object (&data->cancellable); - nm_clear_g_free (&data->type); - nm_clear_g_free (&data->pin); - nm_clear_g_free (&data->bssid); + g_clear_object (&wps_data->cancellable); + nm_clear_g_free (&wps_data->type); + nm_clear_g_free (&wps_data->pin); + nm_clear_g_free (&wps_data->bssid); } static void -_wps_handle_set_pc_cb (GObject *source_object, - GAsyncResult *res, +_wps_handle_set_pc_cb (GVariant *res, + GError *error, gpointer user_data) { - WpsData *data; NMSupplicantInterface *self; - gs_unref_variant GVariant *result = NULL; - gs_free_error GError *error = NULL; + NMSupplicantInterfacePrivate *priv; + WpsData *wps_data; GVariantBuilder start_args; guint8 bssid_buf[ETH_ALEN]; - result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); - if ( !result - && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (nm_utils_error_is_cancelled (error)) return; - data = user_data; - self = data->self; + wps_data = user_data; + self = wps_data->self; + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (result) + if (res) _LOGT ("wps: ProcessCredentials successfully set, starting..."); else _LOGW ("wps: ProcessCredentials failed to set (%s), starting...", error->message); - _nm_dbus_signal_connect (data->proxy, "Credentials", G_VARIANT_TYPE ("(a{sv})"), - G_CALLBACK (_wps_credentials_changed_cb), self); + wps_data->signal_id = g_dbus_connection_signal_subscribe (priv->dbus_connection, + priv->name_owner->str, + NM_WPAS_DBUS_IFACE_INTERFACE_WPS, + "Credentials", + priv->object_path->str, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + _wps_credentials_changed_cb, + self, + NULL); g_variant_builder_init (&start_args, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&start_args, "{sv}", "Role", g_variant_new_string ("enrollee")); - g_variant_builder_add (&start_args, "{sv}", "Type", g_variant_new_string (data->type)); - if (data->pin) - g_variant_builder_add (&start_args, "{sv}", "Pin", g_variant_new_string (data->pin)); - - if (data->bssid) { + g_variant_builder_add (&start_args, "{sv}", "Type", g_variant_new_string (wps_data->type)); + if (wps_data->pin) + g_variant_builder_add (&start_args, "{sv}", "Pin", g_variant_new_string (wps_data->pin)); + if (wps_data->bssid) { /* The BSSID is in fact not mandatory. If it is not set the supplicant would * enroll with any BSS in range. */ - if (!nm_utils_hwaddr_aton (data->bssid, bssid_buf, sizeof (bssid_buf))) + if (!nm_utils_hwaddr_aton (wps_data->bssid, bssid_buf, sizeof (bssid_buf))) nm_assert_not_reached (); g_variant_builder_add (&start_args, "{sv}", "Bssid", g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, bssid_buf, ETH_ALEN, sizeof (guint8))); } - g_dbus_proxy_call (data->proxy, - "Start", - g_variant_new ("(a{sv})", &start_args), - G_DBUS_CALL_FLAGS_NONE, - -1, - data->cancellable, - _wps_handle_start_cb, - data); -} + wps_data->needs_cancelling = TRUE; + if (!wps_data->cancellable) + wps_data->cancellable = g_cancellable_new (); -static void -_wps_call_set_pc (WpsData *data) -{ - g_dbus_proxy_call (data->proxy, - "org.freedesktop.DBus.Properties.Set", - g_variant_new ("(ssv)", - WPAS_DBUS_IFACE_INTERFACE_WPS, - "ProcessCredentials", - g_variant_new_boolean (TRUE)), - G_DBUS_CALL_FLAGS_NONE, - -1, - data->cancellable, - _wps_handle_set_pc_cb, - data); + _dbus_connection_call (self, + NM_WPAS_DBUS_IFACE_INTERFACE_WPS, + "Start", + g_variant_new ("(a{sv})", &start_args), + G_VARIANT_TYPE ("(a{sv})"), + G_DBUS_CALL_FLAGS_NONE, + 5000, + wps_data->cancellable, + _wps_handle_start_cb, + wps_data); } static void -_wps_handle_proxy_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +_wps_call_set_pc (NMSupplicantInterface *self, + WpsData *wps_data) { - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; - WpsData *data; - gs_free_error GError *error = NULL; - GDBusProxy *proxy; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - proxy = g_dbus_proxy_new_for_bus_finish (res, &error); - if ( !proxy - && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + if (!wps_data->cancellable) + wps_data->cancellable = g_cancellable_new (); - data = user_data; - self = data->self; - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - if (!proxy) { - _LOGW ("wps: failure to create D-Bus proxy: %s", error->message); - _wps_data_free (data); - priv->wps_data = NULL; - return; - } - - data->proxy = proxy; - _LOGT ("wps: D-Bus proxy created. set ProcessCredentials..."); - _wps_call_set_pc (data); + nm_dbus_connection_call_set (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE_WPS, + "ProcessCredentials", + g_variant_new_boolean (TRUE), + 5000, + wps_data->cancellable, + _wps_handle_set_pc_cb, + wps_data); } static void -_wps_handle_cancel_cb (GObject *source_object, - GAsyncResult *res, +_wps_handle_cancel_cb (GObject *source, + GAsyncResult *result, gpointer user_data) { + GDBusConnection *dbus_connection = G_DBUS_CONNECTION (source); NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; - WpsData *data; - gs_unref_variant GVariant *result = NULL; + WpsData *wps_data; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; - result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); - if ( !result - && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + res = g_dbus_connection_call_finish (dbus_connection, result, &error); + nm_assert (!nm_utils_error_is_cancelled (error)); - data = user_data; - self = data->self; + wps_data = user_data; + self = wps_data->self; if (!self) { - _wps_data_free (data); - if (result) + _wps_data_free (wps_data, dbus_connection); + if (res) _LOGT ("wps: cancel completed successfully, after supplicant interface is gone"); else _LOGW ("wps: cancel failed (%s), after supplicant interface is gone", error->message); @@ -1099,23 +1621,24 @@ _wps_handle_cancel_cb (GObject *source_object, priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - data->is_cancelling = FALSE; + wps_data->is_cancelling = FALSE; - if (!data->type) { + if (!wps_data->type) { priv->wps_data = NULL; - _wps_data_free (data); - if (result) + _wps_data_free (wps_data, dbus_connection); + if (res) _LOGT ("wps: cancel completed successfully"); else _LOGW ("wps: cancel failed (%s)", error->message); return; } - if (result) + if (res) _LOGT ("wps: cancel completed successfully, setting ProcessCredentials now..."); else _LOGW ("wps: cancel failed (%s), setting ProcessCredentials now...", error->message); - _wps_call_set_pc (data); + + _wps_call_set_pc (self, wps_data); } static void @@ -1125,74 +1648,71 @@ _wps_start (NMSupplicantInterface *self, const char *pin) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - WpsData *data = priv->wps_data; + WpsData *wps_data; if (type) _LOGI ("wps: type %s start...", type); - if (!data) { + wps_data = priv->wps_data; + + if (!wps_data) { if (!type) return; - data = g_slice_new0 (WpsData); - data->self = self; - data->type = g_strdup (type); - data->bssid = g_strdup (bssid); - data->pin = g_strdup (pin); - data->cancellable = g_cancellable_new (); - - priv->wps_data = data; - - _LOGT ("wps: create D-Bus proxy..."); - - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, - WPAS_DBUS_SERVICE, - priv->object_path, - WPAS_DBUS_IFACE_INTERFACE_WPS, - data->cancellable, - _wps_handle_proxy_cb, - data); - return; - } - - g_free (data->type); - g_free (data->bssid); - g_free (data->pin); - data->type = g_strdup (type); - data->bssid = g_strdup (bssid); - data->pin = g_strdup (pin); + if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_DOWN) { + _LOGD ("wps: interface is down. Cannot start with WPS"); + return; + } - if (!data->proxy) { - if (!type) { - nm_clear_g_cancellable (&data->cancellable); - priv->wps_data = NULL; - _wps_data_free (data); + wps_data = g_slice_new (WpsData); + *wps_data = (WpsData) { + .self = self, + .type = g_strdup (type), + .bssid = g_strdup (bssid), + .pin = g_strdup (pin), + }; + priv->wps_data = wps_data; + } else { + g_free (wps_data->type); + g_free (wps_data->bssid); + g_free (wps_data->pin); + wps_data->type = g_strdup (type); + wps_data->bssid = g_strdup (bssid); + wps_data->pin = g_strdup (pin); + } - _LOGT ("wps: abort creation of D-Bus proxy"); - } else - _LOGT ("wps: new enrollment. Wait for D-Bus proxy..."); + if (wps_data->is_cancelling) { + /* we wait for cancellation to complete. */ return; } - if (data->is_cancelling) + if ( !type + || wps_data->needs_cancelling) { + + _LOGT ("wps: cancel %senrollment...", + wps_data->needs_cancelling ? "previous " : ""); + + wps_data->is_cancelling = TRUE; + wps_data->needs_cancelling = FALSE; + nm_clear_g_cancellable (&wps_data->cancellable); + nm_clear_g_dbus_connection_signal (priv->dbus_connection, + &wps_data->signal_id); + + _dbus_connection_call (self, + NM_WPAS_DBUS_IFACE_INTERFACE_WPS, + "Cancel", + NULL, + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NONE, + 5000, + NULL, + _wps_handle_cancel_cb, + wps_data); return; + } - _LOGT ("wps: cancel previous enrollment..."); - - data->is_cancelling = TRUE; - nm_clear_g_cancellable (&data->cancellable); - data->cancellable = g_cancellable_new (); - g_signal_handlers_disconnect_by_data (data->proxy, self); - g_dbus_proxy_call (data->proxy, - "Cancel", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - data->cancellable, - _wps_handle_cancel_cb, - data); + _LOGT ("wps: setting ProcessCredentials..."); + _wps_call_set_pc (self, wps_data); } void @@ -1213,926 +1733,199 @@ nm_supplicant_interface_cancel_wps (NMSupplicantInterface *self) /*****************************************************************************/ static void -iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +iface_introspect_cb (GObject *source, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; - gs_unref_variant GVariant *variant = NULL; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; const char *data; + NMTernary value; - variant = _nm_dbus_proxy_call_finish (proxy, result, - G_VARIANT_TYPE ("(s)"), - &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (nm_utils_error_is_cancelled (error)) return; self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (variant) { - g_variant_get (variant, "(&s)", &data); - - /* The ProbeRequest method only exists if AP mode has been enabled */ - if (strstr (data, "ProbeRequest")) - priv->ap_support = NM_SUPPLICANT_FEATURE_YES; - } - - iface_check_ready (self); -} - -static void -scan_done_emit_signal (NMSupplicantInterface *self) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - const char *object_path; - BssData *bss_data; - gboolean success; - GHashTableIter iter; - - g_hash_table_iter_init (&iter, priv->bss_proxies); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &bss_data)) { - /* we have some BSS' that need to be initialized first. Delay - * emitting signal. */ - if (!bss_data->change_id) { - priv->scan_done_pending = TRUE; - return; - } - } + nm_assert (NM_SUPPL_CAP_MASK_GET (priv->global_capabilities, NM_SUPPL_CAP_TYPE_AP) == NM_TERNARY_DEFAULT); - /* Emit BSS_UPDATED so that wifi device has the APs (in case it removed them) */ - g_hash_table_iter_init (&iter, priv->bss_proxies); - while (g_hash_table_iter_next (&iter, (gpointer *) &object_path, (gpointer *) &bss_data)) { - gs_unref_variant GVariant *props = NULL; + value = NM_TERNARY_DEFAULT; + if (res) { + g_variant_get (res, "(&s)", &data); - props = bss_proxy_get_properties (self, bss_data->proxy); - g_signal_emit (self, signals[BSS_UPDATED], 0, - object_path, - g_variant_ref_sink (props)); + /* The ProbeRequest method only exists if AP mode has been enabled */ + value = strstr (data, "ProbeRequest") + ? NM_TERNARY_TRUE + : NM_TERNARY_FALSE; } - success = priv->scan_done_success; - priv->scan_done_success = FALSE; - priv->scan_done_pending = FALSE; - g_signal_emit (self, signals[SCAN_DONE], 0, success); -} - -static void -wpas_iface_scan_done (GDBusProxy *proxy, - gboolean success, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - /* Cache last scan completed time */ - priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); - priv->scan_done_success |= success; - scan_done_emit_signal (self); -} - -static void -wpas_iface_bss_added (GDBusProxy *proxy, - const char *path, - GVariant *props, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - if (priv->scanning) - priv->last_scan = nm_utils_get_monotonic_timestamp_ms (); - - bss_add_new (self, path); -} - -static void -wpas_iface_bss_removed (GDBusProxy *proxy, - const char *path, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - BssData *bss_data; - - bss_data = g_hash_table_lookup (priv->bss_proxies, path); - if (!bss_data) - return; - g_hash_table_steal (priv->bss_proxies, path); - g_signal_emit (self, signals[BSS_REMOVED], 0, path); - bss_data_destroy (bss_data); -} - -static void -wpas_iface_network_request (GDBusProxy *proxy, - const char *path, - const char *field, - const char *message, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - if (priv->has_credreq && priv->net_path && !g_strcmp0 (path, priv->net_path)) - g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message); -} - -static void -eap_changed (GDBusProxy *proxy, - const char *status, - const char *parameter, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - NMSupplicantAuthState auth_state = NM_SUPPLICANT_AUTH_STATE_UNKNOWN; - - if (nm_streq0 (status, "started")) - auth_state = NM_SUPPLICANT_AUTH_STATE_STARTED; - else if (nm_streq0 (status, "completion")) { - if (nm_streq0 (parameter, "success")) - auth_state = NM_SUPPLICANT_AUTH_STATE_SUCCESS; - else if (nm_streq0 (parameter, "failure")) - auth_state = NM_SUPPLICANT_AUTH_STATE_FAILURE; - } + priv->iface_capabilities = NM_SUPPL_CAP_MASK_SET (priv->iface_capabilities, NM_SUPPL_CAP_TYPE_AP, value); - /* the state eventually reaches one of started, success or failure - * so ignore any other intermediate (unknown) state change. */ - if ( auth_state != NM_SUPPLICANT_AUTH_STATE_UNKNOWN - && auth_state != priv->auth_state) { - priv->auth_state = auth_state; - _notify (self, PROP_AUTH_STATE); - } + priv->starting_pending_count--; + _starting_check_ready (self); } static void -props_changed_cb (GDBusProxy *proxy, - GVariant *changed_properties, - GStrv invalidated_properties, - gpointer user_data) +_properties_changed_main (NMSupplicantInterface *self, + GVariant *properties) { - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - const char *s, **array, **iter; - gboolean b = FALSE; - gint32 i32; - GVariant *v; - - g_object_freeze_notify (G_OBJECT (self)); + const char **v_strv; + const char *v_s; + gboolean v_b; + gint32 v_i32; + GVariant *v_v; + gboolean do_log_driver_info = FALSE; + gboolean do_set_state = FALSE; + gboolean do_notify_current_bss = FALSE; - if (g_variant_lookup (changed_properties, "Scanning", "b", &b)) - set_scanning (self, b); + nm_assert (properties || g_variant_is_of_type (properties, G_VARIANT_TYPE ("a{sv}"))); - if ( g_variant_lookup (changed_properties, "State", "&s", &s) - && priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY) { - /* Only transition to actual wpa_supplicant interface states (ie, - * anything > READY) after the NMSupplicantInterface has had a - * chance to initialize, which is signalled by entering the READY - * state. - */ - set_state_from_string (self, s); + v_v = g_variant_lookup_value (properties, "Capabilities", G_VARIANT_TYPE_VARDICT); + if (v_v) { + parse_capabilities (self, v_v); + g_variant_unref (v_v); } - if (g_variant_lookup (changed_properties, "BSSs", "^a&o", &array)) { - iter = array; - while (*iter) - bss_add_new (self, *iter++); - g_free (array); - } + if (nm_g_variant_lookup (properties, "Scanning", "b", &v_b)) + priv->scanning_property = v_b; - if (g_variant_lookup (changed_properties, "CurrentBSS", "&o", &s)) { - s = nm_utils_dbus_normalize_object_path (s); - if (!nm_streq0 (s, priv->current_bss)) { - g_free (priv->current_bss); - priv->current_bss = g_strdup (s); - _notify (self, PROP_CURRENT_BSS); - } + if (nm_g_variant_lookup (properties, "Ifname", "&s", &v_s)) { + if (nm_utils_strdup_reset (&priv->ifname, v_s)) + do_log_driver_info = TRUE; } - - v = g_variant_lookup_value (changed_properties, "Capabilities", G_VARIANT_TYPE_VARDICT); - if (v) { - parse_capabilities (self, v); - g_variant_unref (v); + if (nm_g_variant_lookup (properties, "Driver", "&s", &v_s)) { + if (nm_utils_strdup_reset (&priv->driver, v_s)) + do_log_driver_info = TRUE; } - if (g_variant_lookup (changed_properties, "DisconnectReason", "i", &i32)) { + if (nm_g_variant_lookup (properties, "DisconnectReason", "i", &v_i32)) { /* Disconnect reason is currently only given for deauthentication events, * not disassociation; currently they are IEEE 802.11 "reason codes", * defined by (IEEE 802.11-2007, 7.3.1.7, Table 7-22). Any locally caused * deauthentication will be negative, while authentications caused by the * AP will be positive. */ - priv->disconnect_reason = i32; - if (priv->disconnect_reason != 0) - _LOGW ("connection disconnected (reason %d)", priv->disconnect_reason); - } - - /* We may not have priv->dev set yet if this interface was created from a - * known wpa_supplicant interface without knowing the device name. - */ - if (priv->dev == NULL && g_variant_lookup (changed_properties, "Ifname", "&s", &s)) { - priv->dev = g_strdup (s); - _notify (self, PROP_IFACE); - } - - g_object_thaw_notify (G_OBJECT (self)); -} - -static void -group_props_changed_cb (GDBusProxy *proxy, - GVariant *changed_properties, - char **invalidated_properties, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - char *s; - - g_object_freeze_notify (G_OBJECT (self)); - -#if 0 - v = g_variant_lookup_value (properties, "BSSID", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - if ( len == ETH_ALEN - && memcmp (bytes, nm_ip_addr_zero.addr_eth, ETH_ALEN) != 0 - && memcmp (bytes, (char[ETH_ALEN]) { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, ETH_ALEN) != 0) - nm_wifi_p2p_group_set_bssid_bin (group, bytes); - g_variant_unref (v); - } - - v = g_variant_lookup_value (properties, "SSID", G_VARIANT_TYPE_BYTESTRING); - if (v) { - bytes = g_variant_get_fixed_array (v, &len, 1); - len = MIN (32, len); - - /* Stupid ieee80211 layer uses <hidden> */ - if ( bytes && len - && !(((len == 8) || (len == 9)) && !memcmp (bytes, "<hidden>", 8)) - && !nm_utils_is_empty_ssid (bytes, len)) - nm_wifi_p2p_group_set_ssid (group, bytes, len); - - g_variant_unref (v); - } -#endif - - if (g_variant_lookup (changed_properties, "Role", "s", &s)) { - priv->p2p_group_owner = g_strcmp0 (s, "GO") == 0; - _notify (self, PROP_P2P_GROUP_OWNER); - g_free (s); - } - - /* NOTE: We do not seem to get any property change notifications for the Members - * property. However, we can keep track of these indirectly either by querying - * the groups that each peer is in or listening to the Join/Disconnect - * notifications. - */ - - g_object_thaw_notify (G_OBJECT (self)); -} - -static void -group_proxy_acquired_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; - gs_free_error GError *error = NULL; - gboolean success; - - success = g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error); - if ( !success - && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - if (!success) { - _LOGD ("failed to acquire Group proxy: (%s)", error->message); - g_clear_object (&priv->group_proxy); - return; - } - - priv->group_proxy_acquired = TRUE; - _notify (self, PROP_P2P_GROUP_JOINED); - _notify (self, PROP_P2P_GROUP_PATH); - - iface_check_ready (self); -} - -static void -p2p_props_changed_cb (GDBusProxy *proxy, - GVariant *changed_properties, - GStrv invalidated_properties, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - const char **array, **iter; - const char *path = NULL; - - g_object_freeze_notify (G_OBJECT (self)); - - if (g_variant_lookup (changed_properties, "Peers", "^a&o", &array)) { - iter = array; - while (*iter) - peer_add_new (self, *iter++); - g_free (array); - } - - if (g_variant_lookup (changed_properties, "Group", "&o", &path)) { - if (priv->group_proxy && g_strcmp0 (path, g_dbus_proxy_get_object_path (priv->group_proxy)) == 0) { - /* We already have the proxy, nothing to do. */ - } else if (nm_dbus_path_not_empty (path)) { - if (priv->group_proxy != NULL) { - _LOGW ("P2P: Unexpected update of the group object path"); - priv->group_proxy_acquired = FALSE; - _notify (self, PROP_P2P_GROUP_JOINED); - _notify (self, PROP_P2P_GROUP_PATH); - g_clear_object (&priv->group_proxy); + priv->disconnect_reason = v_i32; + } + + if (nm_g_variant_lookup (properties, "State", "&s", &v_s)) { + NMSupplicantInterfaceState state; + + state = wpas_state_string_to_enum (v_s); + if (state == NM_SUPPLICANT_INTERFACE_STATE_INVALID) + _LOGT ("ignore unknown supplicant state '%s'", v_s); + else if (priv->supp_state != state) { + priv->supp_state = state; + if (priv->state > NM_SUPPLICANT_INTERFACE_STATE_STARTING) { + /* Only transition to actual wpa_supplicant interface states (ie, + * anything > STARTING) after the NMSupplicantInterface has had a + * chance to initialize, which is signalled by entering the STARTING + * state. + */ + do_set_state = TRUE; } - - /* Delay ready state if we have not reached it yet. */ - if (priv->ready_count) - priv->ready_count++; - - priv->group_proxy = g_object_new (G_TYPE_DBUS_PROXY, - "g-bus-type", G_BUS_TYPE_SYSTEM, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-name", WPAS_DBUS_SERVICE, - "g-object-path", path, - "g-interface-name", WPAS_DBUS_IFACE_GROUP, - NULL); - g_signal_connect (priv->group_proxy, "g-properties-changed", G_CALLBACK (group_props_changed_cb), self); - g_async_initable_init_async (G_ASYNC_INITABLE (priv->group_proxy), - G_PRIORITY_DEFAULT, - priv->other_cancellable, - (GAsyncReadyCallback) group_proxy_acquired_cb, - self); - } else { - priv->group_proxy_acquired = FALSE; - _notify (self, PROP_P2P_GROUP_JOINED); - _notify (self, PROP_P2P_GROUP_PATH); - g_clear_object (&priv->group_proxy); } } - g_object_thaw_notify (G_OBJECT (self)); -} - -static void -p2p_device_found (GDBusProxy *proxy, - const char *path, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - - peer_add_new (self, path); -} - -static void -p2p_device_lost (GDBusProxy *proxy, - const char *path, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - PeerData *peer_data; - - peer_data = g_hash_table_lookup (priv->peer_proxies, path); - if (!peer_data) - return; - g_hash_table_steal (priv->peer_proxies, path); - g_signal_emit (self, signals[PEER_REMOVED], 0, path); - peer_data_destroy (peer_data); -} - -static void -p2p_group_started (GDBusProxy *proxy, - GVariant *params, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - NMSupplicantInterface *iface = NULL; - char *group_path = NULL; - char *iface_path = NULL; - - /* There is one more parameter: the role, but we don't really care about that here. */ - if (!g_variant_lookup (params, "group_object", "&o", &group_path)) { - _LOGW ("P2P: GroupStarted signal is missing the \"group_object\" parameter"); - return; - } - - if (!g_variant_lookup (params, "interface_object", "&o", &iface_path)) { - _LOGW ("P2P: GroupStarted signal is missing the \"interface\" parameter"); - return; - } - - if (g_strcmp0 (iface_path, priv->object_path) == 0) { - _LOGW ("P2P: GroupStarted on existing interface"); - iface = g_object_ref (self); - } else { - iface = nm_supplicant_manager_create_interface_from_path (nm_supplicant_manager_get (), - iface_path); - if (iface == NULL) { - _LOGW ("P2P: Group interface already exists in GroupStarted handler, aborting further processing."); - return; + if (nm_g_variant_lookup (properties, "CurrentBSS", "&o", &v_s)) { + v_s = nm_dbus_path_not_empty (v_s); + if (!nm_ref_string_equals_str (priv->current_bss, v_s)) { + nm_ref_string_unref (priv->current_bss); + priv->current_bss = nm_ref_string_new (v_s); + do_notify_current_bss = TRUE; } } - /* Signal existence of the (new) interface. */ - g_signal_emit (self, signals[GROUP_STARTED], 0, iface); - g_object_unref (iface); -} - -static void -p2p_group_formation_failure (GDBusProxy *proxy, - const char *group, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - - g_signal_emit (self, signals[GROUP_FORMATION_FAILURE], 0, group); -} - -static void -p2p_group_finished (GDBusProxy *proxy, - GVariant *params, - gpointer user_data) -{ - NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - const char *iface_path = NULL; - /* TODO: Group finished is called on the management interface! - * This means the signal consumer will currently need to assume which - * interface is finishing or it needs to match the object paths. - */ - - if (!g_variant_lookup (params, "interface_object", "&o", &iface_path)) { - _LOGW ("P2P: GroupFinished signal is missing the \"interface\" parameter"); - return; + if (do_log_driver_info) { + _LOGD ("supplicant interface for ifindex=%d, ifname=%s%s%s, driver=%s%s%s (requested %s)", + priv->ifindex, + NM_PRINT_FMT_QUOTE_STRING (priv->ifname), + NM_PRINT_FMT_QUOTE_STRING (priv->driver), + nm_supplicant_driver_to_string (priv->requested_driver)); } - _LOGD ("P2P: GroupFinished signal on interface %s for interface %s", priv->object_path, iface_path); - - /* Signal group finish interface (on management interface). */ - g_signal_emit (self, signals[GROUP_FINISHED], 0, iface_path); -} + if (nm_g_variant_lookup (properties, "BSSs", "^a&o", &v_strv)) { + NMSupplicantBssInfo *bss_info; + NMSupplicantBssInfo *bss_info_safe; + const char **iter; -static void -on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; - gs_free_error GError *error = NULL; + c_list_for_each_entry (bss_info, &priv->bss_lst_head, _bss_lst) + bss_info->_bss_dirty = TRUE; + c_list_for_each_entry (bss_info, &priv->bss_initializing_lst_head, _bss_lst) + bss_info->_bss_dirty = TRUE; - if (!g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error)) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - self = NM_SUPPLICANT_INTERFACE (user_data); - _LOGW ("failed to acquire wpa_supplicant interface proxy: (%s)", error->message); - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); - } - return; - } + for (iter = v_strv; *iter; iter++) + _bss_info_add (self, *iter); - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + g_free (v_strv); - _nm_dbus_signal_connect (priv->iface_proxy, "ScanDone", G_VARIANT_TYPE ("(b)"), - G_CALLBACK (wpas_iface_scan_done), self); - _nm_dbus_signal_connect (priv->iface_proxy, "BSSAdded", G_VARIANT_TYPE ("(oa{sv})"), - G_CALLBACK (wpas_iface_bss_added), self); - _nm_dbus_signal_connect (priv->iface_proxy, "BSSRemoved", G_VARIANT_TYPE ("(o)"), - G_CALLBACK (wpas_iface_bss_removed), self); - _nm_dbus_signal_connect (priv->iface_proxy, "NetworkRequest", G_VARIANT_TYPE ("(oss)"), - G_CALLBACK (wpas_iface_network_request), self); - _nm_dbus_signal_connect (priv->iface_proxy, "EAP", G_VARIANT_TYPE ("(ss)"), - G_CALLBACK (eap_changed), self); - - /* Scan result aging parameters */ - g_dbus_proxy_call (priv->iface_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new ("(ssv)", - WPAS_DBUS_IFACE_INTERFACE, - "BSSExpireAge", - g_variant_new_uint32 (250)), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - NULL, - NULL); - g_dbus_proxy_call (priv->iface_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new ("(ssv)", - WPAS_DBUS_IFACE_INTERFACE, - "BSSExpireCount", - g_variant_new_uint32 (2)), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - NULL, - NULL); - - /* Check whether NetworkReply and AP mode are supported. - * ready_count was initialized to 1 in interface_add_done(). - */ - g_dbus_proxy_call (priv->iface_proxy, - "NetworkReply", - g_variant_new ("(oss)", - "/fff", - "foobar", - "foobar"), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - (GAsyncReadyCallback) iface_check_netreply_cb, - self); - - if (priv->pmf_support == NM_SUPPLICANT_FEATURE_YES) { - /* Initialize global PMF setting to 'optional' */ - priv->ready_count++; - g_dbus_proxy_call (priv->iface_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new ("(ssv)", - WPAS_DBUS_IFACE_INTERFACE, - "Pmf", - g_variant_new_string ("1")), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - (GAsyncReadyCallback) iface_set_pmf_cb, - self); - } - - if (priv->ap_support == NM_SUPPLICANT_FEATURE_UNKNOWN) { - /* If the global supplicant capabilities property is not present, we can - * fall back to checking whether the ProbeRequest method is supported. If - * neither of these works we have no way of determining if AP mode is - * supported or not. hostap 1.0 and earlier don't support either of these. - */ - priv->ready_count++; - g_dbus_proxy_call (priv->iface_proxy, - DBUS_INTERFACE_INTROSPECTABLE ".Introspect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - (GAsyncReadyCallback) iface_introspect_cb, - self); - } -} - -static void -on_p2p_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; - gs_free_error GError *error = NULL; - - if (!g_async_initable_init_finish (G_ASYNC_INITABLE (proxy), result, &error)) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - _LOGW ("failed to acquire wpa_supplicant p2p proxy: (%s)", error->message); - - g_clear_object (&priv->p2p_proxy); - - iface_check_ready (self); + c_list_for_each_entry_safe (bss_info, bss_info_safe, &priv->bss_initializing_lst_head, _bss_lst) { + if (bss_info->_bss_dirty) + _bss_info_remove (self, &bss_info->bss_path); + } + c_list_for_each_entry_safe (bss_info, bss_info_safe, &priv->bss_lst_head, _bss_lst) { + if (bss_info->_bss_dirty) + _bss_info_remove (self, &bss_info->bss_path); } - return; } - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + if (do_notify_current_bss) + _notify (self, PROP_CURRENT_BSS); - _nm_dbus_signal_connect (priv->p2p_proxy, "DeviceFound", G_VARIANT_TYPE ("(o)"), - G_CALLBACK (p2p_device_found), self); - _nm_dbus_signal_connect (priv->p2p_proxy, "DeviceLost", G_VARIANT_TYPE ("(o)"), - G_CALLBACK (p2p_device_lost), self); - _nm_dbus_signal_connect (priv->p2p_proxy, "GroupStarted", G_VARIANT_TYPE ("(a{sv})"), - G_CALLBACK (p2p_group_started), self); - _nm_dbus_signal_connect (priv->p2p_proxy, "GroupFormationFailure", G_VARIANT_TYPE ("(s)"), - G_CALLBACK (p2p_group_formation_failure), self); - _nm_dbus_signal_connect (priv->p2p_proxy, "GroupFinished", G_VARIANT_TYPE ("(a{sv})"), - G_CALLBACK (p2p_group_finished), self); - /* TODO: - * * WpsFailed - * * FindStopped - * * GONegotationFailure - * * InvitationReceived - */ - - priv->p2p_proxy_acquired = TRUE; - _notify (self, PROP_P2P_AVAILABLE); + if (do_set_state) + set_state (self, priv->supp_state); - iface_check_ready (self); + _notify_maybe_scanning (self); } static void -interface_add_done (NMSupplicantInterface *self, const char *path) +_properties_changed_p2p_device (NMSupplicantInterface *self, + GVariant *properties) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + const char **v_strv; + const char *v_s; - _LOGD ("interface added to supplicant"); - - /* Iface ready check happens in iface_check_netreply_cb */ - priv->ready_count = 1; - - priv->object_path = g_strdup (path); - _notify (self, PROP_OBJECT_PATH); - priv->iface_proxy = g_object_new (G_TYPE_DBUS_PROXY, - "g-bus-type", G_BUS_TYPE_SYSTEM, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-name", WPAS_DBUS_SERVICE, - "g-object-path", priv->object_path, - "g-interface-name", WPAS_DBUS_IFACE_INTERFACE, - NULL); - g_signal_connect (priv->iface_proxy, "g-properties-changed", G_CALLBACK (props_changed_cb), self); - g_async_initable_init_async (G_ASYNC_INITABLE (priv->iface_proxy), - G_PRIORITY_DEFAULT, - priv->init_cancellable, - (GAsyncReadyCallback) on_iface_proxy_acquired, - self); - - if (priv->p2p_support == NM_SUPPLICANT_FEATURE_YES) { - priv->ready_count++; - priv->p2p_proxy = g_object_new (G_TYPE_DBUS_PROXY, - "g-bus-type", G_BUS_TYPE_SYSTEM, - "g-flags", G_DBUS_PROXY_FLAGS_NONE, - "g-name", WPAS_DBUS_SERVICE, - "g-object-path", priv->object_path, - "g-interface-name", WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, - NULL); - g_signal_connect (priv->p2p_proxy, "g-properties-changed", G_CALLBACK (p2p_props_changed_cb), self); - g_async_initable_init_async (G_ASYNC_INITABLE (priv->p2p_proxy), - G_PRIORITY_DEFAULT, - priv->init_cancellable, - (GAsyncReadyCallback) on_p2p_proxy_acquired, - self); - } -} - -static void -interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMSupplicantInterface *self; - gs_unref_variant GVariant *variant = NULL; - gs_free_error GError *error = NULL; - const char *path; - - variant = _nm_dbus_proxy_call_finish (proxy, result, - G_VARIANT_TYPE ("(o)"), - &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_SUPPLICANT_INTERFACE (user_data); - - if (variant) { - g_variant_get (variant, "(&o)", &path); - interface_add_done (self, path); - } else { - g_dbus_error_strip_remote_error (error); - _LOGE ("error getting interface: %s", error->message); - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); - } -} - -static void -interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *variant = NULL; - const char *path; - - variant = _nm_dbus_proxy_call_finish (proxy, result, - G_VARIANT_TYPE ("(o)"), - &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - if (variant) { - g_variant_get (variant, "(&o)", &path); - interface_add_done (self, path); - } else if (_nm_dbus_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) { - /* Interface already added, just get its object path */ - g_dbus_proxy_call (priv->wpas_proxy, - "GetInterface", - g_variant_new ("(s)", priv->dev), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - (GAsyncReadyCallback) interface_get_cb, - self); - } else if ( g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_EXEC_FAILED) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FORK_FAILED) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FAILED) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMEOUT) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NO_REPLY) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_TIMED_OUT) - || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { - /* Supplicant wasn't running and could not be launched via service - * activation. Wait for it to start by moving back to the INIT - * state. - */ - g_dbus_error_strip_remote_error (error); - _LOGD ("failed to activate supplicant: %s", error->message); - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_INIT); - } else { - g_dbus_error_strip_remote_error (error); - _LOGE ("error adding interface: %s", error->message); - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); - } -} - -static void -interface_removed_cb (GDBusProxy *proxy, - const char *path, - gpointer user_data) -{ - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; + nm_assert (!properties || g_variant_is_of_type (properties, G_VARIANT_TYPE ("a{sv}"))); - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - if (g_strcmp0 (priv->object_path, path) != 0) - return; + if (nm_g_variant_lookup (properties, "Peers", "^a&o", &v_strv)) { + NMSupplicantPeerInfo *peer_info; + NMSupplicantPeerInfo *peer_info_safe; + const char *const*iter; - _LOGD ("Received interface removed signal"); + c_list_for_each_entry (peer_info, &priv->peer_lst_head, _peer_lst) + peer_info->_peer_dirty = TRUE; + c_list_for_each_entry (peer_info, &priv->peer_initializing_lst_head, _peer_lst) + peer_info->_peer_dirty = TRUE; - /* The interface may lose its last reference during signal handling otherwise. */ - g_object_ref (self); + for (iter = v_strv; *iter; iter++) + _peer_info_add (self, *iter); - /* Invalidate the object path to prevent the manager from trying to remove - * a non-existing interface. */ - g_clear_pointer (&priv->object_path, g_free); - _notify (self, PROP_OBJECT_PATH); + g_free (v_strv); - /* No need to clean up everything now, that will happen at dispose time. */ - - /* Interface is down and has been removed. */ - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); - g_signal_emit (self, signals[REMOVED], 0); - - g_object_unref (self); -} - -#if HAVE_WEXT -#define DEFAULT_WIFI_DRIVER "nl80211,wext" -#else -#define DEFAULT_WIFI_DRIVER "nl80211" -#endif - -static void -on_wpas_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - NMSupplicantInterface *self; - NMSupplicantInterfacePrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy *wpas_proxy; - GVariantBuilder props; - - wpas_proxy = g_dbus_proxy_new_for_bus_finish (result, &error); - if (!wpas_proxy) { - if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - self = NM_SUPPLICANT_INTERFACE (user_data); - _LOGW ("failed to acquire wpa_supplicant proxy: (%s)", error->message); - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); + c_list_for_each_entry_safe (peer_info, peer_info_safe, &priv->peer_initializing_lst_head, _peer_lst) { + if (peer_info->_peer_dirty) + _peer_info_remove (self, &peer_info->peer_path); } - return; - } - - self = NM_SUPPLICANT_INTERFACE (user_data); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - priv->wpas_proxy = wpas_proxy; - - /* Watch for interface removal. */ - _nm_dbus_signal_connect (priv->wpas_proxy, "InterfaceRemoved", G_VARIANT_TYPE ("(o)"), - G_CALLBACK (interface_removed_cb), self); - - /* Try to add the interface to the supplicant. If the supplicant isn't - * running, this will start it via D-Bus activation and return the response - * when the supplicant has started. - */ - - if (priv->dev != NULL) { - const char *driver_name = NULL; - - switch (priv->driver) { - case NM_SUPPLICANT_DRIVER_WIRELESS: - driver_name = DEFAULT_WIFI_DRIVER; - break; - case NM_SUPPLICANT_DRIVER_WIRED: - driver_name = "wired"; - break; - case NM_SUPPLICANT_DRIVER_MACSEC: - driver_name = "macsec_linux"; - break; + c_list_for_each_entry_safe (peer_info, peer_info_safe, &priv->peer_lst_head, _peer_lst) { + if (peer_info->_peer_dirty) + _peer_info_remove (self, &peer_info->peer_path); } - - g_return_if_fail (driver_name); - - g_variant_builder_init (&props, G_VARIANT_TYPE_VARDICT); - g_variant_builder_add (&props, "{sv}", - "Driver", - g_variant_new_string (driver_name)); - g_variant_builder_add (&props, "{sv}", - "Ifname", - g_variant_new_string (priv->dev)); - - g_dbus_proxy_call (priv->wpas_proxy, - "CreateInterface", - g_variant_new ("(a{sv})", &props), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->init_cancellable, - (GAsyncReadyCallback) interface_add_cb, - self); - } else if (priv->object_path) { - interface_add_done (self, priv->object_path); - } else { - g_assert_not_reached (); - } -} - -static void -interface_add (NMSupplicantInterface *self) -{ - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - /* Can only start the interface from INIT state */ - g_return_if_fail (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT); - - _LOGD ("adding interface to supplicant"); - - /* Move to starting to prevent double-calls of interface_add() */ - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_STARTING); - - nm_clear_g_cancellable (&priv->init_cancellable); - priv->init_cancellable = g_cancellable_new (); - - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, - NULL, - WPAS_DBUS_SERVICE, - WPAS_DBUS_PATH, - WPAS_DBUS_INTERFACE, - priv->init_cancellable, - (GAsyncReadyCallback) on_wpas_proxy_acquired, - self); -} - -void -nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self, - gboolean available) -{ - NMSupplicantInterfacePrivate *priv; - - g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); - - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - if (available) { - /* This can happen if the supplicant couldn't be activated but - * for some reason was started after the activation failure. - */ - if (priv->state == NM_SUPPLICANT_INTERFACE_STATE_INIT) - interface_add (self); - } else { - /* The supplicant stopped; so we must tear down the interface */ - set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); } -} - -static void -log_result_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) -{ - gs_unref_variant GVariant *reply = NULL; - gs_free_error GError *error = NULL; - reply = g_dbus_proxy_call_finish (proxy, result, &error); - if ( !reply - && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) - && !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) { - g_dbus_error_strip_remote_error (error); - nm_log_warn (_NMLOG_DOMAIN, "%s: failed to %s: %s", - _NMLOG_PREFIX_NAME, (const char *) user_data, error->message); - } + if (nm_g_variant_lookup (properties, "Group", "&o", &v_s)) + _p2p_group_set_path (self, v_s); } /*****************************************************************************/ static void -assoc_return (NMSupplicantInterface *self, GError *error, const char *message) +assoc_return (NMSupplicantInterface *self, + GError *error, + const char *message) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); AssocData *assoc_data; @@ -2143,9 +1936,14 @@ assoc_return (NMSupplicantInterface *self, GError *error, const char *message) if (error) { g_dbus_error_strip_remote_error (error); - _LOGW ("assoc[%p]: %s: %s", assoc_data, message, error->message); - } else - _LOGD ("assoc[%p]: association request successful", assoc_data); + _LOGW ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: %s: %s", + NM_HASH_OBFUSCATE_PTR (assoc_data), + message, + error->message); + } else { + _LOGD ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: association request successful", + NM_HASH_OBFUSCATE_PTR (assoc_data)); + } if (assoc_data->add_network_data) { /* signal that this request already completed */ @@ -2171,112 +1969,83 @@ nm_supplicant_interface_disconnect (NMSupplicantInterface * self) priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - /* Cancel all pending calls related to a prior connection attempt */ - if (priv->assoc_data) { - gs_free_error GError *error = NULL; - - nm_utils_error_set_cancelled (&error, FALSE, "NMSupplicantInterface"); - assoc_return (self, error, "abort due to disconnect"); - } - - /* Don't do anything if there is no connection to the supplicant yet. */ - if (!priv->iface_proxy) - return; - /* Disconnect from the current AP */ if ( (priv->state >= NM_SUPPLICANT_INTERFACE_STATE_SCANNING) && (priv->state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED)) { - g_dbus_proxy_call (priv->iface_proxy, - "Disconnect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback) log_result_cb, - "disconnect"); - } - - /* Remove any network that was added by NetworkManager */ - if (priv->net_path) { - g_dbus_proxy_call (priv->iface_proxy, - "RemoveNetwork", - g_variant_new ("(o)", priv->net_path), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->other_cancellable, - (GAsyncReadyCallback) log_result_cb, - "remove network"); - g_free (priv->net_path); - priv->net_path = NULL; + _dbus_connection_call_simple (self, + NM_WPAS_DBUS_IFACE_INTERFACE, + "Disconnect", + NULL, + G_VARIANT_TYPE ("()"), + "disconnect"); } + _remove_network (self); + /* Cancel any WPS enrollment, if any */ nm_supplicant_interface_cancel_wps (self); + + /* Cancel all pending calls related to a prior connection attempt */ + if (priv->assoc_data) { + gs_free_error GError *error = NULL; + + nm_utils_error_set_cancelled (&error, FALSE, "NMSupplicantInterface"); + assoc_return (self, error, "abort due to disconnect"); + } } static void -disconnect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +disconnect_cb (GObject *source, GAsyncResult *result, gpointer user_data) { - DisconnectData *disconnect_data = user_data; - gs_unref_object NMSupplicantInterface *self = disconnect_data->self; - gs_unref_variant GVariant *reply = NULL; + gs_unref_object NMSupplicantInterface *self = NULL; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; + NMSupplicantInterfaceDisconnectCb callback; + gpointer callback_user_data; + + nm_utils_user_data_unpack (user_data, &self, &callback, &callback_user_data); - reply = g_dbus_proxy_call_finish (proxy, result, &error); + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); - /* an already disconnected interface is not an error*/ - if ( !reply + if ( !res && !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) { + /* an already disconnected interface is not an error*/ g_clear_error(&error); } - disconnect_data->callback(self, error, disconnect_data->user_data); - g_slice_free (DisconnectData, disconnect_data); + callback (self, error, callback_user_data); } void -nm_supplicant_interface_disconnect_async ( NMSupplicantInterface * self, - GCancellable * cancellable, - NMSupplicantInterfaceDisconnectCb callback, - gpointer user_data) +nm_supplicant_interface_disconnect_async (NMSupplicantInterface *self, + GCancellable *cancellable, + NMSupplicantInterfaceDisconnectCb callback, + gpointer user_data) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - DisconnectData *disconnect_data; - - /* Don't do anything if there is no connection to the supplicant yet. */ - if (!priv->iface_proxy) - return; - g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); - g_return_if_fail (NULL != callback); - - disconnect_data = g_slice_new0(DisconnectData); + g_return_if_fail (callback); - /* Keep interface alive until disconnect finishes */ - disconnect_data->self = g_object_ref (self); - disconnect_data->callback = callback; - disconnect_data->user_data = user_data; - - /* Disconnect the interface */ - g_dbus_proxy_call (priv->iface_proxy, - "Disconnect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - cancellable, - (GAsyncReadyCallback) disconnect_cb, - disconnect_data); + _dbus_connection_call (self, + NM_WPAS_DBUS_IFACE_INTERFACE, + "Disconnect", + NULL, + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_MSEC, + cancellable, + disconnect_cb, + nm_utils_user_data_pack (g_object_ref (self), callback, user_data)); } static void -assoc_select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +assoc_select_network_cb (GObject *source, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; - gs_unref_variant GVariant *reply = NULL; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; - reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (nm_utils_error_is_cancelled (error)) return; self = NM_SUPPLICANT_INTERFACE (user_data); @@ -2291,26 +2060,28 @@ assoc_call_select_network (NMSupplicantInterface *self) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - g_dbus_proxy_call (priv->iface_proxy, - "SelectNetwork", - g_variant_new ("(o)", priv->net_path), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->assoc_data->cancellable, - (GAsyncReadyCallback) assoc_select_network_cb, - self); + _dbus_connection_call (self, + NM_WPAS_DBUS_IFACE_INTERFACE, + "SelectNetwork", + g_variant_new ("(o)", priv->net_path), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_MSEC, + priv->assoc_data->cancellable, + assoc_select_network_cb, + self); } static void -assoc_add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +assoc_add_blob_cb (GObject *source, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; - gs_unref_variant GVariant *reply = NULL; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; - reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (nm_utils_error_is_cancelled (error)) return; self = NM_SUPPLICANT_INTERFACE (user_data); @@ -2322,52 +2093,62 @@ assoc_add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) } priv->assoc_data->blobs_left--; - _LOGT ("assoc[%p]: blob added (%u left)", priv->assoc_data, priv->assoc_data->blobs_left); + _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: blob added (%u left)", + NM_HASH_OBFUSCATE_PTR (priv->assoc_data), + priv->assoc_data->blobs_left); if (priv->assoc_data->blobs_left == 0) assoc_call_select_network (self); } static void -assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +assoc_add_network_cb (GObject *source, GAsyncResult *result, gpointer user_data) { AddNetworkData *add_network_data = user_data; AssocData *assoc_data; NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; - gs_unref_variant GVariant *reply = NULL; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; GHashTable *blobs; GHashTableIter iter; const char *blob_name; GBytes *blob_data; + nm_auto_ref_string NMRefString *name_owner = NULL; + nm_auto_ref_string NMRefString *object_path = NULL; + + g_clear_object (&add_network_data->shutdown_wait_obj); assoc_data = add_network_data->assoc_data; if (assoc_data) assoc_data->add_network_data = NULL; - g_slice_free (AddNetworkData, add_network_data); + name_owner = g_steal_pointer (&add_network_data->name_owner); + object_path = g_steal_pointer (&add_network_data->object_path); + nm_g_slice_free (add_network_data); - reply = _nm_dbus_proxy_call_finish (proxy, result, - G_VARIANT_TYPE ("(o)"), - &error); + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); if (!assoc_data) { if (!error) { - gs_free char *net_path = NULL; + const char *net_path; /* the assoc-request was already cancelled, but the AddNetwork request succeeded. * Cleanup the created network. * * This cleanup action does not work when NetworkManager is about to exit * and leaves the mainloop. During program shutdown, we may orphan networks. */ - g_variant_get (reply, "(o)", &net_path); - g_dbus_proxy_call (proxy, - "RemoveNetwork", - g_variant_new ("(o)", net_path), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - NULL, - NULL); + g_variant_get (res, "(&o)", &net_path); + g_dbus_connection_call (G_DBUS_CONNECTION (source), + name_owner->str, + object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + "RemoveNetwork", + g_variant_new ("(o)", net_path), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_MSEC, + NULL, + NULL, + NULL); } return; } @@ -2380,44 +2161,50 @@ assoc_add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat return; } - g_variant_get (reply, "(o)", &priv->net_path); + nm_assert (!priv->net_path); + g_variant_get (res, "(o)", &priv->net_path); /* Send blobs first; otherwise jump to selecting the network */ blobs = nm_supplicant_config_get_blobs (priv->assoc_data->cfg); - priv->assoc_data->blobs_left = g_hash_table_size (blobs); + priv->assoc_data->blobs_left = blobs + ? g_hash_table_size (blobs) + : 0u; - _LOGT ("assoc[%p]: network added (%s) (%u blobs left)", priv->assoc_data, priv->net_path, priv->assoc_data->blobs_left); + _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: network added (%s) (%u blobs left)", + NM_HASH_OBFUSCATE_PTR (priv->assoc_data), + priv->net_path, + priv->assoc_data->blobs_left); - if (priv->assoc_data->blobs_left == 0) + if (priv->assoc_data->blobs_left == 0) { assoc_call_select_network (self); - else { - g_hash_table_iter_init (&iter, blobs); - while (g_hash_table_iter_next (&iter, (gpointer) &blob_name, (gpointer) &blob_data)) { - g_dbus_proxy_call (priv->iface_proxy, - "AddBlob", - g_variant_new ("(s@ay)", - blob_name, - nm_utils_gbytes_to_variant_ay (blob_data)), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->assoc_data->cancellable, - (GAsyncReadyCallback) assoc_add_blob_cb, - self); - } + return; + } + + g_hash_table_iter_init (&iter, blobs); + while (g_hash_table_iter_next (&iter, (gpointer) &blob_name, (gpointer) &blob_data)) { + _dbus_connection_call (self, + NM_WPAS_DBUS_IFACE_INTERFACE, + "AddBlob", + g_variant_new ("(s@ay)", + blob_name, + nm_utils_gbytes_to_variant_ay (blob_data)), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_MSEC, + priv->assoc_data->cancellable, + assoc_add_blob_cb, + self); } } static void -assoc_set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +assoc_set_ap_scan_cb (GVariant *ret, GError *error, gpointer user_data) { NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; - gs_unref_variant GVariant *reply = NULL; - gs_free_error GError *error = NULL; AddNetworkData *add_network_data; - reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (nm_utils_error_is_cancelled (error)) return; self = NM_SUPPLICANT_INTERFACE (user_data); @@ -2428,23 +2215,36 @@ assoc_set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_dat return; } - _LOGT ("assoc[%p]: set interface ap_scan to %d", - priv->assoc_data, + _LOGT ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: interface ap_scan set to %d", + NM_HASH_OBFUSCATE_PTR (priv->assoc_data), nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)); - add_network_data = g_slice_new0 (AddNetworkData); + /* the association does not keep @self alive. We want to be able to remove + * the network again, even if @self is already gone. Hence, track the data + * separately. + * + * For that we also have a shutdown_wait_obj so that on exit we still wait + * to handle the response. */ + add_network_data = g_slice_new (AddNetworkData); + *add_network_data = (AddNetworkData) { + .assoc_data = priv->assoc_data, + .name_owner = nm_ref_string_ref (priv->name_owner), + .object_path = nm_ref_string_ref (priv->object_path), + .shutdown_wait_obj = g_object_new (G_TYPE_OBJECT, NULL), + }; + nm_shutdown_wait_obj_register_object (add_network_data->shutdown_wait_obj, "supplicant-add-network"); priv->assoc_data->add_network_data = add_network_data; - add_network_data->assoc_data = priv->assoc_data; - - g_dbus_proxy_call (priv->iface_proxy, - "AddNetwork", - g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->assoc_data->cfg)), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - (GAsyncReadyCallback) assoc_add_network_cb, - add_network_data); + _dbus_connection_call (self, + NM_WPAS_DBUS_IFACE_INTERFACE, + "AddNetwork", + g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->assoc_data->cfg)), + G_VARIANT_TYPE ("(o)"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_MSEC, + NULL, + assoc_add_network_cb, + add_network_data); } static gboolean @@ -2491,61 +2291,64 @@ nm_supplicant_interface_assoc (NMSupplicantInterface *self, nm_supplicant_interface_disconnect (self); - assoc_data = g_slice_new0 (AssocData); - priv->assoc_data = assoc_data; + assoc_data = g_slice_new (AssocData); + *assoc_data = (AssocData) { + .self = self, + .cfg = g_object_ref (cfg), + .callback = callback, + .user_data = user_data, + }; - assoc_data->self = self; - assoc_data->cfg = g_object_ref (cfg); - assoc_data->callback = callback; - assoc_data->user_data = user_data; + priv->assoc_data = assoc_data; - _LOGD ("assoc[%p]: starting association...", assoc_data); + _LOGD ("assoc["NM_HASH_OBFUSCATE_PTR_FMT"]: starting association...", + NM_HASH_OBFUSCATE_PTR (assoc_data)); - /* Make sure the supplicant supports EAP-FAST before trying to send - * it an EAP-FAST configuration. - */ - if ( priv->fast_support == NM_SUPPLICANT_FEATURE_NO + if ( _get_capability (priv, NM_SUPPL_CAP_TYPE_FAST) == NM_TERNARY_FALSE && nm_supplicant_config_fast_required (cfg)) { + /* Make sure the supplicant supports EAP-FAST before trying to send + * it an EAP-FAST configuration. + */ assoc_data->fail_on_idle_id = g_idle_add (assoc_fail_on_idle_cb, self); return; } assoc_data->cancellable = g_cancellable_new(); - g_dbus_proxy_call (priv->iface_proxy, - DBUS_INTERFACE_PROPERTIES ".Set", - g_variant_new ("(ssv)", - WPAS_DBUS_IFACE_INTERFACE, - "ApScan", - g_variant_new_uint32 (nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg))), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->assoc_data->cancellable, - (GAsyncReadyCallback) assoc_set_ap_scan_cb, - self); + nm_dbus_connection_call_set (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + "ApScan", + g_variant_new_uint32 (nm_supplicant_config_get_ap_scan (priv->assoc_data->cfg)), + DBUS_TIMEOUT_MSEC, + assoc_data->cancellable, + assoc_set_ap_scan_cb, + self); } /*****************************************************************************/ static void -scan_request_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +scan_request_cb (GObject *source, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; - gs_unref_variant GVariant *reply = NULL; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; - reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (nm_utils_error_is_cancelled (error)) return; self = NM_SUPPLICANT_INTERFACE (user_data); if (error) { if (_nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.Interface.ScanError")) - _LOGD ("could not get scan request result: %s", error->message); + _LOGD ("request-scan: could not get scan request result: %s", error->message); else { g_dbus_error_strip_remote_error (error); - _LOGW ("could not get scan request result: %s", error->message); + _LOGW ("request-scan: could not get scan request result: %s", error->message); } - } + } else + _LOGT ("request-scan: request scanning success"); } void @@ -2561,7 +2364,8 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self, priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - /* Scan parameters */ + _LOGT ("request-scan: request scanning (%u ssids)...", ssids_len); + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&builder, "{sv}", "Type", g_variant_new_string ("active")); g_variant_builder_add (&builder, "{sv}", "AllowRoam", g_variant_new_boolean (FALSE)); @@ -2577,14 +2381,16 @@ nm_supplicant_interface_request_scan (NMSupplicantInterface *self, g_variant_builder_add (&builder, "{sv}", "SSIDs", g_variant_builder_end (&ssids_builder)); } - g_dbus_proxy_call (priv->iface_proxy, - "Scan", - g_variant_new ("(a{sv})", &builder), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->other_cancellable, - (GAsyncReadyCallback) scan_request_cb, - self); + _dbus_connection_call (self, + NM_WPAS_DBUS_IFACE_INTERFACE, + "Scan", + g_variant_new ("(a{sv})", &builder), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT_MSEC, + priv->main_cancellable, + scan_request_cb, + self); } /*****************************************************************************/ @@ -2597,7 +2403,23 @@ nm_supplicant_interface_get_state (NMSupplicantInterface * self) return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->state; } -const char * +void +_nm_supplicant_interface_set_state_down (NMSupplicantInterface * self, + gboolean force_remove_from_supplicant, + const char *reason) +{ + set_state_down (self, force_remove_from_supplicant, reason); +} + +NMRefString * +nm_supplicant_interface_get_name_owner (NMSupplicantInterface *self) +{ + g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL); + + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->name_owner; +} + +NMRefString * nm_supplicant_interface_get_object_path (NMSupplicantInterface *self) { g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL); @@ -2610,7 +2432,7 @@ nm_supplicant_interface_get_ifname (NMSupplicantInterface *self) { g_return_val_if_fail (NM_IS_SUPPLICANT_INTERFACE (self), NULL); - return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->dev; + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->ifname; } guint @@ -2627,133 +2449,461 @@ void nm_supplicant_interface_p2p_start_find (NMSupplicantInterface *self, guint timeout) { - NMSupplicantInterfacePrivate *priv; GVariantBuilder builder; g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); g_return_if_fail (timeout > 0 && timeout <= 600); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&builder, "{sv}", "Timeout", g_variant_new_int32 (timeout)); - g_dbus_proxy_call (priv->p2p_proxy, - "Find", - g_variant_new ("(a{sv})", &builder), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->other_cancellable, - (GAsyncReadyCallback) log_result_cb, - self); + _dbus_connection_call_simple (self, + NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + "Find", + g_variant_new ("(a{sv})", &builder), + G_VARIANT_TYPE ("()"), + "p2p-find"); } void nm_supplicant_interface_p2p_stop_find (NMSupplicantInterface *self) { - NMSupplicantInterfacePrivate *priv; - g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - g_dbus_proxy_call (priv->p2p_proxy, - "StopFind", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->other_cancellable, - (GAsyncReadyCallback) scan_request_cb, - self); + _dbus_connection_call_simple (self, + NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + "StopFind", + NULL, + G_VARIANT_TYPE ("()"), + "p2p-stop-find"); } /*****************************************************************************/ void -nm_supplicant_interface_p2p_connect (NMSupplicantInterface * self, - const char * peer, - const char * wps_method, - const char * wps_pin) +nm_supplicant_interface_p2p_connect (NMSupplicantInterface *self, + const char *peer, + const char *wps_method, + const char *wps_pin) { - NMSupplicantInterfacePrivate *priv; GVariantBuilder builder; g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - - /* Don't do anything if there is no connection to the supplicant yet. */ - if (!priv->p2p_proxy || !priv->object_path) - return; - - /* Connect parameters */ g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_add (&builder, "{sv}", "wps_method", g_variant_new_string (wps_method)); - if (wps_pin) g_variant_builder_add (&builder, "{sv}", "pin", g_variant_new_string (wps_pin)); - g_variant_builder_add (&builder, "{sv}", "peer", g_variant_new_object_path (peer)); - g_variant_builder_add (&builder, "{sv}", "join", g_variant_new_boolean (FALSE)); g_variant_builder_add (&builder, "{sv}", "persistent", g_variant_new_boolean (FALSE)); g_variant_builder_add (&builder, "{sv}", "go_intent", g_variant_new_int32 (7)); - g_dbus_proxy_call (priv->p2p_proxy, - "Connect", - g_variant_new ("(a{sv})", &builder), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->other_cancellable, - (GAsyncReadyCallback) log_result_cb, - "p2p connect"); + _dbus_connection_call_simple (self, + NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + "Connect", + g_variant_new ("(a{sv})", &builder), + G_VARIANT_TYPE ("()"), + "p2p-connect"); } void nm_supplicant_interface_p2p_cancel_connect (NMSupplicantInterface * self) { - NMSupplicantInterfacePrivate *priv; + g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + + _dbus_connection_call_simple (self, + NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + "Cancel", + NULL, + G_VARIANT_TYPE ("()"), + "p2p-cancel"); +} +void +nm_supplicant_interface_p2p_disconnect (NMSupplicantInterface * self) +{ g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + _dbus_connection_call_simple (self, + NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + "Disconnect", + NULL, + G_VARIANT_TYPE ("()"), + "p2p-disconnect"); +} + +/*****************************************************************************/ + +static void +_properties_changed (NMSupplicantInterface *self, + const char *interface_name, + GVariant *properties, + gboolean initial) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + gboolean is_main; + + nm_assert (!properties || g_variant_is_of_type (properties, G_VARIANT_TYPE ("a{sv}"))); + + if (initial) + priv->starting_pending_count--; + + if ( (initial || priv->is_ready_main) + && nm_streq (interface_name, NM_WPAS_DBUS_IFACE_INTERFACE)) + is_main = TRUE; + else if ( (initial || priv->is_ready_p2p_device) + && nm_streq (interface_name, NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE)) { + nm_assert (_get_capability (priv, NM_SUPPL_CAP_TYPE_P2P) == NM_TERNARY_TRUE); + is_main = FALSE; + } else + return; + + g_object_freeze_notify (G_OBJECT (self)); + + priv->starting_pending_count++; - /* Don't do anything if there is no connection to the supplicant yet. */ - if (!priv->p2p_proxy || !priv->object_path) + if (is_main) { + priv->is_ready_main = TRUE; + _properties_changed_main (self, properties); + } else { + priv->is_ready_p2p_device = TRUE; + _properties_changed_p2p_device (self, properties); + } + + priv->starting_pending_count--; + _starting_check_ready (self); + + _notify_maybe_scanning (self); + _notify_maybe_p2p_available (self); + + g_object_thaw_notify (G_OBJECT (self)); +} + +static void +_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) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + const char *interface_name; + gs_unref_variant GVariant *changed_properties = NULL; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)"))) return; - g_dbus_proxy_call (priv->p2p_proxy, - "Cancel", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->other_cancellable, - (GAsyncReadyCallback) log_result_cb, - "cancel p2p connect"); + g_variant_get (parameters, + "(&s@a{sv}^a&s)", + &interface_name, + &changed_properties, + NULL); + _properties_changed (self, + interface_name, + changed_properties, + FALSE); } -void -nm_supplicant_interface_p2p_disconnect (NMSupplicantInterface * self) +static void +_bss_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) { - NMSupplicantInterfacePrivate *priv; + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + nm_auto_ref_string NMRefString *bss_path = NULL; + gs_unref_variant GVariant *changed_properties = NULL; + NMSupplicantBssInfo *bss_info; - g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (self)); + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)"))) + return; - priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + bss_path = nm_ref_string_new (object_path); - /* Don't do anything if there is no connection to the supplicant. */ - if (!priv->p2p_proxy || !priv->object_path) + bss_info = g_hash_table_lookup (priv->bss_idx, &bss_path); + if (!bss_info) + return; + if (bss_info->_init_cancellable) return; - g_dbus_proxy_call (priv->p2p_proxy, - "Disconnect", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->other_cancellable, - (GAsyncReadyCallback) log_result_cb, - "p2p disconnect"); + g_variant_get (parameters, + "(&s@a{sv}^a&s)", + NULL, + &changed_properties, + NULL); + _bss_info_properties_changed (self, bss_info, changed_properties, FALSE); +} + +static void +_peer_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) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + nm_auto_ref_string NMRefString *peer_path = NULL; + gs_unref_variant GVariant *changed_properties = NULL; + NMSupplicantPeerInfo *peer_info; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)"))) + return; + + peer_path = nm_ref_string_new (object_path); + + peer_info = g_hash_table_lookup (priv->peer_idx, &peer_path); + if (!peer_info) + return; + if (peer_info->_init_cancellable) + return; + + g_variant_get (parameters, + "(&s@a{sv}^a&s)", + NULL, + &changed_properties, + NULL); + _peer_info_properties_changed (self, peer_info, changed_properties, FALSE); +} + +static void +_get_all_main_cb (GVariant *result, + GError *error, + gpointer user_data) +{ + gs_unref_variant GVariant *properties = NULL; + + if (nm_utils_error_is_cancelled (error)) + return; + + if (result) + g_variant_get (result, "(@a{sv})", &properties); + _properties_changed (user_data, + NM_WPAS_DBUS_IFACE_INTERFACE, + properties, + TRUE); +} + +static void +_get_all_p2p_device_cb (GVariant *result, + GError *error, + gpointer user_data) +{ + gs_unref_variant GVariant *properties = NULL; + + if (nm_utils_error_is_cancelled (error)) + return; + + if (result) + g_variant_get (result, "(@a{sv})", &properties); + _properties_changed (user_data, + NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + properties, + TRUE); +} + +static void +_signal_handle (NMSupplicantInterface *self, + const char *signal_interface_name, + const char *signal_name, + GVariant *parameters) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + const char *path; + + if (nm_streq (signal_interface_name, NM_WPAS_DBUS_IFACE_INTERFACE)) { + + if (!priv->is_ready_main) + return; + + if (nm_streq (signal_name, "BSSAdded")) { + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(oa{sv})"))) + return; + + g_variant_get (parameters, "(&oa{sv})", &path, NULL); + _bss_info_add (self, path); + return; + } + + if (nm_streq (signal_name, "BSSRemoved")) { + nm_auto_ref_string NMRefString *bss_path = NULL; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) + return; + + g_variant_get (parameters, "(&o)", &path); + bss_path = nm_ref_string_new (path); + _bss_info_remove (self, &bss_path); + return; + } + + if (nm_streq (signal_name, "EAP")) { + NMSupplicantAuthState auth_state = NM_SUPPLICANT_AUTH_STATE_UNKNOWN; + const char *status; + const char *parameter; + + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(ss)"))) + return; + + g_variant_get (parameters, "(&s&s)", &status, ¶meter); + + if (nm_streq (status, "started")) + auth_state = NM_SUPPLICANT_AUTH_STATE_STARTED; + else if (nm_streq (status, "completion")) { + if (nm_streq (parameter, "success")) + auth_state = NM_SUPPLICANT_AUTH_STATE_SUCCESS; + else if (nm_streq (parameter, "failure")) + auth_state = NM_SUPPLICANT_AUTH_STATE_FAILURE; + } + + /* the state eventually reaches one of started, success or failure + * so ignore any other intermediate (unknown) state change. */ + if ( auth_state != NM_SUPPLICANT_AUTH_STATE_UNKNOWN + && auth_state != priv->auth_state) { + priv->auth_state = auth_state; + _notify (self, PROP_AUTH_STATE); + } + return; + } + + return; + } + + if (nm_streq (signal_interface_name, NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE)) { + + if (!priv->is_ready_p2p_device) + return; + + if (nm_streq (signal_name, "DeviceFound")) { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) { + g_variant_get (parameters, "(&o)", &path); + _peer_info_add (self, path); + } + return; + } + + if (nm_streq (signal_name, "DeviceLost")) { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) { + nm_auto_ref_string NMRefString *peer_path = NULL; + + g_variant_get (parameters, "(&o)", &path); + peer_path = nm_ref_string_new (path); + _peer_info_remove (self, &peer_path); + } + return; + } + + if (nm_streq (signal_name, "GroupStarted")) { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) { + gs_unref_variant GVariant *args = NULL; + gs_unref_object NMSupplicantInterface *iface = NULL; + const char *group_path; + const char *iface_path; + + g_variant_get (parameters, "(@a{sv})", &args); + if (!g_variant_lookup (args, "group_object", "&o", &group_path)) + return; + if (!g_variant_lookup (args, "interface_object", "&o", &iface_path)) + return; + + if (nm_streq (iface_path, priv->object_path->str)) { + _LOGW ("P2P: GroupStarted on existing interface"); + iface = g_object_ref (self); + } else { + iface = nm_supplicant_manager_create_interface_from_path (priv->supplicant_manager, + iface_path); + if (iface == NULL) { + _LOGW ("P2P: Group interface already exists in GroupStarted handler, aborting further processing."); + return; + } + } + + /* Signal existence of the (new) interface. */ + g_signal_emit (self, signals[GROUP_STARTED], 0, iface); + } + return; + } + + if (nm_streq (signal_name, "GroupFinished")) { + if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) { + gs_unref_variant GVariant *args = NULL; + const char *iface_path; + + g_variant_get (parameters, "(@a{sv})", &args); + + /* TODO: Group finished is called on the management interface! + * This means the signal consumer will currently need to assume which + * interface is finishing or it needs to match the object paths. + */ + if (!g_variant_lookup (args, "interface_object", "&o", &iface_path)) + return; + + _LOGD ("P2P: GroupFinished signal on interface %s for interface %s", priv->object_path->str, iface_path); + + /* Signal group finish interface (on management interface). */ + g_signal_emit (self, signals[GROUP_FINISHED], 0, iface_path); + } + return; + } + + return; + } +} + +static void +_signal_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) +{ + NMSupplicantInterface *self = user_data; + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + priv->starting_pending_count++; + _signal_handle (self, signal_interface_name, signal_name, parameters); + priv->starting_pending_count--; + _starting_check_ready (self); + + _notify_maybe_scanning (self); +} + +/*****************************************************************************/ + +gboolean +nm_supplicant_interface_get_p2p_available (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_capable_cached; +} + +gboolean +nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_group_joined_cached; +} + +const char* +nm_supplicant_interface_get_p2p_group_path (NMSupplicantInterface *self) +{ + return nm_ref_string_get_str (NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_group_path); +} + +gboolean +nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->p2p_group_owner_cached; } /*****************************************************************************/ @@ -2764,26 +2914,27 @@ get_property (GObject *object, GValue *value, GParamSpec *pspec) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE ((NMSupplicantInterface *) object); + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); switch (prop_id) { case PROP_SCANNING: - g_value_set_boolean (value, priv->scanning); + g_value_set_boolean (value, nm_supplicant_interface_get_scanning (self)); break; case PROP_CURRENT_BSS: - g_value_set_string (value, priv->current_bss); + g_value_set_string (value, nm_ref_string_get_str (nm_supplicant_interface_get_current_bss (self))); break; case PROP_P2P_GROUP_JOINED: - g_value_set_boolean (value, priv->p2p_capable && priv->group_proxy_acquired); + g_value_set_boolean (value, nm_supplicant_interface_get_p2p_group_joined (self)); break; case PROP_P2P_GROUP_PATH: - g_value_set_string (value, nm_supplicant_interface_get_p2p_group_path (NM_SUPPLICANT_INTERFACE (object))); + g_value_set_string (value, nm_supplicant_interface_get_p2p_group_path (self)); break; case PROP_P2P_GROUP_OWNER: - g_value_set_boolean (value, priv->p2p_group_owner); + g_value_set_boolean (value, nm_supplicant_interface_get_p2p_group_owner (self)); break; case PROP_P2P_AVAILABLE: - g_value_set_boolean (value, priv->p2p_capable && priv->p2p_proxy_acquired); + g_value_set_boolean (value, nm_supplicant_interface_get_p2p_available (self)); break; case PROP_AUTH_STATE: g_value_set_uint (value, priv->auth_state); @@ -2800,56 +2951,34 @@ set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE ((NMSupplicantInterface *) object); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object); switch (prop_id) { - case PROP_IFACE: + case PROP_SUPPLICANT_MANAGER: /* construct-only */ - priv->dev = g_value_dup_string (value); - break; - case PROP_OBJECT_PATH: - /* construct-only */ - priv->object_path = g_value_dup_string (value); - break; - case PROP_DRIVER: - /* construct-only */ - priv->driver = g_value_get_uint (value); - break; - case PROP_FAST_SUPPORT: - /* construct-only */ - priv->fast_support = g_value_get_int (value); - break; - case PROP_AP_SUPPORT: - /* construct-only */ - priv->ap_support = g_value_get_int (value); - break; - case PROP_PMF_SUPPORT: - /* construct-only */ - priv->pmf_support = g_value_get_int (value); - break; - case PROP_FILS_SUPPORT: - /* construct-only */ - priv->fils_support = g_value_get_int (value); - break; - case PROP_P2P_SUPPORT: - /* construct-only */ - priv->p2p_support = g_value_get_int (value); - break; - case PROP_MESH_SUPPORT: - /* construct-only */ - priv->mesh_support = g_value_get_int (value); + priv->supplicant_manager = g_object_ref (g_value_get_pointer (value)); + nm_assert (NM_IS_SUPPLICANT_MANAGER (priv->supplicant_manager)); + + priv->dbus_connection = g_object_ref (nm_supplicant_manager_get_dbus_connection (priv->supplicant_manager)); + nm_assert (G_IS_DBUS_CONNECTION (priv->dbus_connection)); + + priv->name_owner = nm_ref_string_ref (nm_supplicant_manager_get_dbus_name_owner (priv->supplicant_manager)); + nm_assert (NM_IS_REF_STRING (priv->name_owner)); + + priv->global_capabilities = nm_supplicant_manager_get_global_capabilities (priv->supplicant_manager); break; - case PROP_WFD_SUPPORT: + case PROP_DBUS_OBJECT_PATH: /* construct-only */ - priv->wfd_support = g_value_get_int (value); + priv->object_path = nm_ref_string_ref (g_value_get_pointer (value)); + nm_assert (NM_IS_REF_STRING (priv->object_path)); break; - case PROP_FT_SUPPORT: + case PROP_IFINDEX: /* construct-only */ - priv->ft_support_global = g_value_get_int (value); + priv->ifindex = g_value_get_int (value); break; - case PROP_SHA384_SUPPORT: + case PROP_DRIVER: /* construct-only */ - priv->sha384_support = g_value_get_int (value); + priv->requested_driver = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2857,47 +2986,179 @@ set_property (GObject *object, } } +/*****************************************************************************/ + static void nm_supplicant_interface_init (NMSupplicantInterface * self) { + NMSupplicantInterfacePrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfacePrivate); + + self->_priv = priv; + + nm_assert (priv->global_capabilities == NM_SUPPL_CAP_MASK_NONE); + nm_assert (priv->iface_capabilities == NM_SUPPL_CAP_MASK_NONE); + + priv->state = NM_SUPPLICANT_INTERFACE_STATE_STARTING; + priv->supp_state = NM_SUPPLICANT_INTERFACE_STATE_INVALID; + priv->last_scan_msec = -1; + + c_list_init (&self->supp_lst); + + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMSupplicantBssInfo, bss_path) == 0); + priv->bss_idx = g_hash_table_new (nm_pdirect_hash, nm_pdirect_equal); + + c_list_init (&priv->bss_lst_head); + c_list_init (&priv->bss_initializing_lst_head); + + G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMSupplicantPeerInfo, peer_path) == 0); + priv->peer_idx = g_hash_table_new (nm_pdirect_hash, nm_pdirect_equal); + + c_list_init (&priv->peer_lst_head); + c_list_init (&priv->peer_initializing_lst_head); + + priv->main_cancellable = g_cancellable_new (); +} + +static void +constructed (GObject *object) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - priv->state = NM_SUPPLICANT_INTERFACE_STATE_INIT; - priv->bss_proxies = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, bss_data_destroy); - priv->peer_proxies = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, peer_data_destroy); + G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->constructed (object); + + _LOGD ("new supplicant interface %s on %s", + priv->object_path->str, + priv->name_owner->str); + + priv->properties_changed_id = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NULL, + _properties_changed_cb, + self, + NULL); + + priv->bss_properties_changed_id = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection, + priv->name_owner->str, + NULL, + NM_WPAS_DBUS_IFACE_BSS, + _bss_properties_changed_cb, + self, + NULL); + + priv->signal_id = g_dbus_connection_signal_subscribe (priv->dbus_connection, + priv->name_owner->str, + NULL, + NULL, + priv->object_path->str, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + _signal_cb, + self, + NULL); + + /* Scan result aging parameters */ + nm_dbus_connection_call_set (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + "BSSExpireAge", + g_variant_new_uint32 (250), + DBUS_TIMEOUT_MSEC, + NULL, + NULL, + NULL); + nm_dbus_connection_call_set (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + "BSSExpireCount", + g_variant_new_uint32 (2), + DBUS_TIMEOUT_MSEC, + NULL, + NULL, + NULL); + + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_PMF) == NM_TERNARY_TRUE) { + /* Initialize global PMF setting to 'optional' */ + nm_dbus_connection_call_set (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + "Pmf", + g_variant_new_string ("1"), + DBUS_TIMEOUT_MSEC, + NULL, + NULL, + NULL); + } + + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_AP) == NM_TERNARY_DEFAULT) { + /* If the global supplicant capabilities property is not present, we can + * fall back to checking whether the ProbeRequest method is supported. If + * neither of these works we have no way of determining if AP mode is + * supported or not. hostap 1.0 and earlier don't support either of these. + */ + priv->starting_pending_count++; + _dbus_connection_call (self, + DBUS_INTERFACE_INTROSPECTABLE, + "Introspect", + NULL, + G_VARIANT_TYPE ("(s)"), + G_DBUS_CALL_FLAGS_NONE, + 5000, + priv->main_cancellable, + iface_introspect_cb, + self); + } + + priv->starting_pending_count++; + nm_dbus_connection_call_get_all (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE, + 5000, + priv->main_cancellable, + _get_all_main_cb, + self); + + if (_get_capability (priv, NM_SUPPL_CAP_TYPE_P2P) == NM_TERNARY_TRUE) { + priv->peer_properties_changed_id = nm_dbus_connection_signal_subscribe_properties_changed (priv->dbus_connection, + priv->name_owner->str, + NULL, + NM_WPAS_DBUS_IFACE_PEER, + _peer_properties_changed_cb, + self, + NULL); + + priv->starting_pending_count++; + nm_dbus_connection_call_get_all (priv->dbus_connection, + priv->name_owner->str, + priv->object_path->str, + NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE, + 5000, + priv->main_cancellable, + _get_all_p2p_device_cb, + self); + } } NMSupplicantInterface * -nm_supplicant_interface_new (const char *ifname, - const char *object_path, - NMSupplicantDriver driver, - NMSupplicantFeature fast_support, - NMSupplicantFeature ap_support, - NMSupplicantFeature pmf_support, - NMSupplicantFeature fils_support, - NMSupplicantFeature p2p_support, - NMSupplicantFeature mesh_support, - NMSupplicantFeature wfd_support, - NMSupplicantFeature ft_support, - NMSupplicantFeature sha384_support) -{ - /* One of ifname or path need to be set */ - g_return_val_if_fail (ifname != NULL || object_path != NULL, NULL); - g_return_val_if_fail (ifname == NULL || object_path == NULL, NULL); +nm_supplicant_interface_new (NMSupplicantManager *supplicant_manager, + NMRefString *object_path, + int ifindex, + NMSupplicantDriver driver) +{ + nm_assert (NM_IS_SUPPLICANT_MANAGER (supplicant_manager)); return g_object_new (NM_TYPE_SUPPLICANT_INTERFACE, - NM_SUPPLICANT_INTERFACE_IFACE, ifname, - NM_SUPPLICANT_INTERFACE_OBJECT_PATH, object_path, + NM_SUPPLICANT_INTERFACE_SUPPLICANT_MANAGER, supplicant_manager, + NM_SUPPLICANT_INTERFACE_DBUS_OBJECT_PATH, object_path, + NM_SUPPLICANT_INTERFACE_IFINDEX, ifindex, NM_SUPPLICANT_INTERFACE_DRIVER, (guint) driver, - NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, (int) fast_support, - NM_SUPPLICANT_INTERFACE_AP_SUPPORT, (int) ap_support, - NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, (int) pmf_support, - NM_SUPPLICANT_INTERFACE_FILS_SUPPORT, (int) fils_support, - NM_SUPPLICANT_INTERFACE_P2P_SUPPORT, (int) p2p_support, - NM_SUPPLICANT_INTERFACE_MESH_SUPPORT, (int) mesh_support, - NM_SUPPLICANT_INTERFACE_WFD_SUPPORT, (int) wfd_support, - NM_SUPPLICANT_INTERFACE_FT_SUPPORT, (int) ft_support, - NM_SUPPLICANT_INTERFACE_SHA384_SUPPORT, (int) sha384_support, NULL); } @@ -2907,7 +3168,11 @@ dispose (GObject *object) NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (object); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - nm_supplicant_interface_cancel_wps (self); + if (priv->state != NM_SUPPLICANT_INTERFACE_STATE_DOWN) + set_state_down (self, TRUE, "NMSupplicantInterface is disposing"); + + nm_assert (c_list_is_empty (&self->supp_lst)); + if (priv->wps_data) { /* we shut down, but an asynchronous Cancel request is pending. * We don't want to cancel it, so mark wps-data that @self is gone. @@ -2917,38 +3182,21 @@ dispose (GObject *object) priv->wps_data = NULL; } - if (priv->assoc_data) { - gs_free_error GError *error = NULL; - - nm_utils_error_set_cancelled (&error, TRUE, "NMSupplicantInterface"); - assoc_return (self, error, "cancelled due to dispose of supplicant interface"); - } - - if (priv->iface_proxy) - g_signal_handlers_disconnect_by_data (priv->iface_proxy, object); - g_clear_object (&priv->iface_proxy); - if (priv->p2p_proxy) - g_signal_handlers_disconnect_by_data (priv->p2p_proxy, object); - g_clear_object (&priv->p2p_proxy); - if (priv->group_proxy) - g_signal_handlers_disconnect_by_data (priv->group_proxy, object); - g_clear_object (&priv->group_proxy); + nm_assert (!priv->assoc_data); - nm_clear_g_cancellable (&priv->init_cancellable); - nm_clear_g_cancellable (&priv->other_cancellable); + nm_clear_pointer (&priv->bss_idx, g_hash_table_destroy); + nm_clear_pointer (&priv->peer_idx, g_hash_table_destroy); - if (priv->wpas_proxy) - g_signal_handlers_disconnect_by_data (priv->wpas_proxy, object); - g_clear_object (&priv->wpas_proxy); - g_clear_pointer (&priv->bss_proxies, g_hash_table_destroy); - g_clear_pointer (&priv->peer_proxies, g_hash_table_destroy); - - g_clear_pointer (&priv->net_path, g_free); - g_clear_pointer (&priv->dev, g_free); - g_clear_pointer (&priv->object_path, g_free); - g_clear_pointer (&priv->current_bss, g_free); + nm_clear_pointer (&priv->current_bss, nm_ref_string_unref); G_OBJECT_CLASS (nm_supplicant_interface_parent_class)->dispose (object); + + nm_clear_pointer (&priv->object_path, nm_ref_string_unref); + nm_clear_pointer (&priv->name_owner, nm_ref_string_unref); + g_clear_object (&priv->supplicant_manager); + g_clear_object (&priv->dbus_connection); + nm_clear_g_free (&priv->ifname); + nm_assert (!priv->net_path); } static void @@ -2956,10 +3204,36 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->dispose = dispose; + g_type_class_add_private (object_class, sizeof (NMSupplicantInterfacePrivate)); + + object_class->constructed = constructed; + object_class->dispose = dispose; object_class->set_property = set_property; object_class->get_property = get_property; + obj_properties[PROP_SUPPLICANT_MANAGER] = + g_param_spec_pointer (NM_SUPPLICANT_INTERFACE_SUPPLICANT_MANAGER, "", "", + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DBUS_OBJECT_PATH] = + g_param_spec_pointer (NM_SUPPLICANT_INTERFACE_DBUS_OBJECT_PATH, "", "", + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_IFINDEX] = + g_param_spec_int (NM_SUPPLICANT_INTERFACE_IFINDEX, "", "", + 0, G_MAXINT, 0, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DRIVER] = + g_param_spec_uint (NM_SUPPLICANT_INTERFACE_DRIVER, "", "", + 0, G_MAXUINT, NM_SUPPLICANT_DRIVER_WIRELESS, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_SCANNING] = g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_SCANNING, "", "", FALSE, @@ -2970,18 +3244,6 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFACE] = - g_param_spec_string (NM_SUPPLICANT_INTERFACE_IFACE, "", "", - NULL, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_OBJECT_PATH] = - g_param_spec_string (NM_SUPPLICANT_INTERFACE_OBJECT_PATH, "", "", - NULL, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); obj_properties[PROP_P2P_GROUP_JOINED] = g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED, "", "", FALSE, @@ -2997,89 +3259,11 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_DRIVER] = - g_param_spec_uint (NM_SUPPLICANT_INTERFACE_DRIVER, "", "", - 0, G_MAXUINT, NM_SUPPLICANT_DRIVER_WIRELESS, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); obj_properties[PROP_P2P_AVAILABLE] = g_param_spec_boolean (NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE, "", "", FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FAST_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_FAST_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_AP_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_AP_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_PMF_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_PMF_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FILS_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_FILS_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_P2P_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_P2P_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_MESH_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_MESH_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_WFD_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_WFD_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_FT_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_FT_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - obj_properties[PROP_SHA384_SUPPORT] = - g_param_spec_int (NM_SUPPLICANT_INTERFACE_SHA384_SUPPORT, "", "", - NM_SUPPLICANT_FEATURE_UNKNOWN, - NM_SUPPLICANT_FEATURE_YES, - NM_SUPPLICANT_FEATURE_UNKNOWN, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); obj_properties[PROP_AUTH_STATE] = g_param_spec_uint (NM_SUPPLICANT_INTERFACE_AUTH_STATE, "", "", NM_SUPPLICANT_AUTH_STATE_UNKNOWN, @@ -3098,61 +3282,21 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_INT, G_TYPE_INT); - signals[REMOVED] = - g_signal_new (NM_SUPPLICANT_INTERFACE_REMOVED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 0); - - signals[BSS_UPDATED] = - g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_UPDATED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VARIANT); - - signals[BSS_REMOVED] = - g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_REMOVED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_STRING); - - signals[PEER_UPDATED] = - g_signal_new (NM_SUPPLICANT_INTERFACE_PEER_UPDATED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VARIANT); - - signals[PEER_REMOVED] = - g_signal_new (NM_SUPPLICANT_INTERFACE_PEER_REMOVED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_STRING); - - signals[SCAN_DONE] = - g_signal_new (NM_SUPPLICANT_INTERFACE_SCAN_DONE, + signals[BSS_CHANGED] = + g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_BOOLEAN); + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN); - signals[CREDENTIALS_REQUEST] = - g_signal_new (NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST, + signals[PEER_CHANGED] = + g_signal_new (NM_SUPPLICANT_INTERFACE_PEER_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_BOOLEAN); signals[WPS_CREDENTIALS] = g_signal_new (NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS, @@ -3177,12 +3321,4 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); - - signals[GROUP_FORMATION_FAILURE] = - g_signal_new (NM_SUPPLICANT_INTERFACE_GROUP_FORMATION_FAILURE, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_STRING); } diff --git a/src/supplicant/nm-supplicant-interface.h b/src/supplicant/nm-supplicant-interface.h index 3580f754..eb414f26 100644 --- a/src/supplicant/nm-supplicant-interface.h +++ b/src/supplicant/nm-supplicant-interface.h @@ -9,15 +9,17 @@ #include "nm-supplicant-types.h" +#include "c-list/src/c-list.h" + /* * Supplicant interface states * A mix of wpa_supplicant interface states and internal states. */ typedef enum { - NM_SUPPLICANT_INTERFACE_STATE_INVALID = -1, - NM_SUPPLICANT_INTERFACE_STATE_INIT = 0, - NM_SUPPLICANT_INTERFACE_STATE_STARTING, - NM_SUPPLICANT_INTERFACE_STATE_READY, + NM_SUPPLICANT_INTERFACE_STATE_INVALID = 0, + + NM_SUPPLICANT_INTERFACE_STATE_STARTING = 1, + NM_SUPPLICANT_INTERFACE_STATE_DISABLED, NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, NM_SUPPLICANT_INTERFACE_STATE_INACTIVE, @@ -28,9 +30,24 @@ typedef enum { NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE, NM_SUPPLICANT_INTERFACE_STATE_GROUP_HANDSHAKE, NM_SUPPLICANT_INTERFACE_STATE_COMPLETED, + NM_SUPPLICANT_INTERFACE_STATE_DOWN, } NMSupplicantInterfaceState; +static inline gboolean +nm_supplicant_interface_state_is_operational (NMSupplicantInterfaceState state) +{ + return state > NM_SUPPLICANT_INTERFACE_STATE_STARTING + && state < NM_SUPPLICANT_INTERFACE_STATE_DOWN; +} + +static inline gboolean +nm_supplicant_interface_state_is_associated (NMSupplicantInterfaceState state) +{ + return state >= NM_SUPPLICANT_INTERFACE_STATE_AUTHENTICATING + && state <= NM_SUPPLICANT_INTERFACE_STATE_COMPLETED; +} + typedef enum { NM_SUPPLICANT_AUTH_STATE_UNKNOWN, NM_SUPPLICANT_AUTH_STATE_STARTED, @@ -46,60 +63,48 @@ typedef enum { #define NM_IS_SUPPLICANT_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SUPPLICANT_INTERFACE)) #define NM_SUPPLICANT_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass)) -/* Properties */ -#define NM_SUPPLICANT_INTERFACE_IFACE "iface" -#define NM_SUPPLICANT_INTERFACE_OBJECT_PATH "object-path" -#define NM_SUPPLICANT_INTERFACE_SCANNING "scanning" -#define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss" -#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED "p2p-group-joined" -#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_PATH "p2p-group-path" -#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_OWNER "p2p-group-owner" -#define NM_SUPPLICANT_INTERFACE_DRIVER "driver" -#define NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE "p2p-available" -#define NM_SUPPLICANT_INTERFACE_FAST_SUPPORT "fast-support" -#define NM_SUPPLICANT_INTERFACE_AP_SUPPORT "ap-support" -#define NM_SUPPLICANT_INTERFACE_PMF_SUPPORT "pmf-support" -#define NM_SUPPLICANT_INTERFACE_FILS_SUPPORT "fils-support" -#define NM_SUPPLICANT_INTERFACE_P2P_SUPPORT "p2p-support" -#define NM_SUPPLICANT_INTERFACE_MESH_SUPPORT "mesh-support" -#define NM_SUPPLICANT_INTERFACE_WFD_SUPPORT "wfd-support" -#define NM_SUPPLICANT_INTERFACE_FT_SUPPORT "ft-support" -#define NM_SUPPLICANT_INTERFACE_SHA384_SUPPORT "sha384-support" -#define NM_SUPPLICANT_INTERFACE_AUTH_STATE "auth-state" - -/* Signals */ -#define NM_SUPPLICANT_INTERFACE_STATE "state" -#define NM_SUPPLICANT_INTERFACE_REMOVED "removed" -#define NM_SUPPLICANT_INTERFACE_BSS_UPDATED "bss-updated" -#define NM_SUPPLICANT_INTERFACE_BSS_REMOVED "bss-removed" -#define NM_SUPPLICANT_INTERFACE_PEER_UPDATED "peer-updated" -#define NM_SUPPLICANT_INTERFACE_PEER_REMOVED "peer-removed" -#define NM_SUPPLICANT_INTERFACE_SCAN_DONE "scan-done" -#define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request" -#define NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS "wps-credentials" +#define NM_SUPPLICANT_INTERFACE_SUPPLICANT_MANAGER "supplicant-manager" +#define NM_SUPPLICANT_INTERFACE_DBUS_OBJECT_PATH "dbus-object-path" +#define NM_SUPPLICANT_INTERFACE_IFINDEX "ifindex" +#define NM_SUPPLICANT_INTERFACE_SCANNING "scanning" +#define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss" +#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_JOINED "p2p-group-joined" +#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_PATH "p2p-group-path" +#define NM_SUPPLICANT_INTERFACE_P2P_GROUP_OWNER "p2p-group-owner" +#define NM_SUPPLICANT_INTERFACE_DRIVER "driver" +#define NM_SUPPLICANT_INTERFACE_P2P_AVAILABLE "p2p-available" +#define NM_SUPPLICANT_INTERFACE_AUTH_STATE "auth-state" + +#define NM_SUPPLICANT_INTERFACE_STATE "state" +#define NM_SUPPLICANT_INTERFACE_BSS_CHANGED "bss-changed" +#define NM_SUPPLICANT_INTERFACE_PEER_CHANGED "peer-changed" +#define NM_SUPPLICANT_INTERFACE_WPS_CREDENTIALS "wps-credentials" #define NM_SUPPLICANT_INTERFACE_GROUP_STARTED "group-started" #define NM_SUPPLICANT_INTERFACE_GROUP_FINISHED "group-finished" -#define NM_SUPPLICANT_INTERFACE_GROUP_FORMATION_FAILURE "group-formation-failure" typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass; +struct _NMSupplicantInterfacePrivate; + +struct _NMSupplicantInterface { + GObject parent; + CList supp_lst; + struct _NMSupplicantInterfacePrivate *_priv; +}; + GType nm_supplicant_interface_get_type (void); -NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, - const char *object_path, - NMSupplicantDriver driver, - NMSupplicantFeature fast_support, - NMSupplicantFeature ap_support, - NMSupplicantFeature pmf_support, - NMSupplicantFeature fils_support, - NMSupplicantFeature p2p_support, - NMSupplicantFeature mesh_support, - NMSupplicantFeature wfd_support, - NMSupplicantFeature ft_support, - NMSupplicantFeature sha384_support); - -void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self, - gboolean available); +NMSupplicantInterface *nm_supplicant_interface_new (NMSupplicantManager *supplicant_manager, + NMRefString *object_path, + int ifindex, + NMSupplicantDriver driver); + +NMRefString *nm_supplicant_interface_get_name_owner (NMSupplicantInterface *self); +NMRefString *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface); + +void _nm_supplicant_interface_set_state_down (NMSupplicantInterface * self, + gboolean force_remove_from_supplicant, + const char *reason); typedef void (*NMSupplicantInterfaceAssocCb) (NMSupplicantInterface *iface, GError *error, @@ -123,8 +128,6 @@ nm_supplicant_interface_disconnect_async (NMSupplicantInterface * self, NMSupplicantInterfaceDisconnectCb callback, gpointer user_data); -const char *nm_supplicant_interface_get_object_path (NMSupplicantInterface * iface); - void nm_supplicant_interface_request_scan (NMSupplicantInterface *self, GBytes *const*ssids, guint ssids_len); @@ -135,7 +138,7 @@ const char *nm_supplicant_interface_state_to_string (NMSupplicantInterfaceState gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self); -const char *nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self); +NMRefString *nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self); gint64 nm_supplicant_interface_get_last_scan (NMSupplicantInterface *self); @@ -143,7 +146,7 @@ const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self); guint nm_supplicant_interface_get_max_scan_ssids (NMSupplicantInterface *self); -gboolean nm_supplicant_interface_get_has_credentials_request (NMSupplicantInterface *self); +gboolean nm_supplicant_interface_get_p2p_available (NMSupplicantInterface *self); gboolean nm_supplicant_interface_get_p2p_group_joined (NMSupplicantInterface *self); @@ -151,11 +154,6 @@ const char* nm_supplicant_interface_get_p2p_group_path (NMSupplicantInterface *s gboolean nm_supplicant_interface_get_p2p_group_owner (NMSupplicantInterface *self); -gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, - const char *field, - const char *value, - GError **error); - void nm_supplicant_interface_p2p_start_find (NMSupplicantInterface *self, guint timeout); void nm_supplicant_interface_p2p_stop_find (NMSupplicantInterface *self); @@ -167,41 +165,13 @@ void nm_supplicant_interface_p2p_connect (NMSupplicantInterface * self, void nm_supplicant_interface_p2p_cancel_connect (NMSupplicantInterface * self); void nm_supplicant_interface_p2p_disconnect (NMSupplicantInterface * self); -NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self); -NMSupplicantFeature nm_supplicant_interface_get_pmf_support (NMSupplicantInterface *self); -NMSupplicantFeature nm_supplicant_interface_get_fils_support (NMSupplicantInterface *self); -NMSupplicantFeature nm_supplicant_interface_get_p2p_support (NMSupplicantInterface *self); -NMSupplicantFeature nm_supplicant_interface_get_mesh_support (NMSupplicantInterface *self); -NMSupplicantFeature nm_supplicant_interface_get_wfd_support (NMSupplicantInterface *self); -NMSupplicantFeature nm_supplicant_interface_get_ft_support (NMSupplicantInterface *self); -NMSupplicantFeature nm_supplicant_interface_get_sha384_support (NMSupplicantInterface *self); - -void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, - NMSupplicantFeature apmode); - -void nm_supplicant_interface_set_fast_support (NMSupplicantInterface *self, - NMSupplicantFeature fast_support); - -void nm_supplicant_interface_set_pmf_support (NMSupplicantInterface *self, - NMSupplicantFeature pmf_support); - -void nm_supplicant_interface_set_fils_support (NMSupplicantInterface *self, - NMSupplicantFeature fils_support); - -void nm_supplicant_interface_set_p2p_support (NMSupplicantInterface *self, - NMSupplicantFeature p2p_support); - -void nm_supplicant_interface_set_mesh_support (NMSupplicantInterface *self, - NMSupplicantFeature mesh_support); - -void nm_supplicant_interface_set_wfd_support (NMSupplicantInterface *self, - NMSupplicantFeature wfd_support); +void nm_supplicant_interface_set_global_capabilities (NMSupplicantInterface *self, + NMSupplCapMask value); -void nm_supplicant_interface_set_ft_support (NMSupplicantInterface *self, - NMSupplicantFeature ft_support); +NMTernary nm_supplicant_interface_get_capability (NMSupplicantInterface *self, + NMSupplCapType type); -void nm_supplicant_interface_set_sha384_support (NMSupplicantInterface *self, - NMSupplicantFeature sha384_support); +NMSupplCapMask nm_supplicant_interface_get_capabilities (NMSupplicantInterface *self); void nm_supplicant_interface_enroll_wps (NMSupplicantInterface *self, const char *const type, diff --git a/src/supplicant/nm-supplicant-manager.c b/src/supplicant/nm-supplicant-manager.c index 49581f6e..cf5cf111 100644 --- a/src/supplicant/nm-supplicant-manager.c +++ b/src/supplicant/nm-supplicant-manager.c @@ -8,29 +8,64 @@ #include "nm-supplicant-manager.h" +#include "nm-core-internal.h" +#include "nm-dbus-manager.h" +#include "nm-glib-aux/nm-dbus-aux.h" +#include "nm-glib-aux/nm-ref-string.h" #include "nm-supplicant-interface.h" #include "nm-supplicant-types.h" -#include "nm-core-internal.h" +#include "platform/nm-platform.h" /*****************************************************************************/ +#define CREATE_IFACE_TRY_COUNT_MAX 7u + +struct _NMSupplMgrCreateIfaceHandle { + NMSupplicantManager *self; + CList create_iface_lst; + GCancellable *cancellable; + NMSupplicantManagerCreateInterfaceCb callback; + gpointer callback_user_data; + NMShutdownWaitObjHandle *shutdown_handle; + NMRefString *name_owner; + GError *fail_on_idle_error; + NMSupplicantDriver driver; + int ifindex; + guint fail_on_idle_id; + guint create_iface_try_count:5; +}; + +enum { + AVAILABLE_CHANGED, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + typedef struct { - GDBusProxy * proxy; - GCancellable * cancellable; - gboolean running; - - GSList *ifaces; - NMSupplicantFeature fast_support; - NMSupplicantFeature ap_support; - NMSupplicantFeature pmf_support; - NMSupplicantFeature fils_support; - NMSupplicantFeature p2p_support; - NMSupplicantFeature mesh_support; - NMSupplicantFeature wfd_support; - NMSupplicantFeature ft_support; - NMSupplicantFeature sha384_support; - guint die_count_reset_id; - guint die_count; + GDBusConnection *dbus_connection; + + NMRefString *name_owner; + + GCancellable *get_name_owner_cancellable; + GCancellable *get_capabilities_cancellable; + GCancellable *poke_name_owner_cancellable; + + GHashTable *supp_ifaces; + CList supp_lst_head; + + CList create_iface_lst_head; + + NMSupplCapMask capabilities; + + guint name_owner_changed_id; + guint interface_removed_id; + guint poke_name_owner_timeout_id; + guint available_reset_id; + + /* see nm_supplicant_manager_get_available(). */ + NMTernary available:2; + } NMSupplicantManagerPrivate; struct _NMSupplicantManager { @@ -46,6 +81,8 @@ G_DEFINE_TYPE (NMSupplicantManager, nm_supplicant_manager, G_TYPE_OBJECT) #define NM_SUPPLICANT_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSupplicantManager, NM_IS_SUPPLICANT_MANAGER) +NM_DEFINE_SINGLETON_GETTER (NMSupplicantManager, nm_supplicant_manager_get, NM_TYPE_SUPPLICANT_MANAGER); + /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_SUPPLICANT @@ -57,72 +94,140 @@ NM_CACHED_QUARK_FCN ("nm-supplicant-error-quark", nm_supplicant_error_quark) /*****************************************************************************/ -static gboolean -die_count_exceeded (guint32 count) +static void _create_iface_proceed_all (NMSupplicantManager *self, + GError *error); +static void _supp_iface_add (NMSupplicantManager *self, + NMRefString *iface_path, + NMSupplicantInterface *supp_iface); +static void _supp_iface_remove_one (NMSupplicantManager *self, + NMSupplicantInterface *supp_iface, + gboolean force_remove_from_supplicant, + const char *reason); +static void _create_iface_dbus_call_get_interface (NMSupplicantManager *self, + NMSupplMgrCreateIfaceHandle *handle, + const char *ifname); +static void _create_iface_dbus_call_create_interface (NMSupplicantManager *self, + NMSupplMgrCreateIfaceHandle *handle, + const char *ifname); +static gboolean _create_iface_fail_on_idle_cb (gpointer user_data); + +static gboolean _available_reset_cb (gpointer user_data); + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE (nm_supplicant_driver_to_string, NMSupplicantDriver, + NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), + NM_UTILS_LOOKUP_ITEM (NM_SUPPLICANT_DRIVER_UNKNOWN, "???"), + NM_UTILS_LOOKUP_ITEM (NM_SUPPLICANT_DRIVER_WIRELESS, NM_WPAS_DEFAULT_WIFI_DRIVER), + NM_UTILS_LOOKUP_ITEM (NM_SUPPLICANT_DRIVER_WIRED, "wired"), + NM_UTILS_LOOKUP_ITEM (NM_SUPPLICANT_DRIVER_MACSEC, "macsec_linux"), +); + +/*****************************************************************************/ + +NMTernary +nm_supplicant_manager_is_available (NMSupplicantManager *self) { - return count > 2; + g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NM_TERNARY_FALSE); + + return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->available; } -static gboolean -is_available (NMSupplicantManager *self) +NMRefString * +nm_supplicant_manager_get_dbus_name_owner (NMSupplicantManager *self) { - NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL); - return priv->running - && !die_count_exceeded (priv->die_count); + return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->name_owner; +} + +GDBusConnection *nm_supplicant_manager_get_dbus_connection (NMSupplicantManager *self) +{ + g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL); + + return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->dbus_connection; +} + +NMSupplCapMask +nm_supplicant_manager_get_global_capabilities (NMSupplicantManager *self) +{ + g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NM_SUPPL_CAP_MASK_NONE); + + return NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->capabilities; } /*****************************************************************************/ static void -_sup_iface_last_ref (gpointer data, - GObject *object, - gboolean is_last_ref) +_caps_set (NMSupplicantManagerPrivate *priv, + NMSupplCapType type, + NMTernary value) { - NMSupplicantManager *self = data; - NMSupplicantManagerPrivate *priv; - NMSupplicantInterface *sup_iface = (NMSupplicantInterface *) object; - const char *op; + priv->capabilities = NM_SUPPL_CAP_MASK_SET (priv->capabilities, type, value); +} - g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self)); - g_return_if_fail (NM_IS_SUPPLICANT_INTERFACE (sup_iface)); - g_return_if_fail (is_last_ref); +static char +_caps_to_char (NMSupplicantManagerPrivate *priv, + NMSupplCapType type) +{ + NMTernary val; + + val = NM_SUPPL_CAP_MASK_GET (priv->capabilities, type); + if (val == NM_TERNARY_TRUE) + return '+'; + if (val == NM_TERNARY_FALSE) + return '-'; + return '?'; +} - priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); +/*****************************************************************************/ - if (!g_slist_find (priv->ifaces, sup_iface)) - g_return_if_reached (); - - /* Ask wpa_supplicant to remove this interface */ - if ( priv->running - && priv->proxy - && (op = nm_supplicant_interface_get_object_path (sup_iface))) { - g_dbus_proxy_call (priv->proxy, - "RemoveInterface", - g_variant_new ("(o)", op), - G_DBUS_CALL_FLAGS_NONE, - 3000, - NULL, - NULL, - NULL); - } +static void +_dbus_call_remove_interface (GDBusConnection *dbus_connection, + const char *name_owner, + const char *iface_path) +{ + nm_assert (G_IS_DBUS_CONNECTION (dbus_connection)); + nm_assert (name_owner); + nm_assert (iface_path); + + g_dbus_connection_call (dbus_connection, + name_owner, + NM_WPAS_DBUS_PATH, + NM_WPAS_DBUS_INTERFACE, + "RemoveInterface", + g_variant_new ("(o)", iface_path), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 10000, + NULL, + NULL, + NULL); +} - priv->ifaces = g_slist_remove (priv->ifaces, sup_iface); - g_object_remove_toggle_ref ((GObject *) sup_iface, _sup_iface_last_ref, self); +void +_nm_supplicant_manager_dbus_call_remove_interface (NMSupplicantManager *self, + const char *name_owner, + const char *iface_path) +{ + _dbus_call_remove_interface (NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->dbus_connection, + name_owner, + iface_path); } +/*****************************************************************************/ + static void on_supplicant_wfd_ies_set (GObject *source_object, - GAsyncResult *res, + GAsyncResult *result, gpointer user_data) { - gs_unref_variant GVariant *result = NULL; + gs_unref_variant GVariant *res = NULL; gs_free_error GError *error = NULL; - result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), res, &error); - - if (!result) - _LOGW ("failed to set WFD IEs on wpa_supplicant: %s", error->message); + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), result, &error); + if (!res) + _LOGD ("failed to set WFD IEs on wpa_supplicant: %s", error->message); } /** @@ -140,172 +245,677 @@ nm_supplicant_manager_set_wfd_ies (NMSupplicantManager *self, { NMSupplicantManagerPrivate *priv; GVariantBuilder params; - GVariant *val; g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (self)); priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - _LOGD ("setting WFD IEs for P2P operation"); + if (!priv->name_owner) + return; - if (wfd_ies) - val = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - g_bytes_get_data (wfd_ies, NULL), - g_bytes_get_size (wfd_ies), - sizeof (guint8)); - else - val = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - NULL, 0, sizeof (guint8)); + _LOGD ("setting WFD IEs for P2P operation on %s", priv->name_owner->str); g_variant_builder_init (¶ms, G_VARIANT_TYPE ("(ssv)")); - g_variant_builder_add (¶ms, "s", g_dbus_proxy_get_interface_name (priv->proxy)); + g_variant_builder_add (¶ms, "s", NM_WPAS_DBUS_INTERFACE); g_variant_builder_add (¶ms, "s", "WFDIEs"); - g_variant_builder_add_value (¶ms, g_variant_new_variant (val)); + g_variant_builder_add_value (¶ms, + g_variant_new_variant (nm_utils_gbytes_to_variant_ay (wfd_ies))); - g_dbus_connection_call (g_dbus_proxy_get_connection (priv->proxy), - g_dbus_proxy_get_name (priv->proxy), - g_dbus_proxy_get_object_path (priv->proxy), - "org.freedesktop.DBus.Properties", + g_dbus_connection_call (priv->dbus_connection, + priv->name_owner->str, + NM_WPAS_DBUS_PATH, + DBUS_INTERFACE_PROPERTIES, "Set", g_variant_builder_end (¶ms), - G_VARIANT_TYPE_UNIT, + G_VARIANT_TYPE ("()"), G_DBUS_CALL_FLAGS_NO_AUTO_START, - 1000, + 3000, NULL, on_supplicant_wfd_ies_set, NULL); } -/** - * nm_supplicant_manager_create_interface: - * @self: the #NMSupplicantManager - * @ifname: the interface for which to obtain the supplicant interface - * @is_wireless: whether the interface is supposed to be wireless. - * - * Note: the manager owns a reference to the instance and the only way to - * get the manager to release it, is by dropping all other references - * to the supplicant-interface (or destroying the manager). - * - * Returns: (transfer full): returns a #NMSupplicantInterface or %NULL. - * Must be unrefed at the end. - * */ -NMSupplicantInterface * +/*****************************************************************************/ + +static gboolean +_poke_name_owner_timeout_cb (gpointer user_data) +{ + NMSupplicantManager *self = user_data; + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + gs_free_error GError *error = NULL; + gboolean available_changed = FALSE; + + nm_assert (!priv->name_owner); + + priv->poke_name_owner_timeout_id = 0; + nm_clear_g_cancellable (&priv->poke_name_owner_cancellable); + + _LOGT ("poke service \"%s\" failed for good with timeout%s", + NM_WPAS_DBUS_SERVICE, + (priv->available == NM_TERNARY_DEFAULT) + ? " (set as not available)" + : ""); + + if (priv->available == NM_TERNARY_DEFAULT) { + /* the available flag usually only changes together with the name-owner. + * However, if we tries to poke the service but failed to start it (with + * timeout), was also set it as (hard) not available. */ + priv->available = NM_TERNARY_FALSE; + nm_clear_g_source (&priv->available_reset_id); + priv->available_reset_id = g_timeout_add_seconds (60, + _available_reset_cb, + self); + available_changed = TRUE; + } + + nm_utils_error_set (&error, + NM_UTILS_ERROR_UNKNOWN, + "Failed to D-Bus activate wpa_supplicant service"); + + _create_iface_proceed_all (self, error); + + if (available_changed) { + /* We delay the emitting of the notification after aborting all + * create-iface handles. */ + g_signal_emit (self, signals[AVAILABLE_CHANGED], 0); + } + + return G_SOURCE_REMOVE; +} + +static void +_poke_name_owner_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + gs_unref_variant GVariant *res = NULL; + gs_free_error GError *error = NULL; + + res = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error); + if (nm_utils_error_is_cancelled (error)) + return; + + if (!res) + _LOGT ("poke service \"%s\" failed: %s", NM_WPAS_DBUS_SERVICE, error->message); + else + _LOGT ("poke service \"%s\" succeeded", NM_WPAS_DBUS_SERVICE); + + /* in both cases, we react the same: we wait for the name owner to appear + * or hit the timeout. */ +} + +static void +_poke_name_owner (NMSupplicantManager *self) +{ + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + + if (priv->poke_name_owner_cancellable) + return; + + _LOGT ("poke service \"%s\"...", NM_WPAS_DBUS_SERVICE); + + priv->poke_name_owner_cancellable = g_cancellable_new (); + priv->poke_name_owner_timeout_id = g_timeout_add (3000, + _poke_name_owner_timeout_cb, + self); + nm_dbus_connection_call_start_service_by_name (priv->dbus_connection, + NM_WPAS_DBUS_SERVICE, + 5000, + priv->poke_name_owner_cancellable, + _poke_name_owner_cb, + self); +} + +/*****************************************************************************/ + +static void +_create_iface_complete (NMSupplMgrCreateIfaceHandle *handle, + NMSupplicantInterface *supp_iface, + GError *error) +{ + nm_assert (!supp_iface || NM_IS_SUPPLICANT_INTERFACE (supp_iface)); + nm_assert ((!!supp_iface) != (!!error)); + + c_list_unlink (&handle->create_iface_lst); + + nm_clear_g_source (&handle->fail_on_idle_id); + + if (handle->callback) { + NMSupplicantManagerCreateInterfaceCb callback; + + nm_assert (NM_IS_SUPPLICANT_MANAGER (handle->self)); + + callback = handle->callback; + handle->callback = NULL; + callback (handle->self, + handle, + supp_iface, + error, + handle->callback_user_data); + } + + g_clear_error (&handle->fail_on_idle_error); + + g_clear_object (&handle->self); + + if (handle->shutdown_handle) { + /* we have a pending CreateInterface request. We keep the handle + * instance alive. This is to remove the device again, once the + * request completes. */ + return; + } + + nm_clear_g_cancellable (&handle->cancellable); + nm_ref_string_unref (handle->name_owner); + + nm_g_slice_free_fcn (handle); +} + +static void +_create_iface_add (NMSupplicantManager *self, + NMSupplMgrCreateIfaceHandle *handle, + const char *iface_path_str, + gboolean created_by_us) +{ + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + nm_auto_ref_string NMRefString *iface_path = NULL; + gs_unref_object NMSupplicantInterface *supp_iface = NULL; + + iface_path = nm_ref_string_new (iface_path_str); + + supp_iface = g_hash_table_lookup (priv->supp_ifaces, iface_path); + if (supp_iface) { + /* Now this is odd... Reuse the same interface. */ + g_object_ref (supp_iface); + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: interface %s on %s created (already existing)", + NM_HASH_OBFUSCATE_PTR (handle), + iface_path_str, + priv->name_owner->str); + _create_iface_complete (handle, supp_iface, NULL); + return; + } + + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: interface %s on %s created%s", + NM_HASH_OBFUSCATE_PTR (handle), + iface_path_str, + priv->name_owner->str, + created_by_us ? " (created by us)" : ""); + + supp_iface = nm_supplicant_interface_new (self, + iface_path, + handle->ifindex, + handle->driver); + + _supp_iface_add (self, iface_path, supp_iface); + + _create_iface_complete (handle, supp_iface, NULL); +} + +static void +_create_iface_dbus_call_get_interface_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GDBusConnection *dbus_connection = G_DBUS_CONNECTION (source); + NMSupplMgrCreateIfaceHandle *handle; + NMSupplicantManager *self; + NMSupplicantManagerPrivate *priv; + gs_unref_variant GVariant *res = NULL; + gs_free_error GError *error = NULL; + const char *iface_path_str; + + res = g_dbus_connection_call_finish (dbus_connection, result, &error); + + if (nm_utils_error_is_cancelled (error)) + return; + + handle = user_data; + nm_assert (handle->callback); + + self = handle->self; + priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + + nm_assert (handle->name_owner == priv->name_owner); + + if (!res) { + char ifname[NMP_IFNAMSIZ]; + + if ( handle->create_iface_try_count < CREATE_IFACE_TRY_COUNT_MAX + && _nm_dbus_error_has_name (error, NM_WPAS_ERROR_UNKNOWN_IFACE) + && nm_platform_if_indextoname (NM_PLATFORM_GET, handle->ifindex, ifname)) { + /* Before, supplicant told us the interface existed. Was there a race? + * Try again. */ + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: D-Bus call failed to get interface. Try to create it again (ifname \"%s\")", + NM_HASH_OBFUSCATE_PTR (handle), + ifname); + _create_iface_dbus_call_create_interface (self, handle, ifname); + return; + } + + g_clear_object (&handle->cancellable); + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: D-Bus call to get interface failed: %s", + NM_HASH_OBFUSCATE_PTR (handle), + error->message); + _create_iface_complete (handle, NULL, error); + return; + } + + g_clear_object (&handle->cancellable); + + g_variant_get (res, "(&o)", &iface_path_str); + + _create_iface_add (self, handle, iface_path_str, FALSE); +} + +static void +_create_iface_dbus_call_create_interface_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GDBusConnection *dbus_connection = G_DBUS_CONNECTION (source); + NMSupplMgrCreateIfaceHandle *handle = user_data; + NMSupplicantManager *self; + NMSupplicantManagerPrivate *priv; + gs_unref_variant GVariant *res = NULL; + gs_free_error GError *error = NULL; + const char *iface_path_str; + char ifname[NMP_IFNAMSIZ]; + + res = g_dbus_connection_call_finish (dbus_connection, result, &error); + + nm_shutdown_wait_obj_unregister (g_steal_pointer (&handle->shutdown_handle)); + + if (!res) { + if ( handle->callback + && ({ nm_assert (handle->self); TRUE; }) + && _nm_dbus_error_has_name (error, NM_WPAS_ERROR_EXISTS_ERROR) + && nm_platform_if_indextoname (NM_PLATFORM_GET, handle->ifindex, ifname)) { + self = handle->self; + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: D-Bus call failed to create interface. Try to get existing interface (ifname \"%s\")", + NM_HASH_OBFUSCATE_PTR (handle), + ifname); + _create_iface_dbus_call_get_interface (self, handle, ifname); + return; + } + g_clear_object (&handle->cancellable); + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: D-Bus call failed: %s", + NM_HASH_OBFUSCATE_PTR (handle), + error->message); + _create_iface_complete (handle, NULL, error); + return; + } + + g_clear_object (&handle->cancellable); + + self = handle->self; + priv = self + ? NM_SUPPLICANT_MANAGER_GET_PRIVATE (self) + : NULL; + + g_variant_get (res, "(&o)", &iface_path_str); + + if ( !handle->callback + || priv->name_owner != handle->name_owner) { + if (!handle->callback) { + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: request already cancelled but still remove interface %s in %s", + NM_HASH_OBFUSCATE_PTR (handle), + iface_path_str, + handle->name_owner->str); + } else { + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: name owner changed, still remove interface %s in %s", + NM_HASH_OBFUSCATE_PTR (handle), + iface_path_str, + handle->name_owner->str); + nm_utils_error_set (&error, + NM_UTILS_ERROR_UNKNOWN, + "The name owner changed since creating the interface"); + } + _dbus_call_remove_interface (dbus_connection, + handle->name_owner->str, + iface_path_str); + _create_iface_complete (handle, NULL, error); + return; + } + + _create_iface_add (self, handle, iface_path_str, TRUE); +} + +static void +_create_iface_dbus_call_get_interface (NMSupplicantManager *self, + NMSupplMgrCreateIfaceHandle *handle, + const char *ifname) +{ + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + + nm_assert (handle->cancellable); + nm_assert (!handle->shutdown_handle); + + g_dbus_connection_call (priv->dbus_connection, + priv->name_owner->str, + NM_WPAS_DBUS_PATH, + NM_WPAS_DBUS_INTERFACE, + "GetInterface", + g_variant_new ("(s)", ifname), + G_VARIANT_TYPE ("(o)"), + G_DBUS_CALL_FLAGS_NONE, + 5000, + handle->cancellable, + _create_iface_dbus_call_get_interface_cb, + handle); +} + +static void +_create_iface_dbus_call_create_interface (NMSupplicantManager *self, + NMSupplMgrCreateIfaceHandle *handle, + const char *ifname) +{ + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + GVariantBuilder builder; + + nm_assert (priv->name_owner == handle->name_owner); + nm_assert (handle->cancellable); + nm_assert (!handle->shutdown_handle); + nm_assert (handle->create_iface_try_count <= CREATE_IFACE_TRY_COUNT_MAX); + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&builder, + "{sv}", + "Driver", + g_variant_new_string (nm_supplicant_driver_to_string (handle->driver))); + g_variant_builder_add (&builder, + "{sv}", + "Ifname", + g_variant_new_string (ifname)); + + handle->shutdown_handle = nm_shutdown_wait_obj_register_cancellable_full (handle->cancellable, + g_strdup_printf ("wpas-create-" NM_HASH_OBFUSCATE_PTR_FMT, + NM_HASH_OBFUSCATE_PTR (handle)), + TRUE); + handle->create_iface_try_count++; + g_dbus_connection_call (priv->dbus_connection, + handle->name_owner->str, + NM_WPAS_DBUS_PATH, + NM_WPAS_DBUS_INTERFACE, + "CreateInterface", + g_variant_new ("(a{sv})", &builder), + G_VARIANT_TYPE ("(o)"), + G_DBUS_CALL_FLAGS_NONE, + 5000, + handle->cancellable, + _create_iface_dbus_call_create_interface_cb, + handle); +} + +static void +_create_iface_dbus_start (NMSupplicantManager *self, + NMSupplMgrCreateIfaceHandle *handle) +{ + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + char ifname[NMP_IFNAMSIZ]; + + nm_assert (priv->name_owner); + nm_assert (!handle->cancellable); + + if (!nm_platform_if_indextoname (NM_PLATFORM_GET, handle->ifindex, ifname)) { + nm_utils_error_set (&handle->fail_on_idle_error, + NM_UTILS_ERROR_UNKNOWN, + "Cannot find interface %d", + handle->ifindex); + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: creating interface fails to find interface name for ifindex %d", + NM_HASH_OBFUSCATE_PTR (handle), + handle->ifindex); + handle->fail_on_idle_id = g_idle_add (_create_iface_fail_on_idle_cb, handle); + return; + } + + /* Our handle keeps @self alive. That means, when NetworkManager shall shut + * down, it's the responsibility of the callers to cancel the handles, + * to initiate coordinated shutdown. + * + * However, we now issue a CreateInterface call. Even if the handle gets cancelled + * (because of shutdown, or because the caller is no longer interested in the + * result), we don't want to cancel this request. Instead, we want to get + * the interface path and remove it right away. + * + * That means, the D-Bus call cannot be cancelled (because we always care about + * the result). Only the @handle can be cancelled, but parts of the handle will + * stick around to complete the task. + * + * See also handle->shutdown_handle. + */ + handle->name_owner = nm_ref_string_ref (priv->name_owner); + handle->cancellable = g_cancellable_new (); + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: creating interface (ifname \"%s\")...", + NM_HASH_OBFUSCATE_PTR (handle), + ifname); + _create_iface_dbus_call_create_interface (self, handle, ifname); +} + +static gboolean +_create_iface_fail_on_idle_cb (gpointer user_data) +{ + NMSupplMgrCreateIfaceHandle *handle = user_data; + + handle->fail_on_idle_id = 0; + + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: fail with internal error: %s", + NM_HASH_OBFUSCATE_PTR (handle), + handle->fail_on_idle_error->message); + + _create_iface_complete (handle, NULL, handle->fail_on_idle_error); + return G_SOURCE_REMOVE; +} + +NMSupplMgrCreateIfaceHandle * nm_supplicant_manager_create_interface (NMSupplicantManager *self, - const char *ifname, - NMSupplicantDriver driver) + int ifindex, + NMSupplicantDriver driver, + NMSupplicantManagerCreateInterfaceCb callback, + gpointer user_data) { NMSupplicantManagerPrivate *priv; - NMSupplicantInterface *iface; - GSList *ifaces; + NMSupplMgrCreateIfaceHandle *handle; g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL); - g_return_val_if_fail (ifname != NULL, NULL); + g_return_val_if_fail (ifindex > 0, NULL); + g_return_val_if_fail (callback, NULL); + nm_assert (nm_supplicant_driver_to_string (driver)); priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - _LOGD ("(%s): creating new supplicant interface", ifname); + handle = g_slice_new (NMSupplMgrCreateIfaceHandle); + *handle = (NMSupplMgrCreateIfaceHandle) { + .self = g_object_ref (self), + .callback = callback, + .callback_user_data = user_data, + .driver = driver, + .ifindex = ifindex, + }; + c_list_link_tail (&priv->create_iface_lst_head, &handle->create_iface_lst); + + if (!priv->dbus_connection) { + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: new request interface %d (driver %s). Fail bacause no D-Bus connection to talk to wpa_supplicant...", + NM_HASH_OBFUSCATE_PTR (handle), + ifindex, + nm_supplicant_driver_to_string (driver)); + nm_utils_error_set (&handle->fail_on_idle_error, + NM_UTILS_ERROR_UNKNOWN, + "No D-Bus connection to talk to wpa_supplicant"); + handle->fail_on_idle_id = g_idle_add (_create_iface_fail_on_idle_cb, handle); + return handle; + } - /* assert against not requesting duplicate interfaces. */ - for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) { - if (g_strcmp0 (nm_supplicant_interface_get_ifname (ifaces->data), ifname) == 0) - g_return_val_if_reached (NULL); + if (!priv->name_owner) { + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: new request interface %d (driver %s). %s", + NM_HASH_OBFUSCATE_PTR (handle), + ifindex, + nm_supplicant_driver_to_string (driver), + priv->poke_name_owner_cancellable + ? "Waiting for supplicant..." + : "Poke supplicant..."); + _poke_name_owner (self); + return handle; } - iface = nm_supplicant_interface_new (ifname, - NULL, - driver, - priv->fast_support, - priv->ap_support, - priv->pmf_support, - priv->fils_support, - priv->p2p_support, - priv->mesh_support, - priv->wfd_support, - priv->ft_support, - priv->sha384_support); - - priv->ifaces = g_slist_prepend (priv->ifaces, iface); - g_object_add_toggle_ref ((GObject *) iface, _sup_iface_last_ref, self); - - /* If we're making the supplicant take a time out for a bit, don't - * let the supplicant interface start immediately, just let it hang - * around in INIT state until we're ready to talk to the supplicant - * again. - */ - if (is_available (self)) - nm_supplicant_interface_set_supplicant_available (iface, TRUE); + if (priv->get_capabilities_cancellable) { + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: new request interface %d (driver %s). Waiting to fetch capabilities for %s...", + NM_HASH_OBFUSCATE_PTR (handle), + ifindex, + nm_supplicant_driver_to_string (driver), + priv->name_owner->str); + return handle; + } - return iface; + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: new request interface %d (driver %s). create interface on %s...", + NM_HASH_OBFUSCATE_PTR (handle), + ifindex, + nm_supplicant_driver_to_string (driver), + priv->name_owner->str); + + _create_iface_dbus_start (self, handle); + return handle; +} + +static void +_create_iface_proceed_all (NMSupplicantManager *self, + GError *error) +{ + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + NMSupplMgrCreateIfaceHandle *handle; + + nm_assert (error || priv->name_owner); + nm_assert (error || !priv->get_capabilities_cancellable); + + if (c_list_is_empty (&priv->create_iface_lst_head)) + return; + + if (error) { + CList alt_list; + + /* we move the handles we want to proceed to a alternative list. + * That is, because we invoke callbacks to the caller, who might + * create another request right away. We don't want to proceed + * that one. */ + c_list_init (&alt_list); + c_list_splice (&alt_list, &priv->create_iface_lst_head); + + while ((handle = c_list_last_entry (&alt_list, NMSupplMgrCreateIfaceHandle, create_iface_lst))) { + /* We don't need to keep @self alive. Every handle holds a reference already. */ + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: create interface failed: %s", + NM_HASH_OBFUSCATE_PTR (handle), + error->message); + _create_iface_complete (handle, NULL, error); + } + return; + } + + /* start all the handles. This does not invoke callbacks, so the list of handles + * cannot be modified while we iterate it. */ + c_list_for_each_entry (handle, &priv->create_iface_lst_head, create_iface_lst) { + _LOGT ("create-iface["NM_HASH_OBFUSCATE_PTR_FMT"]: create interface on %s...", + NM_HASH_OBFUSCATE_PTR (handle), + priv->name_owner->str); + _create_iface_dbus_start (self, handle); + } +} + +void +nm_supplicant_manager_create_interface_cancel (NMSupplMgrCreateIfaceHandle *handle) +{ + gs_free_error GError *error = NULL; + + if (!handle) + return; + + g_return_if_fail (NM_IS_SUPPLICANT_MANAGER (handle->self)); + g_return_if_fail (handle->callback); + nm_assert (!c_list_is_empty (&handle->create_iface_lst)); + + nm_utils_error_set_cancelled (&error, FALSE, NULL); + _create_iface_complete (handle, NULL, error); } -/** - * nm_supplicant_manager_create_interface_from_path: - * @self: the #NMSupplicantManager - * @object_path: the DBus object path for which to obtain the supplicant interface - * - * Note: the manager owns a reference to the instance and the only way to - * get the manager to release it, is by dropping all other references - * to the supplicant-interface (or destroying the manager). - * - * Returns: (transfer full): returns a #NMSupplicantInterface or %NULL. - * Must be unrefed at the end. - * */ NMSupplicantInterface * nm_supplicant_manager_create_interface_from_path (NMSupplicantManager *self, const char *object_path) { NMSupplicantManagerPrivate *priv; - NMSupplicantInterface *iface; - GSList *ifaces; + NMSupplicantInterface *supp_iface; + nm_auto_ref_string NMRefString *iface_path = NULL; g_return_val_if_fail (NM_IS_SUPPLICANT_MANAGER (self), NULL); - g_return_val_if_fail (object_path != NULL, NULL); + g_return_val_if_fail (object_path, NULL); priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - _LOGD ("creating new supplicant interface for dbus path %s", object_path); + iface_path = nm_ref_string_new (object_path); - /* assert against not requesting duplicate interfaces. */ - for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) { - if (g_strcmp0 (nm_supplicant_interface_get_object_path (ifaces->data), object_path) == 0) - g_return_val_if_reached (NULL); - } + supp_iface = g_hash_table_lookup (priv->supp_ifaces, iface_path); - iface = nm_supplicant_interface_new (NULL, - object_path, - NM_SUPPLICANT_DRIVER_WIRELESS, - priv->fast_support, - priv->ap_support, - priv->pmf_support, - priv->fils_support, - priv->p2p_support, - priv->mesh_support, - priv->wfd_support, - priv->ft_support, - priv->sha384_support); - - priv->ifaces = g_slist_prepend (priv->ifaces, iface); - g_object_add_toggle_ref ((GObject *) iface, _sup_iface_last_ref, self); - - /* If we're making the supplicant take a time out for a bit, don't - * let the supplicant interface start immediately, just let it hang - * around in INIT state until we're ready to talk to the supplicant - * again. - */ - if (is_available (self)) - nm_supplicant_interface_set_supplicant_available (iface, TRUE); + if (supp_iface) + return g_object_ref (supp_iface); + + supp_iface = nm_supplicant_interface_new (self, + iface_path, + 0, + NM_SUPPLICANT_DRIVER_UNKNOWN); + + _supp_iface_add (self, iface_path, supp_iface); - return iface; + return supp_iface; } +/*****************************************************************************/ + static void -update_capabilities (NMSupplicantManager *self) +_dbus_interface_removed_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) { + NMSupplicantManager *self = user_data; NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - GSList *ifaces; - const char **array; - GVariant *value; + NMSupplicantInterface *supp_iface; + const char *iface_path_str; + nm_auto_ref_string NMRefString *iface_path = NULL; + + nm_assert (nm_streq (sender_name, priv->name_owner->str)); + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)"))) + return; + + g_variant_get (parameters, "(&o)", &iface_path_str); + + iface_path = nm_ref_string_new (iface_path_str); + + supp_iface = g_hash_table_lookup (priv->supp_ifaces, iface_path); + if (!supp_iface) + return; + + _supp_iface_remove_one (self, supp_iface, FALSE, "InterfaceRemoved signal from wpa_supplicant"); +} + +/*****************************************************************************/ + +static void +_dbus_get_capabilities_cb (GVariant *res, + GError *error, + gpointer user_data) +{ + NMSupplicantManager *self; + NMSupplicantManagerPrivate *priv; + + if (nm_utils_error_is_cancelled (error)) + return; + + self = user_data; + priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->get_capabilities_cancellable); /* The supplicant only advertises global capabilities if the following * commit has been applied: @@ -316,269 +926,398 @@ update_capabilities (NMSupplicantManager *self) * * dbus: Add global capabilities property */ - priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->pmf_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->fils_support = NM_SUPPLICANT_FEATURE_UNKNOWN; + _caps_set (priv, NM_SUPPL_CAP_TYPE_AP, NM_TERNARY_DEFAULT); + _caps_set (priv, NM_SUPPL_CAP_TYPE_PMF, NM_TERNARY_DEFAULT); + _caps_set (priv, NM_SUPPL_CAP_TYPE_FILS, NM_TERNARY_DEFAULT); + /* Support for the following is newer than the capabilities property */ - priv->p2p_support = NM_SUPPLICANT_FEATURE_NO; - priv->ft_support = NM_SUPPLICANT_FEATURE_NO; - priv->sha384_support = NM_SUPPLICANT_FEATURE_NO; - priv->mesh_support = NM_SUPPLICANT_FEATURE_NO; - - value = g_dbus_proxy_get_cached_property (priv->proxy, "Capabilities"); - if (value) { - if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) { - array = g_variant_get_strv (value, NULL); - priv->ap_support = NM_SUPPLICANT_FEATURE_NO; - priv->pmf_support = NM_SUPPLICANT_FEATURE_NO; - priv->fils_support = NM_SUPPLICANT_FEATURE_NO; - priv->p2p_support = NM_SUPPLICANT_FEATURE_NO; - priv->ft_support = NM_SUPPLICANT_FEATURE_NO; - priv->sha384_support = NM_SUPPLICANT_FEATURE_NO; - priv->mesh_support = NM_SUPPLICANT_FEATURE_NO; - if (array) { - if (g_strv_contains (array, "ap")) - priv->ap_support = NM_SUPPLICANT_FEATURE_YES; - if (g_strv_contains (array, "pmf")) - priv->pmf_support = NM_SUPPLICANT_FEATURE_YES; - if (g_strv_contains (array, "fils")) - priv->fils_support = NM_SUPPLICANT_FEATURE_YES; - if (g_strv_contains (array, "p2p")) - priv->p2p_support = NM_SUPPLICANT_FEATURE_YES; - if (g_strv_contains (array, "ft")) - priv->ft_support = NM_SUPPLICANT_FEATURE_YES; - if (g_strv_contains (array, "sha384")) - priv->sha384_support = NM_SUPPLICANT_FEATURE_YES; - if (g_strv_contains (array, "mesh")) - priv->mesh_support = NM_SUPPLICANT_FEATURE_YES; - g_free (array); + _caps_set (priv, NM_SUPPL_CAP_TYPE_P2P, NM_TERNARY_FALSE); + _caps_set (priv, NM_SUPPL_CAP_TYPE_FT, NM_TERNARY_FALSE); + _caps_set (priv, NM_SUPPL_CAP_TYPE_SHA384, NM_TERNARY_FALSE); + _caps_set (priv, NM_SUPPL_CAP_TYPE_MESH, NM_TERNARY_FALSE); + _caps_set (priv, NM_SUPPL_CAP_TYPE_FAST, NM_TERNARY_FALSE); + _caps_set (priv, NM_SUPPL_CAP_TYPE_WFD, NM_TERNARY_FALSE); + + if (res) { + nm_auto_free_variant_iter GVariantIter *res_iter = NULL; + const char *res_key; + GVariant *res_val; + + g_variant_get (res, "(a{sv})", &res_iter); + while (g_variant_iter_loop (res_iter, "{&sv}", &res_key, &res_val)) { + if (nm_streq (res_key, "Capabilities")) { + if (g_variant_is_of_type (res_val, G_VARIANT_TYPE_STRING_ARRAY)) { + gs_free const char **array = NULL; + const char **a; + + array = g_variant_get_strv (res_val, NULL); + _caps_set (priv, NM_SUPPL_CAP_TYPE_AP, NM_TERNARY_FALSE); + _caps_set (priv, NM_SUPPL_CAP_TYPE_PMF, NM_TERNARY_FALSE); + _caps_set (priv, NM_SUPPL_CAP_TYPE_FILS, NM_TERNARY_FALSE); + if (array) { + for (a = array; *a; a++) { + if (nm_streq (*a, "ap")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_AP, NM_TERNARY_TRUE); continue; } + if (nm_streq (*a, "pmf")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_PMF, NM_TERNARY_TRUE); continue; } + if (nm_streq (*a, "fils")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_FILS, NM_TERNARY_TRUE); continue; } + if (nm_streq (*a, "p2p")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_P2P, NM_TERNARY_TRUE); continue; } + if (nm_streq (*a, "ft")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_FT, NM_TERNARY_TRUE); continue; } + if (nm_streq (*a, "sha384")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_SHA384, NM_TERNARY_TRUE); continue; } + if (nm_streq (*a, "mesh")) { _caps_set (priv, NM_SUPPL_CAP_TYPE_MESH, NM_TERNARY_TRUE); continue; } + } + } + } + continue; } - } - g_variant_unref (value); - } - - /* Tell all interfaces about results of the AP/PMF/FILS/P2P/FT/SHA384 check */ - for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) { - nm_supplicant_interface_set_ap_support (ifaces->data, priv->ap_support); - nm_supplicant_interface_set_pmf_support (ifaces->data, priv->pmf_support); - nm_supplicant_interface_set_fils_support (ifaces->data, priv->fils_support); - nm_supplicant_interface_set_p2p_support (ifaces->data, priv->p2p_support); - nm_supplicant_interface_set_ft_support (ifaces->data, priv->ft_support); - nm_supplicant_interface_set_sha384_support (ifaces->data, priv->sha384_support); - nm_supplicant_interface_set_mesh_support (ifaces->data, priv->mesh_support); - } - - _LOGD ("AP mode is %ssupported", - (priv->ap_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->ap_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); - _LOGD ("PMF is %ssupported", - (priv->pmf_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->pmf_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); - _LOGD ("FILS is %ssupported", - (priv->fils_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->fils_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); - _LOGD ("P2P is %ssupported", - (priv->p2p_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->p2p_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); - _LOGD ("FT is %ssupported", - (priv->ft_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->ft_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); - _LOGD ("SHA384 is %ssupported", - (priv->sha384_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->sha384_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); - _LOGD ("Mesh is %ssupported", - (priv->mesh_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->mesh_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); - - /* EAP-FAST */ - priv->fast_support = NM_SUPPLICANT_FEATURE_NO; - value = g_dbus_proxy_get_cached_property (priv->proxy, "EapMethods"); - if (value) { - if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) { - array = g_variant_get_strv (value, NULL); - if (array) { - const char **a; - - for (a = array; *a; a++) { - if (g_ascii_strcasecmp (*a, "FAST") == 0) { - priv->fast_support = NM_SUPPLICANT_FEATURE_YES; - break; + if (nm_streq (res_key, "EapMethods")) { + if (g_variant_is_of_type (res_val, G_VARIANT_TYPE_STRING_ARRAY)) { + gs_free const char **array = NULL; + const char **a; + + array = g_variant_get_strv (res_val, NULL); + if (array) { + for (a = array; *a; a++) { + if (g_ascii_strcasecmp (*a, "FAST") == 0) { + _caps_set (priv, NM_SUPPL_CAP_TYPE_FAST, NM_TERNARY_TRUE); + break; + } + } } } - g_free (array); + continue; + } + if (nm_streq (res_key, "WFDIEs")) { + _caps_set (priv, NM_SUPPL_CAP_TYPE_WFD, NM_TERNARY_TRUE); + continue; } } - g_variant_unref (value); } - for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) - nm_supplicant_interface_set_fast_support (ifaces->data, priv->fast_support); + _LOGD ("supported features:" + " AP%c" + " PMF%c" + " FILS%c" + " P2P%c" + " FT%c" + " SHA384%c" + " MESH%c" + " FAST%c" + " WFD%c" + "", + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_AP), + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_PMF), + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_FILS), + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_P2P), + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_FT), + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_SHA384), + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_MESH), + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_FAST), + _caps_to_char (priv, NM_SUPPL_CAP_TYPE_WFD)); + + nm_assert (g_hash_table_size (priv->supp_ifaces) == 0); + nm_assert (c_list_is_empty (&priv->supp_lst_head)); + + _create_iface_proceed_all (self, NULL); +} - _LOGD ("EAP-FAST is %ssupported", - (priv->fast_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->fast_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); +/*****************************************************************************/ - priv->wfd_support = NM_SUPPLICANT_FEATURE_NO; - value = g_dbus_proxy_get_cached_property (priv->proxy, "WFDIEs"); - if (value) { - priv->wfd_support = NM_SUPPLICANT_FEATURE_YES; - g_variant_unref (value); - } +void +_nm_supplicant_manager_unregister_interface (NMSupplicantManager *self, + NMSupplicantInterface *supp_iface) +{ + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) - nm_supplicant_interface_set_wfd_support (ifaces->data, priv->fast_support); + nm_assert (NM_IS_SUPPLICANT_INTERFACE (supp_iface)); + nm_assert (c_list_contains (&NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->supp_lst_head, &supp_iface->supp_lst)); - _LOGD ("WFD is %ssupported", - (priv->wfd_support == NM_SUPPLICANT_FEATURE_YES) ? "" : - (priv->wfd_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); + c_list_unlink (&supp_iface->supp_lst); + if (!g_hash_table_remove (priv->supp_ifaces, nm_supplicant_interface_get_object_path (supp_iface))) + nm_assert_not_reached (); } static void -availability_changed (NMSupplicantManager *self, gboolean available) +_supp_iface_add (NMSupplicantManager *self, + NMRefString *iface_path, + NMSupplicantInterface *supp_iface) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - GSList *ifaces, *iter; - - if (!priv->ifaces) - return; - /* setting the supplicant as unavailable might cause the caller to unref - * the supplicant (and thus remove the instance from the list of interfaces. - * Delay that by taking an additional reference first. */ - ifaces = g_slist_copy (priv->ifaces); - for (iter = ifaces; iter; iter = iter->next) - g_object_ref (iter->data); - for (iter = ifaces; iter; iter = iter->next) - nm_supplicant_interface_set_supplicant_available (iter->data, available); - g_slist_free_full (ifaces, g_object_unref); + c_list_link_tail (&priv->supp_lst_head, &supp_iface->supp_lst); + if (!g_hash_table_insert (priv->supp_ifaces, iface_path, supp_iface)) + nm_assert_not_reached (); } static void -set_running (NMSupplicantManager *self, gboolean now_running) +_supp_iface_remove_one (NMSupplicantManager *self, + NMSupplicantInterface *supp_iface, + gboolean force_remove_from_supplicant, + const char *reason) { - NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - gboolean old_available = is_available (self); - gboolean new_available; +#if NM_MORE_ASSERTS + _nm_unused gs_unref_object NMSupplicantInterface *supp_iface_keep_alive = g_object_ref (supp_iface); +#endif + + nm_assert (NM_IS_SUPPLICANT_MANAGER (self)); + nm_assert (NM_IS_SUPPLICANT_INTERFACE (supp_iface)); + nm_assert (c_list_contains (&NM_SUPPLICANT_MANAGER_GET_PRIVATE (self)->supp_lst_head, &supp_iface->supp_lst)); + + _nm_supplicant_interface_set_state_down (supp_iface, force_remove_from_supplicant, reason); - priv->running = now_running; - new_available = is_available (self); - if (old_available != new_available) - availability_changed (self, new_available); + nm_assert (c_list_is_empty (&supp_iface->supp_lst)); } static void -set_die_count (NMSupplicantManager *self, guint new_die_count) +_supp_iface_remove_all (NMSupplicantManager *self, + gboolean force_remove_from_supplicant, + const char *reason) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - gboolean old_available = is_available (self); - gboolean new_available; + NMSupplicantInterface *supp_iface; - priv->die_count = new_die_count; - new_available = is_available (self); - if (old_available != new_available) - availability_changed (self, new_available); + while ((supp_iface = c_list_first_entry (&priv->supp_lst_head, NMSupplicantInterface, supp_lst))) + _supp_iface_remove_one (self, supp_iface, force_remove_from_supplicant, reason); } +/*****************************************************************************/ + static gboolean -wpas_die_count_reset_cb (gpointer user_data) +_available_reset_cb (gpointer user_data) { - NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data); + NMSupplicantManager *self = user_data; NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - /* Reset the die count back to zero, which allows use of the supplicant again */ - priv->die_count_reset_id = 0; - set_die_count (self, 0); - _LOGI ("wpa_supplicant die count reset"); - return FALSE; + priv->available_reset_id = 0; + nm_assert (priv->available == NM_TERNARY_FALSE); + priv->available = NM_TERNARY_DEFAULT; + g_signal_emit (self, signals[AVAILABLE_CHANGED], 0); + return G_SOURCE_REMOVE; } +/*****************************************************************************/ + static void -name_owner_cb (GDBusProxy *proxy, GParamSpec *pspec, gpointer user_data) +name_owner_changed (NMSupplicantManager *self, + const char *name_owner, + gboolean first_time) { - NMSupplicantManager *self = NM_SUPPLICANT_MANAGER (user_data); NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - char *owner; - - g_return_if_fail (proxy == priv->proxy); - - owner = g_dbus_proxy_get_name_owner (proxy); - _LOGI ("wpa_supplicant %s", owner ? "running" : "stopped"); - - if (owner) { - update_capabilities (self); - set_running (self, TRUE); - } else if (priv->running) { - /* Reschedule the die count reset timeout. Every time the supplicant - * dies we wait 10 seconds before resetting the counter. If the - * supplicant died more than twice before the timer is reset, then - * we don't try to talk to the supplicant for a while. - */ - if (priv->die_count_reset_id) - g_source_remove (priv->die_count_reset_id); - priv->die_count_reset_id = g_timeout_add_seconds (10, wpas_die_count_reset_cb, self); - set_die_count (self, priv->die_count + 1); - - if (die_count_exceeded (priv->die_count)) { - _LOGI ("wpa_supplicant die count %d; ignoring for 10 seconds", - priv->die_count); + NMTernary available; + gboolean available_changed = FALSE; + + nm_assert (!priv->get_name_owner_cancellable); + nm_assert ( !name_owner + || name_owner[0]); + nm_assert ( ( first_time + && !priv->name_owner) + || ( !first_time + && (!!priv->name_owner) != (!!name_owner))); + + if (first_time) { + _LOGD ("wpa_supplicant name owner %s%s%s (%srunning)", + NM_PRINT_FMT_QUOTE_STRING (name_owner), + name_owner ? "" : "not "); + } else { + _LOGD ("wpa_supplicant name owner \"%s\" %s (%srunning)", + name_owner ?: priv->name_owner->str, + name_owner ? "disappeared" : "appeared", + name_owner ? "" : "not "); + } + + nm_ref_string_unref (priv->name_owner); + priv->name_owner = nm_ref_string_new (name_owner); + + nm_clear_g_dbus_connection_signal (priv->dbus_connection, + &priv->interface_removed_id); + + if (name_owner) { + if (nm_clear_g_source (&priv->poke_name_owner_timeout_id)) + _LOGT ("poke service \"%s\" completed with name owner change", NM_WPAS_DBUS_SERVICE); + nm_clear_g_cancellable (&priv->poke_name_owner_cancellable); + } + + nm_clear_g_cancellable (&priv->get_capabilities_cancellable); + + priv->capabilities = NM_SUPPL_CAP_MASK_NONE; + if (priv->name_owner) { + priv->get_capabilities_cancellable = g_cancellable_new (); + nm_dbus_connection_call_get_all (priv->dbus_connection, + priv->name_owner->str, + NM_WPAS_DBUS_PATH, + NM_WPAS_DBUS_INTERFACE, + 5000, + priv->get_capabilities_cancellable, + _dbus_get_capabilities_cb, + self); + priv->interface_removed_id = g_dbus_connection_signal_subscribe (priv->dbus_connection, + priv->name_owner->str, + NM_WPAS_DBUS_INTERFACE, + "InterfaceRemoved", + NULL, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + _dbus_interface_removed_cb, + self, + NULL); + } + + /* if supplicant is running (has a name owner), we may use it. + * If this is the first time, and supplicant is not running, we + * may also use it (and assume that we probably could D-Bus activate + * it). + * + * Otherwise, somebody else stopped supplicant. It's no longer useable to + * us and we block auto starting it. The user has to start the service... + * + * Actually, below we reset the hard block after a short timeout. This + * causes the caller to notify that supplicant may now by around and + * retry to D-Bus activate it. */ + if (priv->name_owner) + available = NM_TERNARY_TRUE; + else if (first_time) + available = NM_TERNARY_DEFAULT; + else + available = NM_TERNARY_FALSE; + + if (priv->available != available) { + priv->available = available; + _LOGD ("supplicant is now %savailable", + available == FALSE + ? "not " + : ( available == TRUE + ? "" + : "maybe ")); + available_changed = TRUE; + + nm_clear_g_source (&priv->available_reset_id); + if (available == NM_TERNARY_FALSE) { + /* reset the availability from a hard "no" to a "maybe" in a bit. */ + priv->available_reset_id = g_timeout_add_seconds (60, + _available_reset_cb, + self); } + } + + _supp_iface_remove_all (self, TRUE, "name-owner changed"); - priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->fast_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->pmf_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->fils_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->ft_support = NM_SUPPLICANT_FEATURE_UNKNOWN; - priv->sha384_support = NM_SUPPLICANT_FEATURE_UNKNOWN; + if (!priv->name_owner) { + if (priv->poke_name_owner_timeout_id) { + /* we are still poking for the service to start. Don't cancel + * the pending create requests just yet. */ + } else { + gs_free_error GError *local_error = NULL; - set_running (self, FALSE); + /* When we loose the name owner, we fail all pending creation requests. */ + nm_utils_error_set (&local_error, + NM_UTILS_ERROR_UNKNOWN, + "Name owner lost"); + _create_iface_proceed_all (self, local_error); + } + } else { + /* We got a name-owner, but we don't do anything. Instead let + * _dbus_get_capabilities_cb() complete and kick of the create-iface + * handles. + * + * Note that before the first name-owner change, all create-iface + * requests fail right away. So we don't have to handle them here + * (by starting to poke the service). */ } - g_free (owner); + if (available_changed) + g_signal_emit (self, signals[AVAILABLE_CHANGED], 0); } static void -on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data) +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) { - NMSupplicantManager *self; - NMSupplicantManagerPrivate *priv; - GError *error = NULL; - GDBusProxy *proxy; + gs_unref_object NMSupplicantManager *self = g_object_ref (user_data); + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + const char *name_owner; - proxy = g_dbus_proxy_new_for_bus_finish (result, &error); - if (!proxy) { - _LOGW ("failed to acquire wpa_supplicant proxy: Wi-Fi and 802.1x will not be available (%s)", - error->message); - g_clear_error (&error); + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) return; + + if (priv->get_name_owner_cancellable) + return; + + g_variant_get (parameters, + "(&s&s&s)", + NULL, + NULL, + &name_owner); + + name_owner = nm_str_not_empty (name_owner); + + if (nm_streq0 (name_owner, nm_ref_string_get_str (priv->name_owner))) + return; + + if ( name_owner + && priv->name_owner) { + /* odd, we directly switch from one name owner to the next. Can't allow that. + * First clear the name owner before resetting. */ + name_owner_changed (self, NULL, FALSE); } + name_owner_changed (user_data, name_owner, FALSE); +} - self = NM_SUPPLICANT_MANAGER (user_data); +static void +get_name_owner_cb (const char *name_owner, + GError *error, + gpointer user_data) +{ + NMSupplicantManager *self = user_data; + NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); + + if ( !name_owner + && nm_utils_error_is_cancelled (error)) + return; + + self = user_data; priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - priv->proxy = proxy; - g_signal_connect (priv->proxy, "notify::g-name-owner", G_CALLBACK (name_owner_cb), self); - name_owner_cb (priv->proxy, NULL, self); + g_clear_object (&priv->get_name_owner_cancellable); + + name_owner_changed (self, nm_str_not_empty (name_owner), TRUE); } /*****************************************************************************/ -NM_DEFINE_SINGLETON_GETTER (NMSupplicantManager, nm_supplicant_manager_get, NM_TYPE_SUPPLICANT_MANAGER); - static void nm_supplicant_manager_init (NMSupplicantManager *self) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - priv->cancellable = g_cancellable_new (); - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - WPAS_DBUS_SERVICE, - WPAS_DBUS_PATH, - WPAS_DBUS_INTERFACE, - priv->cancellable, - (GAsyncReadyCallback) on_proxy_acquired, - self); + nm_assert (priv->capabilities == NM_SUPPL_CAP_MASK_NONE); + nm_assert (priv->available == NM_TERNARY_FALSE); + + priv->supp_ifaces = g_hash_table_new (nm_direct_hash, NULL); + c_list_init (&priv->supp_lst_head); + c_list_init (&priv->create_iface_lst_head); + + priv->dbus_connection = nm_g_object_ref (NM_MAIN_DBUS_CONNECTION_GET); + + if (!priv->dbus_connection) { + _LOGI ("no D-Bus connection to talk to wpa_supplicant"); + return; + } + + priv->name_owner_changed_id = nm_dbus_connection_signal_subscribe_name_owner_changed (priv->dbus_connection, + NM_WPAS_DBUS_SERVICE, + name_owner_changed_cb, + self, + NULL); + priv->get_name_owner_cancellable = g_cancellable_new (); + nm_dbus_connection_call_get_name_owner (priv->dbus_connection, + NM_WPAS_DBUS_SERVICE, + -1, + priv->get_name_owner_cancellable, + get_name_owner_cb, + self); } static void @@ -586,22 +1325,32 @@ dispose (GObject *object) { NMSupplicantManager *self = (NMSupplicantManager *) object; NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self); - GSList *ifaces; - nm_clear_g_source (&priv->die_count_reset_id); + _supp_iface_remove_all (self, TRUE, "NMSupplicantManager is disposing"); - nm_clear_g_cancellable (&priv->cancellable); + nm_assert (c_list_is_empty (&priv->create_iface_lst_head)); - if (priv->ifaces) { - for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next) - g_object_remove_toggle_ref (ifaces->data, _sup_iface_last_ref, self); - g_slist_free (priv->ifaces); - priv->ifaces = NULL; - } + nm_clear_g_source (&priv->available_reset_id); + + priv->available = NM_TERNARY_FALSE; + nm_clear_pointer (&priv->name_owner, nm_ref_string_unref); + + nm_clear_g_source (&priv->poke_name_owner_timeout_id); + nm_clear_g_cancellable (&priv->poke_name_owner_cancellable); - g_clear_object (&priv->proxy); + nm_clear_g_dbus_connection_signal (priv->dbus_connection, + &priv->interface_removed_id); + nm_clear_g_dbus_connection_signal (priv->dbus_connection, + &priv->name_owner_changed_id); + + nm_clear_g_cancellable (&priv->get_name_owner_cancellable); + nm_clear_g_cancellable (&priv->get_capabilities_cancellable); G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object); + + g_clear_object (&priv->dbus_connection); + + nm_clear_pointer (&priv->supp_ifaces, g_hash_table_destroy); } static void @@ -610,5 +1359,11 @@ nm_supplicant_manager_class_init (NMSupplicantManagerClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = dispose; -} + signals[AVAILABLE_CHANGED] = + g_signal_new (NM_SUPPLICANT_MANAGER_AVAILABLE_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 0); +} diff --git a/src/supplicant/nm-supplicant-manager.h b/src/supplicant/nm-supplicant-manager.h index 18ca53b6..b2b814aa 100644 --- a/src/supplicant/nm-supplicant-manager.h +++ b/src/supplicant/nm-supplicant-manager.h @@ -17,19 +17,49 @@ #define NM_IS_SUPPLICANT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SUPPLICANT_MANAGER)) #define NM_SUPPLICANT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUPPLICANT_MANAGER, NMSupplicantManagerClass)) +#define NM_SUPPLICANT_MANAGER_AVAILABLE_CHANGED "available-changed" + typedef struct _NMSupplicantManagerClass NMSupplicantManagerClass; GType nm_supplicant_manager_get_type (void); NMSupplicantManager *nm_supplicant_manager_get (void); +NMTernary nm_supplicant_manager_is_available (NMSupplicantManager *self); + +GDBusConnection *nm_supplicant_manager_get_dbus_connection (NMSupplicantManager *self); +NMRefString *nm_supplicant_manager_get_dbus_name_owner (NMSupplicantManager *self); +NMSupplCapMask nm_supplicant_manager_get_global_capabilities (NMSupplicantManager *self); + void nm_supplicant_manager_set_wfd_ies (NMSupplicantManager *self, GBytes *wfd_ies); -NMSupplicantInterface *nm_supplicant_manager_create_interface (NMSupplicantManager *mgr, - const char *ifname, - NMSupplicantDriver driver); +typedef struct _NMSupplMgrCreateIfaceHandle NMSupplMgrCreateIfaceHandle; + +typedef void (*NMSupplicantManagerCreateInterfaceCb) (NMSupplicantManager *self, + NMSupplMgrCreateIfaceHandle *handle, + NMSupplicantInterface *iface, + GError *error, + gpointer user_data); + +NMSupplMgrCreateIfaceHandle *nm_supplicant_manager_create_interface (NMSupplicantManager *self, + int ifindex, + NMSupplicantDriver driver, + NMSupplicantManagerCreateInterfaceCb callback, + gpointer user_data); + +void nm_supplicant_manager_create_interface_cancel (NMSupplMgrCreateIfaceHandle *handle); + NMSupplicantInterface *nm_supplicant_manager_create_interface_from_path (NMSupplicantManager *self, const char *object_path); +/*****************************************************************************/ + +void _nm_supplicant_manager_unregister_interface (NMSupplicantManager *self, + NMSupplicantInterface *supp_iface); + +void _nm_supplicant_manager_dbus_call_remove_interface (NMSupplicantManager *self, + const char *name_owner, + const char *iface_path); + #endif /* __NETWORKMANAGER_SUPPLICANT_MANAGER_H__ */ diff --git a/src/supplicant/nm-supplicant-settings-verify.c b/src/supplicant/nm-supplicant-settings-verify.c index bea17ede..58dbd73a 100644 --- a/src/supplicant/nm-supplicant-settings-verify.c +++ b/src/supplicant/nm-supplicant-settings-verify.c @@ -56,7 +56,7 @@ static const char *const key_mgmt_allowed[] = { "WPA-PSK", "WPA-PSK-SHA256", "FT "WPA-EAP", "WPA-EAP-SHA256", "FT-EAP", "FT-EAP-SHA384", "FILS-SHA256", "FILS-SHA384", "IEEE8021X", "SAE", "FT-SAE", - "NONE", NULL }; + "OWE", "NONE", NULL }; static const char *const auth_alg_allowed[] = { "OPEN", "SHARED", "LEAP", NULL }; static const char *const eap_allowed[] = { "LEAP", "MD5", "TLS", "PEAP", "TTLS", "SIM", "PSK", "FAST", "PWD", NULL }; @@ -99,6 +99,7 @@ static const struct Opt opt_table[] = { { "subject_match", TYPE_BYTES, 0, 0, FALSE, NULL }, { "altsubject_match", TYPE_BYTES, 0, 0, FALSE, NULL }, { "domain_suffix_match",TYPE_BYTES, 0, 0, FALSE, NULL }, + { "domain_match", TYPE_BYTES, 0, 0, FALSE, NULL }, { "ca_cert", TYPE_BYTES, 0, 65536, FALSE, NULL }, { "client_cert", TYPE_BYTES, 0, 65536, FALSE, NULL }, { "private_key", TYPE_BYTES, 0, 65536, FALSE, NULL }, @@ -110,6 +111,7 @@ static const struct Opt opt_table[] = { { "subject_match2", TYPE_BYTES, 0, 0, FALSE, NULL }, { "altsubject_match2", TYPE_BYTES, 0, 0, FALSE, NULL }, { "domain_suffix_match2", TYPE_BYTES, 0, 0, FALSE, NULL }, + { "domain_match2", TYPE_BYTES, 0, 0, FALSE, NULL }, { "ca_cert2", TYPE_BYTES, 0, 65536, FALSE, NULL }, { "client_cert2", TYPE_BYTES, 0, 65536, FALSE, NULL }, { "private_key2", TYPE_BYTES, 0, 65536, FALSE, NULL }, diff --git a/src/supplicant/nm-supplicant-types.h b/src/supplicant/nm-supplicant-types.h index 2b356354..734ff156 100644 --- a/src/supplicant/nm-supplicant-types.h +++ b/src/supplicant/nm-supplicant-types.h @@ -6,19 +6,116 @@ #ifndef __NETWORKMANAGER_SUPPLICANT_TYPES_H__ #define __NETWORKMANAGER_SUPPLICANT_TYPES_H__ -#define WPAS_DBUS_SERVICE "fi.w1.wpa_supplicant1" -#define WPAS_DBUS_PATH "/fi/w1/wpa_supplicant1" -#define WPAS_DBUS_INTERFACE "fi.w1.wpa_supplicant1" +#include "c-list/src/c-list.h" + +#define NM_WPAS_DBUS_SERVICE "fi.w1.wpa_supplicant1" +#define NM_WPAS_DBUS_PATH "/fi/w1/wpa_supplicant1" +#define NM_WPAS_DBUS_INTERFACE "fi.w1.wpa_supplicant1" + +#if HAVE_WEXT +#define NM_WPAS_DEFAULT_WIFI_DRIVER "nl80211,wext" +#else +#define NM_WPAS_DEFAULT_WIFI_DRIVER "nl80211" +#endif + +#define NM_WPAS_DBUS_IFACE_INTERFACE NM_WPAS_DBUS_INTERFACE ".Interface" +#define NM_WPAS_DBUS_IFACE_INTERFACE_WPS NM_WPAS_DBUS_INTERFACE ".Interface.WPS" +#define NM_WPAS_DBUS_IFACE_INTERFACE_P2P_DEVICE NM_WPAS_DBUS_INTERFACE ".Interface.P2PDevice" +#define NM_WPAS_DBUS_IFACE_BSS NM_WPAS_DBUS_INTERFACE ".BSS" +#define NM_WPAS_DBUS_IFACE_PEER NM_WPAS_DBUS_INTERFACE ".Peer" +#define NM_WPAS_DBUS_IFACE_GROUP NM_WPAS_DBUS_INTERFACE ".Group" +#define NM_WPAS_DBUS_IFACE_NETWORK NM_WPAS_DBUS_INTERFACE ".Network" +#define NM_WPAS_ERROR_INVALID_IFACE NM_WPAS_DBUS_INTERFACE ".InvalidInterface" +#define NM_WPAS_ERROR_EXISTS_ERROR NM_WPAS_DBUS_INTERFACE ".InterfaceExists" +#define NM_WPAS_ERROR_UNKNOWN_IFACE NM_WPAS_DBUS_INTERFACE ".InterfaceUnknown" typedef struct _NMSupplicantManager NMSupplicantManager; typedef struct _NMSupplicantInterface NMSupplicantInterface; typedef struct _NMSupplicantConfig NMSupplicantConfig; +/*****************************************************************************/ + typedef enum { - NM_SUPPLICANT_FEATURE_UNKNOWN = 0, /* Can't detect whether supported or not */ - NM_SUPPLICANT_FEATURE_NO = 1, /* Feature definitely not supported */ - NM_SUPPLICANT_FEATURE_YES = 2, /* Feature definitely supported */ -} NMSupplicantFeature; + NM_SUPPL_CAP_TYPE_AP, + NM_SUPPL_CAP_TYPE_PMF, + NM_SUPPL_CAP_TYPE_FILS, + NM_SUPPL_CAP_TYPE_P2P, + NM_SUPPL_CAP_TYPE_FT, + NM_SUPPL_CAP_TYPE_SHA384, + NM_SUPPL_CAP_TYPE_MESH, + NM_SUPPL_CAP_TYPE_FAST, + NM_SUPPL_CAP_TYPE_WFD, + _NM_SUPPL_CAP_TYPE_NUM, +} NMSupplCapType; + +#define NM_SUPPL_CAP_MASK_NO(type) ((NMSupplCapMask) (1llu << ((type) * 2u))) +#define NM_SUPPL_CAP_MASK_YES(type) ((NMSupplCapMask) (2llu << ((type) * 2u))) +#define NM_SUPPL_CAP_MASK_MASK(type) ((NMSupplCapMask) (3llu << ((type) * 2u))) + +typedef enum { + NM_SUPPL_CAP_MASK_NONE = 0, + NM_SUPPL_CAP_MASK_ALL = ((1llu << (_NM_SUPPL_CAP_TYPE_NUM * 2)) - 1), + +/* usually it's bad to use macros to define enum values (because you cannot find them with ctags/cscope + * anymore. In this case, still do it because the alternative is ugly too. */ +#define _NM_SUPPL_CAP_MASK_DEFINE(type) \ + NM_SUPPL_CAP_MASK_T_##type##_NO = (1llu << ((NM_SUPPL_CAP_TYPE_##type) * 2u)), \ + NM_SUPPL_CAP_MASK_T_##type##_YES = (2llu << ((NM_SUPPL_CAP_TYPE_##type) * 2u)), \ + NM_SUPPL_CAP_MASK_T_##type##_MASK = (3llu << ((NM_SUPPL_CAP_TYPE_##type) * 2u)) + _NM_SUPPL_CAP_MASK_DEFINE (AP), + _NM_SUPPL_CAP_MASK_DEFINE (FAST), + _NM_SUPPL_CAP_MASK_DEFINE (PMF), + _NM_SUPPL_CAP_MASK_DEFINE (FILS), + _NM_SUPPL_CAP_MASK_DEFINE (P2P), + _NM_SUPPL_CAP_MASK_DEFINE (MESH), + _NM_SUPPL_CAP_MASK_DEFINE (WFD), + _NM_SUPPL_CAP_MASK_DEFINE (FT), + _NM_SUPPL_CAP_MASK_DEFINE (SHA384), +#undef _NM_SUPPL_CAP_MASK_DEFINE +} NMSupplCapMask; + +static inline NMSupplCapMask +NM_SUPPL_CAP_MASK_SET (NMSupplCapMask features, NMSupplCapType type, NMTernary value) +{ + nm_assert (_NM_INT_NOT_NEGATIVE (type)); + nm_assert (type < _NM_SUPPL_CAP_TYPE_NUM); + nm_assert (NM_IN_SET (value, NM_TERNARY_DEFAULT, + NM_TERNARY_TRUE, + NM_TERNARY_FALSE)); + nm_assert (!(features & ~NM_SUPPL_CAP_MASK_ALL)); + + features &= ~NM_SUPPL_CAP_MASK_MASK (type); + switch (value) { + case NM_TERNARY_FALSE: + features |= NM_SUPPL_CAP_MASK_NO (type); + break; + case NM_TERNARY_TRUE: + features |= NM_SUPPL_CAP_MASK_YES (type); + break; + case NM_TERNARY_DEFAULT: + break; + } + + return features; +} + +static inline NMTernary +NM_SUPPL_CAP_MASK_GET (NMSupplCapMask features, NMSupplCapType type) +{ + int f; + + nm_assert (_NM_INT_NOT_NEGATIVE (type)); + nm_assert (type < _NM_SUPPL_CAP_TYPE_NUM); + nm_assert (!(features & ~NM_SUPPL_CAP_MASK_ALL)); + + f = ((int) (features >> (2 * (int) type))) & 0x3; + + nm_assert (NM_IN_SET (f, 0, 1, 2)); + + return (NMTernary) (f - 1); +} + +/*****************************************************************************/ /** * NMSupplicantError: @@ -32,12 +129,76 @@ typedef enum { } NMSupplicantError; typedef enum { + NM_SUPPLICANT_DRIVER_UNKNOWN, NM_SUPPLICANT_DRIVER_WIRELESS, NM_SUPPLICANT_DRIVER_WIRED, NM_SUPPLICANT_DRIVER_MACSEC, } NMSupplicantDriver; +const char *nm_supplicant_driver_to_string (NMSupplicantDriver driver); + #define NM_SUPPLICANT_ERROR (nm_supplicant_error_quark ()) GQuark nm_supplicant_error_quark (void); +typedef struct _NMSupplicantBssInfo { + NMRefString *bss_path; + + NMSupplicantInterface *_self; + CList _bss_lst; + GCancellable *_init_cancellable; + + GBytes *ssid; + + gint64 last_seen_msec; + + NM80211ApSecurityFlags wpa_flags; /* WPA-related flags */ + NM80211ApSecurityFlags rsn_flags; /* RSN (WPA2) -related flags */ + + guint32 frequency; + + guint32 max_rate; + + guint8 signal_percent; + + guint8 bssid[6 /* ETH_ALEN */]; + + NM80211ApFlags ap_flags:5; + + NM80211Mode mode:4; + + bool bssid_valid:1; + + bool metered:1; + + bool _bss_dirty:1; + +} NMSupplicantBssInfo; + +typedef struct _NMSupplicantPeerInfo{ + NMRefString *peer_path; + + CList _peer_lst; + NMSupplicantInterface *_self; + GCancellable *_init_cancellable; + + char *device_name; + char *manufacturer; + char *model; + char *model_number; + char *serial; + + GBytes *ies; + + gint64 last_seen_msec; + + guint8 address[6 /* ETH_ALEN */]; + + gint8 signal_percent; + + bool address_valid:1; + + bool _peer_dirty:1; + +} NMSupplicantPeerInfo; + #endif /* NM_SUPPLICANT_TYPES_H */ diff --git a/src/supplicant/tests/meson.build b/src/supplicant/tests/meson.build index 207d22f8..63012d10 100644 --- a/src/supplicant/tests/meson.build +++ b/src/supplicant/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_unit = 'test-supplicant-config' exe = executable( diff --git a/src/supplicant/tests/test-supplicant-config.c b/src/supplicant/tests/test-supplicant-config.c index 008735b4..f9c71f12 100644 --- a/src/supplicant/tests/test-supplicant-config.c +++ b/src/supplicant/tests/test-supplicant-config.c @@ -86,8 +86,7 @@ static GVariant * build_supplicant_config (NMConnection *connection, guint mtu, guint fixed_freq, - gboolean support_pmf, - gboolean support_fils) + NMSupplCapMask capabilities) { gs_unref_object NMSupplicantConfig *config = NULL; gs_free_error GError *error = NULL; @@ -96,7 +95,7 @@ build_supplicant_config (NMConnection *connection, NMSetting8021x *s_8021x; gboolean success; - config = nm_supplicant_config_new (support_pmf, support_fils, FALSE, FALSE); + config = nm_supplicant_config_new (capabilities); s_wifi = nm_connection_get_setting_wireless (connection); g_assert (s_wifi); @@ -195,7 +194,7 @@ test_wifi_open (void) NMTST_EXPECT_NM_INFO ("Config: added 'bssid' value '11:22:33:44:55:66'*"); NMTST_EXPECT_NM_INFO ("Config: added 'freq_list' value *"); NMTST_EXPECT_NM_INFO ("Config: added 'key_mgmt' value 'NONE'"); - config_dict = build_supplicant_config (connection, 1500, 0, TRUE, TRUE); + config_dict = build_supplicant_config (connection, 1500, 0, NM_SUPPL_CAP_MASK_T_PMF_YES | NM_SUPPL_CAP_MASK_T_FILS_YES); g_test_assert_expected_messages (); g_assert (config_dict); @@ -252,7 +251,7 @@ test_wifi_wep_key (const char *detail, if (!test_bssid) NMTST_EXPECT_NM_INFO ("Config: added 'bgscan' value 'simple:30:-70:86400'*"); - config_dict = build_supplicant_config (connection, 1500, 0, TRUE, TRUE); + config_dict = build_supplicant_config (connection, 1500, 0, NM_SUPPL_CAP_MASK_T_PMF_YES | NM_SUPPL_CAP_MASK_T_FILS_YES); g_test_assert_expected_messages (); g_assert (config_dict); @@ -352,7 +351,7 @@ test_wifi_wpa_psk (const char *detail, default: break; } - config_dict = build_supplicant_config (connection, 1500, 0, TRUE, TRUE); + config_dict = build_supplicant_config (connection, 1500, 0, NM_SUPPL_CAP_MASK_T_PMF_YES | NM_SUPPL_CAP_MASK_T_FILS_YES); g_test_assert_expected_messages (); g_assert (config_dict); @@ -416,7 +415,7 @@ test_wifi_sae_psk (const char *psk) NMTST_EXPECT_NM_INFO ("Config: added 'proto' value 'RSN'"); NMTST_EXPECT_NM_INFO ("Config: added 'pairwise' value 'TKIP CCMP'"); NMTST_EXPECT_NM_INFO ("Config: added 'group' value 'TKIP CCMP'"); - config_dict = build_supplicant_config (connection, 1500, 0, TRUE, TRUE); + config_dict = build_supplicant_config (connection, 1500, 0, NM_SUPPL_CAP_MASK_T_PMF_YES | NM_SUPPL_CAP_MASK_T_FILS_YES); g_test_assert_expected_messages (); g_assert (config_dict); @@ -524,7 +523,7 @@ test_wifi_eap_locked_bssid (void) NMTST_EXPECT_NM_INFO ("Config: added 'ca_cert' value '*/test-ca-cert.pem'"); NMTST_EXPECT_NM_INFO ("Config: added 'private_key' value '*/test-cert.p12'"); NMTST_EXPECT_NM_INFO ("Config: added 'proactive_key_caching' value '1'"); - config_dict = build_supplicant_config (connection, mtu, 0, FALSE, FALSE); + config_dict = build_supplicant_config (connection, mtu, 0, NM_SUPPL_CAP_MASK_NONE); g_test_assert_expected_messages (); g_assert (config_dict); @@ -565,7 +564,7 @@ test_wifi_eap_unlocked_bssid (void) NMTST_EXPECT_NM_INFO ("Config: added 'private_key' value '*/test-cert.p12'"); NMTST_EXPECT_NM_INFO ("Config: added 'proactive_key_caching' value '1'"); NMTST_EXPECT_NM_INFO ("Config: added 'bgscan' value 'simple:30:-65:300'"); - config_dict = build_supplicant_config (connection, mtu, 0, FALSE, TRUE); + config_dict = build_supplicant_config (connection, mtu, 0, NM_SUPPL_CAP_MASK_T_FILS_YES); g_test_assert_expected_messages (); g_assert (config_dict); @@ -606,7 +605,7 @@ test_wifi_eap_fils_disabled (void) NMTST_EXPECT_NM_INFO ("Config: added 'private_key' value '*/test-cert.p12'"); NMTST_EXPECT_NM_INFO ("Config: added 'proactive_key_caching' value '1'"); NMTST_EXPECT_NM_INFO ("Config: added 'bgscan' value 'simple:30:-65:300'"); - config_dict = build_supplicant_config (connection, mtu, 0, TRUE, TRUE); + config_dict = build_supplicant_config (connection, mtu, 0, NM_SUPPL_CAP_MASK_T_PMF_YES | NM_SUPPL_CAP_MASK_T_FILS_YES); g_test_assert_expected_messages (); g_assert (config_dict); @@ -621,6 +620,44 @@ test_wifi_eap_fils_disabled (void) validate_opt ("wifi-eap", config_dict, "bgscan", TYPE_BYTES, bgscan); } +/*****************************************************************************/ + +static void +test_suppl_cap_mask (void) +{ + NMSupplCapType type; + + g_assert_cmpint (NM_SUPPL_CAP_MASK_GET (NM_SUPPL_CAP_MASK_T_AP_NO, NM_SUPPL_CAP_TYPE_AP), ==, NM_TERNARY_FALSE); + g_assert_cmpint (NM_SUPPL_CAP_MASK_GET (NM_SUPPL_CAP_MASK_T_AP_YES, NM_SUPPL_CAP_TYPE_AP), ==, NM_TERNARY_TRUE); + g_assert_cmpint (NM_SUPPL_CAP_MASK_GET (NM_SUPPL_CAP_MASK_NONE, NM_SUPPL_CAP_TYPE_AP), ==, NM_TERNARY_DEFAULT); + + g_assert_cmpint (NM_SUPPL_CAP_MASK_GET (NM_SUPPL_CAP_MASK_T_FILS_NO, NM_SUPPL_CAP_TYPE_FILS), ==, NM_TERNARY_FALSE); + g_assert_cmpint (NM_SUPPL_CAP_MASK_GET (NM_SUPPL_CAP_MASK_T_FILS_YES, NM_SUPPL_CAP_TYPE_FILS), ==, NM_TERNARY_TRUE); + g_assert_cmpint (NM_SUPPL_CAP_MASK_GET (NM_SUPPL_CAP_MASK_NONE, NM_SUPPL_CAP_TYPE_FILS), ==, NM_TERNARY_DEFAULT); + + for (type = 0; type < _NM_SUPPL_CAP_TYPE_NUM; type++) { + NMTernary value; + NMSupplCapMask feature; + NMSupplCapMask feature2; + + feature = nmtst_get_rand_bool () + ? 0u + : nmtst_get_rand_uint64 (); + feature &= NM_SUPPL_CAP_MASK_ALL; + + value = nmtst_rand_select (NM_TERNARY_DEFAULT, + NM_TERNARY_FALSE, + NM_TERNARY_TRUE); + + feature2 = NM_SUPPL_CAP_MASK_SET (feature, type, value); + + g_assert_cmpint (NM_SUPPL_CAP_MASK_GET (feature2, type), ==, value); + g_assert_cmpint (feature & ~NM_SUPPL_CAP_MASK_MASK (type), ==, feature2 & ~NM_SUPPL_CAP_MASK_MASK (type)); + } +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -634,6 +671,7 @@ int main (int argc, char **argv) g_test_add_func ("/supplicant-config/wifi-eap/unlocked-bssid", test_wifi_eap_unlocked_bssid); g_test_add_func ("/supplicant-config/wifi-eap/fils-disabled", test_wifi_eap_fils_disabled); g_test_add_func ("/supplicant-config/wifi-sae", test_wifi_sae); + g_test_add_func ("/supplicant-config/test_suppl_cap_mask", test_suppl_cap_mask); return g_test_run (); } diff --git a/src/systemd/meson.build b/src/systemd/meson.build index 5c4fa3e2..9b87d772 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + sources = files( 'src/libsystemd-network/arp-util.c', 'src/libsystemd-network/dhcp-identifier.c', diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h index a2d0f8bd..5cbebb4a 100644 --- a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -61,6 +61,12 @@ struct sd_dhcp_lease { struct in_addr *sip; size_t sip_size; + struct in_addr *pop3_server; + size_t pop3_server_size; + + struct in_addr *smtp_server; + size_t smtp_server_size; + struct sd_dhcp_route *static_route; size_t static_route_size, static_route_allocated; diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 7d22e754..94a6236a 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -10,6 +10,7 @@ #include "sd-ndisc.h" #include "alloc-util.h" +#include "arphrd-list.h" #include "condition.h" #include "conf-parser.h" #include "device-util.h" @@ -106,6 +107,18 @@ static bool net_condition_test_strv(char * const *patterns, const char *string) return has_positive_rule ? match : true; } +static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) { + if (net_condition_test_strv(patterns, ifname)) + return true; + + char * const *p; + STRV_FOREACH(p, alternative_names) + if (net_condition_test_strv(patterns, *p)) + return true; + + return false; +} + static int net_condition_test_property(char * const *match_property, sd_device *device) { char * const *p; @@ -157,7 +170,29 @@ static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype); +char *link_get_type_string(unsigned short iftype, sd_device *device) { + const char *t, *devtype; + char *p; + + if (device && + sd_device_get_devtype(device, &devtype) >= 0 && + !isempty(devtype)) + return strdup(devtype); + + t = arphrd_to_name(iftype); + if (!t) + return NULL; + + p = strdup(t); + if (!p) + return NULL; + + ascii_strlower(p); + return p; +} + bool net_match_config(Set *match_mac, + Set *match_permanent_mac, char * const *match_paths, char * const *match_drivers, char * const *match_types, @@ -166,20 +201,24 @@ bool net_match_config(Set *match_mac, char * const *match_wifi_iftype, char * const *match_ssid, Set *match_bssid, + unsigned short iftype, sd_device *device, const struct ether_addr *dev_mac, + const struct ether_addr *dev_permanent_mac, const char *dev_name, + char * const *alternative_names, enum nl80211_iftype wifi_iftype, const char *ssid, const struct ether_addr *bssid) { - const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str; + const char *dev_path = NULL, *dev_driver = NULL, *mac_str; + _cleanup_free_ char *dev_type; + + dev_type = link_get_type_string(iftype, device); if (device) { (void) sd_device_get_property_value(device, "ID_PATH", &dev_path); (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver); - (void) sd_device_get_devtype(device, &dev_type); - if (!dev_name) (void) sd_device_get_sysname(device, &dev_name); if (!dev_mac && @@ -190,6 +229,12 @@ bool net_match_config(Set *match_mac, if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac))) return false; + if (match_permanent_mac && + (!dev_permanent_mac || + ether_addr_is_null(dev_permanent_mac) || + !set_contains(match_permanent_mac, dev_permanent_mac))) + return false; + if (!net_condition_test_strv(match_paths, dev_path)) return false; @@ -199,7 +244,7 @@ bool net_match_config(Set *match_mac, if (!net_condition_test_strv(match_types, dev_type)) return false; - if (!net_condition_test_strv(match_names, dev_name)) + if (!net_condition_test_ifname(match_names, dev_name, alternative_names)) return false; if (!net_condition_test_property(match_property, device)) @@ -352,7 +397,7 @@ int config_parse_match_ifnames( return 0; } - if (!ifname_valid(word)) { + if (!ifname_valid_full(word, ltype)) { log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", word); continue; diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h index 2eb0cba5..6724cbbf 100644 --- a/src/systemd/src/libsystemd-network/network-internal.h +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -8,7 +8,6 @@ #include "sd-dhcp-lease.h" #include "conf-parser.h" -#include "def.h" #include "set.h" #include "strv.h" @@ -17,6 +16,7 @@ #if 0 /* NM_IGNORED */ bool net_match_config(Set *match_mac, + Set *match_permanent_mac, char * const *match_path, char * const *match_driver, char * const *match_type, @@ -25,9 +25,12 @@ bool net_match_config(Set *match_mac, char * const *match_wifi_iftype, char * const *match_ssid, Set *match_bssid, + unsigned short iftype, sd_device *device, const struct ether_addr *dev_mac, + const struct ether_addr *dev_permanent_mac, const char *dev_name, + char * const *alternative_names, enum nl80211_iftype wifi_iftype, const char *ssid, const struct ether_addr *bssid); @@ -63,5 +66,3 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); - -#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network")) diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index 0266161d..63321cca 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -29,6 +29,7 @@ #include "random-util.h" #include "string-util.h" #include "strv.h" +#include "web-util.h" #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) @@ -85,13 +86,15 @@ struct sd_dhcp_client { size_t client_id_len; char *hostname; char *vendor_class_identifier; + char *mudurl; char **user_class; uint32_t mtu; uint32_t xid; usec_t start_time; uint64_t attempt; uint64_t max_attempts; - OrderedHashmap *options; + OrderedHashmap *extra_options; + OrderedHashmap *vendor_options; usec_t request_sent; sd_event_source *timeout_t1; sd_event_source *timeout_t2; @@ -497,6 +500,18 @@ int sd_dhcp_client_set_vendor_class_identifier( return free_and_strdup(&client->vendor_class_identifier, vci); } +int sd_dhcp_client_set_mud_url( + sd_dhcp_client *client, + const char *mudurl) { + + assert_return(client, -EINVAL); + assert_return(mudurl, -EINVAL); + assert_return(strlen(mudurl) <= 255, -EINVAL); + assert_return(http_url_is_valid(mudurl), -EINVAL); + + return free_and_strdup(&client->mudurl, mudurl); +} + int sd_dhcp_client_set_user_class( sd_dhcp_client *client, const char* const* user_class) { @@ -545,17 +560,17 @@ int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempt return 0; } -int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) { +int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) { int r; assert_return(client, -EINVAL); assert_return(v, -EINVAL); - r = ordered_hashmap_ensure_allocated(&client->options, &dhcp_option_hash_ops); + r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp_option_hash_ops); if (r < 0) return r; - r = ordered_hashmap_put(client->options, UINT_TO_PTR(v->option), v); + r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v); if (r < 0) return r; @@ -563,6 +578,25 @@ int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v) { return 0; } +int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) { + int r; + + assert_return(client, -EINVAL); + assert_return(v, -EINVAL); + + r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops); + if (r < 0) + return -ENOMEM; + + r = ordered_hashmap_put(client->vendor_options, v, v); + if (r < 0) + return r; + + sd_dhcp_option_ref(v); + + return 1; +} + int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { assert_return(client, -EINVAL); @@ -648,7 +682,7 @@ static int client_message_init( assert(ret); assert(_optlen); assert(_optoffset); - assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE)); + assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE)); optlen = DHCP_MIN_OPTIONS_SIZE; size = sizeof(DHCPPacket) + optlen; @@ -880,6 +914,15 @@ static int client_send_discover(sd_dhcp_client *client) { return r; } + if (client->mudurl) { + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_MUD_URL, + strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + if (client->user_class) { r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_USER_CLASS, @@ -889,13 +932,22 @@ static int client_send_discover(sd_dhcp_client *client) { return r; } - ORDERED_HASHMAP_FOREACH(j, client->options, i) { + ORDERED_HASHMAP_FOREACH(j, client->extra_options, i) { r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, j->option, j->length, j->data); if (r < 0) return r; } + if (!ordered_hashmap_isempty(client->vendor_options)) { + r = dhcp_option_append( + &discover->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_VENDOR_SPECIFIC, + ordered_hashmap_size(client->vendor_options), client->vendor_options); + if (r < 0) + return r; + } + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) @@ -1008,6 +1060,16 @@ static int client_send_request(sd_dhcp_client *client) { return r; } + if (client->mudurl) { + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_MUD_URL, + strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) @@ -1971,6 +2033,48 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) { return 0; } +int sd_dhcp_client_send_decline(sd_dhcp_client *client) { + assert_return(client, -EINVAL); + assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE); + assert_return(client->lease, -EUNATCH); + + _cleanup_free_ DHCPPacket *release = NULL; + size_t optoffset, optlen; + int r; + + r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset); + if (r < 0) + return r; + + release->dhcp.ciaddr = client->lease->address; + memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); + + r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; + + r = dhcp_network_send_udp_socket(client->fd, + client->lease->server_address, + DHCP_PORT_SERVER, + &release->dhcp, + sizeof(DHCPMessage) + optoffset); + if (r < 0) + return r; + + log_dhcp_client(client, "DECLINE"); + + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + + if (client->state != DHCP_STATE_STOPPED) { + r = sd_dhcp_client_start(client); + if (r < 0) + return r; + } + + return 0; +} + int sd_dhcp_client_stop(sd_dhcp_client *client) { DHCP_CLIENT_DONT_DESTROY(client); @@ -2035,8 +2139,10 @@ static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { free(client->req_opts); free(client->hostname); free(client->vendor_class_identifier); + free(client->mudurl); client->user_class = strv_free(client->user_class); - ordered_hashmap_free(client->options); + ordered_hashmap_free(client->extra_options); + ordered_hashmap_free(client->vendor_options); return mfree(client); } diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index ac6fe3f4..86f21290 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -131,6 +131,28 @@ int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) { return (int) lease->sip_size; } +int sd_dhcp_lease_get_pop3_server(sd_dhcp_lease *lease, const struct in_addr **addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->pop3_server_size <= 0) + return -ENODATA; + + *addr = lease->pop3_server; + return (int) lease->pop3_server_size; +} + +int sd_dhcp_lease_get_smtp_server(sd_dhcp_lease *lease, const struct in_addr **addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->smtp_server_size <= 0) + return -ENODATA; + + *addr = lease->smtp_server; + return (int) lease->smtp_server_size; +} + int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { assert_return(lease, -EINVAL); assert_return(domainname, -EINVAL); @@ -281,6 +303,8 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { free(lease->dns); free(lease->ntp); free(lease->sip); + free(lease->pop3_server); + free(lease->smtp_server); free(lease->static_route); free(lease->client_id); free(lease->vendor_specific); @@ -603,6 +627,18 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void log_debug_errno(r, "Failed to parse SIP server, ignoring: %m"); break; + case SD_DHCP_OPTION_POP3_SERVER: + r = lease_parse_in_addrs(option, len, &lease->pop3_server, &lease->pop3_server_size); + if (r < 0) + log_debug_errno(r, "Failed to parse POP3 server, ignoring: %m"); + break; + + case SD_DHCP_OPTION_SMTP_SERVER: + r = lease_parse_in_addrs(option, len, &lease->smtp_server, &lease->smtp_server_size); + if (r < 0) + log_debug_errno(r, "Failed to parse SMTP server, ignoring: %m"); + break; + case SD_DHCP_OPTION_STATIC_ROUTE: r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated); if (r < 0) @@ -1039,6 +1075,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { *dns = NULL, *ntp = NULL, *sip = NULL, + *pop3_server = NULL, + *smtp_server = NULL, *mtu = NULL, *routes = NULL, *domains = NULL, @@ -1068,6 +1106,8 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { "DNS", &dns, "NTP", &ntp, "SIP", &sip, + "POP3_SERVERS", &pop3_server, + "SMTP_SERVERS", &smtp_server, "MTU", &mtu, "DOMAINNAME", &lease->domainname, "HOSTNAME", &lease->hostname, @@ -1177,7 +1217,23 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (r < 0) log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip); else - lease->ntp_size = r; + lease->sip_size = r; + } + + if (pop3_server) { + r = deserialize_in_addrs(&lease->pop3_server, pop3_server); + if (r < 0) + log_debug_errno(r, "Failed to deserialize POP3 server %s, ignoring: %m", pop3_server); + else + lease->pop3_server_size = r; + } + + if (smtp_server) { + r = deserialize_in_addrs(&lease->smtp_server, smtp_server); + if (r < 0) + log_debug_errno(r, "Failed to deserialize SMTP server %s, ignoring: %m", smtp_server); + else + lease->smtp_server_size = r; } if (mtu) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index e1150f98..826ad56a 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -27,6 +27,7 @@ #include "socket-util.h" #include "string-table.h" #include "util.h" +#include "web-util.h" #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN @@ -67,6 +68,7 @@ struct sd_dhcp6_client { size_t req_opts_allocated; size_t req_opts_len; char *fqdn; + char *mudurl; sd_event_source *receive_message; usec_t retransmit_time; uint8_t retransmit_count; @@ -369,6 +371,17 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) return 0; } +int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, char *mudurl) { + + assert_return(client, -EINVAL); + assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); + assert_return(mudurl, -EINVAL); + assert_return(strlen(mudurl) <= 255, -EINVAL); + assert_return(http_url_is_valid(mudurl), -EINVAL); + + return free_and_strdup(&client->mudurl, mudurl); +} + int sd_dhcp6_client_get_prefix_delegation(sd_dhcp6_client *client, int *delegation) { assert_return(client, -EINVAL); assert_return(delegation, -EINVAL); @@ -490,6 +503,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { case DHCP6_STATE_INFORMATION_REQUEST: message->type = DHCP6_INFORMATION_REQUEST; + if (client->mudurl) { + r = dhcp6_option_append(&opt, &optlen, + SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + break; case DHCP6_STATE_SOLICITATION: @@ -513,6 +534,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } + if (client->mudurl) { + r = dhcp6_option_append(&opt, &optlen, + SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix); if (r < 0) @@ -551,6 +580,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } + if (client->mudurl) { + r = dhcp6_option_append(&opt, &optlen, + SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); if (r < 0) @@ -577,6 +614,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return r; } + if (client->mudurl) { + r = dhcp6_option_append(&opt, &optlen, + SD_DHCP6_OPTION_MUD_URL, strlen(client->mudurl), + client->mudurl); + if (r < 0) + return r; + } + if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); if (r < 0) @@ -681,8 +726,7 @@ static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void } static usec_t client_timeout_compute_random(usec_t val) { - return val - val / 10 + - (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC; + return val - (random_u32() % USEC_PER_SEC) * val / 10 / USEC_PER_SEC; } static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) { @@ -692,7 +736,6 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda usec_t max_retransmit_duration = 0; uint8_t max_retransmit_count = 0; char time_string[FORMAT_TIMESPAN_MAX]; - uint32_t expire = 0; assert(s); assert(client); @@ -741,8 +784,9 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda max_retransmit_time = DHCP6_REB_MAX_RT; if (event_source_is_enabled(client->timeout_resend_expire) <= 0) { - r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, - &expire); + uint32_t expire = 0; + + r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, &expire); if (r < 0) { client_stop(client, r); return 0; @@ -757,7 +801,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda return 0; } - if (max_retransmit_count && + if (max_retransmit_count > 0 && client->retransmit_count >= max_retransmit_count) { client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX); return 0; @@ -771,7 +815,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda if (r >= 0) client->retransmit_count++; - if (!client->retransmit_time) { + if (client->retransmit_time == 0) { client->retransmit_time = client_timeout_compute_random(init_retransmit_time); @@ -779,7 +823,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda client->retransmit_time += init_retransmit_time / 10; } else { - if (max_retransmit_time && + if (max_retransmit_time > 0 && client->retransmit_time > max_retransmit_time / 2) client->retransmit_time = client_timeout_compute_random(max_retransmit_time); else @@ -797,7 +841,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userda if (r < 0) goto error; - if (max_retransmit_duration && event_source_is_enabled(client->timeout_resend_expire) <= 0) { + if (max_retransmit_duration > 0 && event_source_is_enabled(client->timeout_resend_expire) <= 0) { log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs", max_retransmit_duration / USEC_PER_SEC); @@ -1528,6 +1572,7 @@ static sd_dhcp6_client *dhcp6_client_free(sd_dhcp6_client *client) { free(client->req_opts); free(client->fqdn); + free(client->mudurl); return mfree(client); } diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 3efa8170..9f69088d 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -443,7 +443,7 @@ int sd_ipv4acd_is_running(sd_ipv4acd *acd) { return acd->state != IPV4ACD_STATE_INIT; } -int sd_ipv4acd_start(sd_ipv4acd *acd) { +int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts) { int r; assert_return(acd, -EINVAL); @@ -460,7 +460,9 @@ int sd_ipv4acd_start(sd_ipv4acd *acd) { safe_close(acd->fd); acd->fd = r; acd->defend_window = 0; - acd->n_conflict = 0; + + if (reset_conflicts) + acd->n_conflict = 0; r = sd_event_add_io(acd->event, &acd->receive_message_event_source, acd->fd, EPOLLIN, ipv4acd_on_packet, acd); if (r < 0) diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index 2d17b4fe..a610546c 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -243,7 +243,7 @@ static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) { picked_address = true; } - r = sd_ipv4acd_start(ll->acd); + r = sd_ipv4acd_start(ll->acd, reset_generation); if (r < 0) { /* We couldn't start? If so, let's forget the picked address again, the user might make a change and diff --git a/src/systemd/src/libsystemd/sd-event/event-source.h b/src/systemd/src/libsystemd/sd-event/event-source.h index 99ab8fc1..08eb9b6a 100644 --- a/src/systemd/src/libsystemd/sd-event/event-source.h +++ b/src/systemd/src/libsystemd/sd-event/event-source.h @@ -34,7 +34,7 @@ typedef enum EventSourceType { * we know how to dispatch it */ typedef enum WakeupType { WAKEUP_NONE, - WAKEUP_EVENT_SOURCE, + WAKEUP_EVENT_SOURCE, /* either I/O or pidfd wakeup */ WAKEUP_CLOCK_DATA, WAKEUP_SIGNAL_DATA, WAKEUP_INOTIFY_DATA, @@ -96,6 +96,12 @@ struct sd_event_source { siginfo_t siginfo; pid_t pid; int options; + int pidfd; + bool registered:1; /* whether the pidfd is registered in the epoll */ + bool pidfd_owned:1; /* close pidfd when event source is freed */ + bool process_owned:1; /* kill+reap process when event source is freed */ + bool exited:1; /* true if process exited (i.e. if there's value in SIGKILLing it if we want to get rid of it) */ + bool waited:1; /* true if process was waited for (i.e. if there's value in waitid(P_PID)'ing it if we want to get rid of it) */ } child; struct { sd_event_handler_t callback; diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 7c4566e3..3e56e807 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -11,6 +11,7 @@ #include "sd-id128.h" #include "alloc-util.h" +#include "env-util.h" #include "event-source.h" #include "fd-util.h" #include "fs-util.h" @@ -30,6 +31,14 @@ #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) +static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) { + /* Returns true if this is a PID event source and can be implemented by watching EPOLLIN */ + return s && + s->type == SOURCE_CHILD && + s->child.pidfd >= 0 && + s->child.options == WEXITED; +} + static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { [SOURCE_IO] = "io", [SOURCE_TIME_REALTIME] = "realtime", @@ -108,6 +117,9 @@ struct sd_event { unsigned n_sources; + struct epoll_event *event_queue; + size_t event_queue_allocated; + LIST_HEAD(sd_event_source, sources); usec_t last_run, last_log; @@ -279,6 +291,8 @@ static sd_event *event_free(sd_event *e) { hashmap_free(e->child_sources); set_free(e->post_sources); + free(e->event_queue); + return mfree(e); } @@ -358,8 +372,6 @@ static bool event_pid_changed(sd_event *e) { } static void source_io_unregister(sd_event_source *s) { - int r; - assert(s); assert(s->type == SOURCE_IO); @@ -369,8 +381,7 @@ static void source_io_unregister(sd_event_source *s) { if (!s->io.registered) return; - r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); - if (r < 0) + if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0) log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", strna(s->description), event_source_type_to_string(s->type)); @@ -382,22 +393,20 @@ static int source_io_register( int enabled, uint32_t events) { - struct epoll_event ev; - int r; - assert(s); assert(s->type == SOURCE_IO); assert(enabled != SD_EVENT_OFF); - ev = (struct epoll_event) { + struct epoll_event ev = { .events = events | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0), .data.ptr = s, }; + int r; - if (s->io.registered) - r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->io.fd, &ev); - else - r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->io.fd, &ev); + r = epoll_ctl(s->event->epoll_fd, + s->io.registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, + s->io.fd, + &ev); if (r < 0) return -errno; @@ -406,6 +415,49 @@ static int source_io_register( return 0; } +static void source_child_pidfd_unregister(sd_event_source *s) { + assert(s); + assert(s->type == SOURCE_CHILD); + + if (event_pid_changed(s->event)) + return; + + if (!s->child.registered) + return; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) + if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0) + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + strna(s->description), event_source_type_to_string(s->type)); + + s->child.registered = false; +} + +static int source_child_pidfd_register(sd_event_source *s, int enabled) { + int r; + + assert(s); + assert(s->type == SOURCE_CHILD); + assert(enabled != SD_EVENT_OFF); + + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + struct epoll_event ev = { + .events = EPOLLIN | (enabled == SD_EVENT_ONESHOT ? EPOLLONESHOT : 0), + .data.ptr = s, + }; + + if (s->child.registered) + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_MOD, s->child.pidfd, &ev); + else + r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_ADD, s->child.pidfd, &ev); + if (r < 0) + return -errno; + } + + s->child.registered = true; + return 0; +} + static clockid_t event_source_type_to_clock(EventSourceType t) { switch (t) { @@ -495,7 +547,6 @@ static int event_make_signal_data( int sig, struct signal_data **ret) { - struct epoll_event ev; struct signal_data *d; bool added = false; sigset_t ss_copy; @@ -562,7 +613,7 @@ static int event_make_signal_data( d->fd = fd_move_above_stdio(r); - ev = (struct epoll_event) { + struct epoll_event ev = { .events = EPOLLIN, .data.ptr = d, }; @@ -616,9 +667,8 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) assert(e); - /* Rechecks if the specified signal is still something we are - * interested in. If not, we'll unmask it, and possibly drop - * the signalfd for it. */ + /* Rechecks if the specified signal is still something we are interested in. If not, we'll unmask it, + * and possibly drop the signalfd for it. */ if (sig == SIGCHLD && e->n_enabled_child_sources > 0) @@ -709,9 +759,13 @@ static void source_disconnect(sd_event_source *s) { } (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); - event_gc_signal_data(s->event, &s->priority, SIGCHLD); } + if (EVENT_SOURCE_WATCH_PIDFD(s)) + source_child_pidfd_unregister(s); + else + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; case SOURCE_DEFER: @@ -771,9 +825,7 @@ static void source_disconnect(sd_event_source *s) { if (s->prepare) prioq_remove(s->event->prepare, s, &s->prepare_index); - event = s->event; - - s->event = NULL; + event = TAKE_PTR(s->event); LIST_REMOVE(sources, event->sources, s); event->n_sources--; @@ -792,6 +844,44 @@ static void source_free(sd_event_source *s) { if (s->type == SOURCE_IO && s->io.owned) s->io.fd = safe_close(s->io.fd); + if (s->type == SOURCE_CHILD) { + /* Eventually the kernel will do this automatically for us, but for now let's emulate this (unreliably) in userspace. */ + + if (s->child.process_owned) { + + if (!s->child.exited) { + bool sent = false; + + if (s->child.pidfd >= 0) { + if (pidfd_send_signal(s->child.pidfd, SIGKILL, NULL, 0) < 0) { + if (errno == ESRCH) /* Already dead */ + sent = true; + else if (!ERRNO_IS_NOT_SUPPORTED(errno)) + log_debug_errno(errno, "Failed to kill process " PID_FMT " via pidfd_send_signal(), re-trying via kill(): %m", + s->child.pid); + } else + sent = true; + } + + if (!sent) + if (kill(s->child.pid, SIGKILL) < 0) + if (errno != ESRCH) /* Already dead */ + log_debug_errno(errno, "Failed to kill process " PID_FMT " via kill(), ignoring: %m", + s->child.pid); + } + + if (!s->child.waited) { + siginfo_t si = {}; + + /* Reap the child if we can */ + (void) waitid(P_PID, s->child.pid, &si, WEXITED); + } + } + + if (s->child.pidfd_owned) + s->child.pidfd = safe_close(s->child.pidfd); + } + if (s->destroy_callback) s->destroy_callback(s->userdata); @@ -949,33 +1039,31 @@ static int event_setup_timer_fd( struct clock_data *d, clockid_t clock) { - struct epoll_event ev; - int r, fd; - assert(e); assert(d); if (_likely_(d->fd >= 0)) return 0; + _cleanup_close_ int fd = -1; + int r; + fd = timerfd_create(clock, TFD_NONBLOCK|TFD_CLOEXEC); if (fd < 0) return -errno; fd = fd_move_above_stdio(fd); - ev = (struct epoll_event) { + struct epoll_event ev = { .events = EPOLLIN, .data.ptr = d, }; r = epoll_ctl(e->epoll_fd, EPOLL_CTL_ADD, fd, &ev); - if (r < 0) { - safe_close(fd); + if (r < 0) return -errno; - } - d->fd = fd; + d->fd = TAKE_FD(fd); return 0; } @@ -1076,7 +1164,6 @@ _public_ int sd_event_add_signal( _cleanup_(source_freep) sd_event_source *s = NULL; struct signal_data *d; - sigset_t ss; int r; assert_return(e, -EINVAL); @@ -1088,11 +1175,10 @@ _public_ int sd_event_add_signal( if (!callback) callback = signal_exit_callback; - r = pthread_sigmask(SIG_SETMASK, NULL, &ss); - if (r != 0) - return -r; - - if (!sigismember(&ss, sig)) + r = signal_is_blocked(sig); + if (r < 0) + return r; + if (r == 0) return -EBUSY; if (!e->signal_sources) { @@ -1126,7 +1212,11 @@ _public_ int sd_event_add_signal( return 0; } -#endif /* NM_IGNORED */ + +static bool shall_use_pidfd(void) { + /* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */ + return getenv_bool_secure("SYSTEMD_PIDFD") != 0; +} _public_ int sd_event_add_child( sd_event *e, @@ -1148,6 +1238,20 @@ _public_ int sd_event_add_child( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); + if (e->n_enabled_child_sources == 0) { + /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available, + * for compatibility with pre-pidfd and because we don't want the reap the child processes + * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to + * take effect. + * + * (As an optimization we only do this check on the first child event source created.) */ + r = signal_is_blocked(SIGCHLD); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + } + r = hashmap_ensure_allocated(&e->child_sources, NULL); if (r < 0) return r; @@ -1159,32 +1263,147 @@ _public_ int sd_event_add_child( if (!s) return -ENOMEM; + s->wakeup = WAKEUP_EVENT_SOURCE; s->child.pid = pid; s->child.options = options; s->child.callback = callback; s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; + /* We always take a pidfd here if we can, even if we wait for anything else than WEXITED, so that we + * pin the PID, and make regular waitid() handling race-free. */ + + if (shall_use_pidfd()) { + s->child.pidfd = pidfd_open(s->child.pid, 0); + if (s->child.pidfd < 0) { + /* Propagate errors unless the syscall is not supported or blocked */ + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + } else + s->child.pidfd_owned = true; /* If we allocate the pidfd we own it by default */ + } else + s->child.pidfd = -1; + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); if (r < 0) return r; e->n_enabled_child_sources++; - r = event_make_signal_data(e, SIGCHLD, NULL); - if (r < 0) { - e->n_enabled_child_sources--; - return r; - } + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* We have a pidfd and we only want to watch for exit */ - e->need_process_child = true; + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + } else { + /* We have no pidfd or we shall wait for some other event than WEXITED */ + + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + + e->need_process_child = true; + } if (ret) *ret = s; + TAKE_PTR(s); + return 0; +} + +_public_ int sd_event_add_child_pidfd( + sd_event *e, + sd_event_source **ret, + int pidfd, + int options, + sd_event_child_handler_t callback, + void *userdata) { + + + _cleanup_(source_freep) sd_event_source *s = NULL; + pid_t pid; + int r; + + assert_return(e, -EINVAL); + assert_return(e = event_resolve(e), -ENOPKG); + assert_return(pidfd >= 0, -EBADF); + assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL); + assert_return(options != 0, -EINVAL); + assert_return(callback, -EINVAL); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(!event_pid_changed(e), -ECHILD); + + if (e->n_enabled_child_sources == 0) { + r = signal_is_blocked(SIGCHLD); + if (r < 0) + return r; + if (r == 0) + return -EBUSY; + } + + r = hashmap_ensure_allocated(&e->child_sources, NULL); + if (r < 0) + return r; + + r = pidfd_get_pid(pidfd, &pid); + if (r < 0) + return r; + + if (hashmap_contains(e->child_sources, PID_TO_PTR(pid))) + return -EBUSY; + + s = source_new(e, !ret, SOURCE_CHILD); + if (!s) + return -ENOMEM; + + s->wakeup = WAKEUP_EVENT_SOURCE; + s->child.pidfd = pidfd; + s->child.pid = pid; + s->child.options = options; + s->child.callback = callback; + s->child.pidfd_owned = false; /* If we got the pidfd passed in we don't own it by default (similar to the IO fd case) */ + s->userdata = userdata; + s->enabled = SD_EVENT_ONESHOT; + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); + if (r < 0) + return r; + + e->n_enabled_child_sources++; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* We only want to watch for WEXITED */ + + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + } else { + /* We shall wait for some other event than WEXITED */ + + r = event_make_signal_data(e, SIGCHLD, NULL); + if (r < 0) { + e->n_enabled_child_sources--; + return r; + } + + e->need_process_child = true; + } + + if (ret) + *ret = s; + + TAKE_PTR(s); return 0; } +#endif /* NM_IGNORED */ _public_ int sd_event_add_defer( sd_event *e, @@ -1330,7 +1549,6 @@ static int event_make_inotify_data( _cleanup_close_ int fd = -1; struct inotify_data *d; - struct epoll_event ev; int r; assert(e); @@ -1369,7 +1587,7 @@ static int event_make_inotify_data( return r; } - ev = (struct epoll_event) { + struct epoll_event ev = { .events = EPOLLIN, .data.ptr = d, }; @@ -1769,7 +1987,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { return r; } - epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL); + (void) epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, saved_fd, NULL); } return 0; @@ -2030,7 +2248,11 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { assert(s->event->n_enabled_child_sources > 0); s->event->n_enabled_child_sources--; - event_gc_signal_data(s->event, &s->priority, SIGCHLD); + if (EVENT_SOURCE_WATCH_PIDFD(s)) + source_child_pidfd_unregister(s); + else + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + break; case SOURCE_EXIT: @@ -2104,12 +2326,25 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { s->enabled = m; - r = event_make_signal_data(s->event, SIGCHLD, NULL); - if (r < 0) { - s->enabled = SD_EVENT_OFF; - s->event->n_enabled_child_sources--; - event_gc_signal_data(s->event, &s->priority, SIGCHLD); - return r; + if (EVENT_SOURCE_WATCH_PIDFD(s)) { + /* yes, we have pidfd */ + + r = source_child_pidfd_register(s, s->enabled); + if (r < 0) { + s->enabled = SD_EVENT_OFF; + s->event->n_enabled_child_sources--; + return r; + } + } else { + /* no pidfd, or something other to watch for than WEXITED */ + + r = event_make_signal_data(s->event, SIGCHLD, NULL); + if (r < 0) { + s->enabled = SD_EVENT_OFF; + s->event->n_enabled_child_sources--; + event_gc_signal_data(s->event, &s->priority, SIGCHLD); + return r; + } } break; @@ -2232,6 +2467,98 @@ _public_ int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid) { return 0; } +_public_ int sd_event_source_get_child_pidfd(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + return s->child.pidfd; +} + +_public_ int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + assert_return(!event_pid_changed(s->event), -ECHILD); + assert_return(SIGNAL_VALID(sig), -EINVAL); + + /* If we already have seen indication the process exited refuse sending a signal early. This way we + * can be sure we don't accidentally kill the wrong process on PID reuse when pidfds are not + * available. */ + if (s->child.exited) + return -ESRCH; + + if (s->child.pidfd >= 0) { + siginfo_t copy; + + /* pidfd_send_signal() changes the siginfo_t argument. This is weird, let's hence copy the + * structure here */ + if (si) + copy = *si; + + if (pidfd_send_signal(s->child.pidfd, sig, si ? © : NULL, 0) < 0) { + /* Let's propagate the error only if the system call is not implemented or prohibited */ + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; + } else + return 0; + } + + /* Flags are only supported for pidfd_send_signal(), not for rt_sigqueueinfo(), hence let's refuse + * this here. */ + if (flags != 0) + return -EOPNOTSUPP; + + if (si) { + /* We use rt_sigqueueinfo() only if siginfo_t is specified. */ + siginfo_t copy = *si; + + if (rt_sigqueueinfo(s->child.pid, sig, ©) < 0) + return -errno; + } else if (kill(s->child.pid, sig) < 0) + return -errno; + + return 0; +} + +_public_ int sd_event_source_get_child_pidfd_own(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + return s->child.pidfd_owned; +} + +_public_ int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + if (s->child.pidfd < 0) + return -EOPNOTSUPP; + + s->child.pidfd_owned = own; + return 0; +} + +_public_ int sd_event_source_get_child_process_own(sd_event_source *s) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + return s->child.process_owned; +} + +_public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own) { + assert_return(s, -EINVAL); + assert_return(s->type == SOURCE_CHILD, -EDOM); + + s->child.process_owned = own; + return 0; +} + _public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) { assert_return(s, -EINVAL); assert_return(mask, -EINVAL); @@ -2542,6 +2869,12 @@ static int process_child(sd_event *e) { if (s->enabled == SD_EVENT_OFF) continue; + if (s->child.exited) + continue; + + if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */ + continue; + zero(s->child.siginfo); r = waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | (s->child.options & WEXITED ? WNOWAIT : 0) | s->child.options); @@ -2551,6 +2884,9 @@ static int process_child(sd_event *e) { if (s->child.siginfo.si_pid != 0) { bool zombie = IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); + if (zombie) + s->child.exited = true; + if (!zombie && (s->child.options & WEXITED)) { /* If the child isn't dead then let's * immediately remove the state change @@ -2570,6 +2906,33 @@ static int process_child(sd_event *e) { return 0; } +static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { + assert(e); + assert(s); + assert(s->type == SOURCE_CHILD); + + if (s->pending) + return 0; + + if (s->enabled == SD_EVENT_OFF) + return 0; + + if (!EVENT_SOURCE_WATCH_PIDFD(s)) + return 0; + + zero(s->child.siginfo); + if (waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0) + return -errno; + + if (s->child.siginfo.si_pid == 0) + return 0; + + if (IN_SET(s->child.siginfo.si_code, CLD_EXITED, CLD_KILLED, CLD_DUMPED)) + s->child.exited = true; + + return source_set_pending(s, true); +} + static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { bool read_one = false; int r; @@ -2854,8 +3217,10 @@ static int source_dispatch(sd_event_source *s) { r = s->child.callback(s, &s->child.siginfo, s->userdata); /* Now, reap the PID for good. */ - if (zombie) + if (zombie) { (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|WEXITED); + s->child.waited = true; + } break; } @@ -3056,6 +3421,11 @@ _public_ int sd_event_prepare(sd_event *e) { assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + /* Let's check that if we are a default event loop we are executed in the correct thread. We only do + * this check here once, since gettid() is typically not cached, and thus want to minimize + * syscalls */ + assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); + if (e->exit_requested) goto pending; @@ -3106,8 +3476,7 @@ pending: } _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { - struct epoll_event *ev_queue; - unsigned ev_queue_max; + size_t event_queue_max; int r, m, i; assert_return(e, -EINVAL); @@ -3121,14 +3490,15 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { return 1; } - ev_queue_max = MAX(e->n_sources, 1u); - ev_queue = newa(struct epoll_event, ev_queue_max); + event_queue_max = MAX(e->n_sources, 1u); + if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, event_queue_max)) + return -ENOMEM; /* If we still have inotify data buffered, then query the other fds, but don't wait on it */ if (e->inotify_data_buffered) timeout = 0; - m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max, + m = epoll_wait(e->epoll_fd, e->event_queue, event_queue_max, timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC)); if (m < 0) { if (errno == EINTR) { @@ -3144,29 +3514,50 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { for (i = 0; i < m; i++) { - if (ev_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG)) - r = flush_timer(e, e->watchdog_fd, ev_queue[i].events, NULL); + if (e->event_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG)) + r = flush_timer(e, e->watchdog_fd, e->event_queue[i].events, NULL); else { - WakeupType *t = ev_queue[i].data.ptr; + WakeupType *t = e->event_queue[i].data.ptr; switch (*t) { - case WAKEUP_EVENT_SOURCE: - r = process_io(e, ev_queue[i].data.ptr, ev_queue[i].events); + case WAKEUP_EVENT_SOURCE: { + sd_event_source *s = e->event_queue[i].data.ptr; + + assert(s); + + switch (s->type) { + + case SOURCE_IO: + r = process_io(e, s, e->event_queue[i].events); + break; + + case SOURCE_CHILD: + r = process_pidfd(e, s, e->event_queue[i].events); + break; + + default: + assert_not_reached("Unexpected event source type"); + } + break; + } case WAKEUP_CLOCK_DATA: { - struct clock_data *d = ev_queue[i].data.ptr; - r = flush_timer(e, d->fd, ev_queue[i].events, &d->next); + struct clock_data *d = e->event_queue[i].data.ptr; + + assert(d); + + r = flush_timer(e, d->fd, e->event_queue[i].events, &d->next); break; } case WAKEUP_SIGNAL_DATA: - r = process_signal(e, ev_queue[i].data.ptr, ev_queue[i].events); + r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events); break; case WAKEUP_INOTIFY_DATA: - r = event_inotify_data_read(e, ev_queue[i].data.ptr, ev_queue[i].events); + r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events); break; default: @@ -3450,8 +3841,6 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { return e->watchdog; if (b) { - struct epoll_event ev; - r = sd_watchdog_enabled(false, &e->watchdog_period); if (r <= 0) return r; @@ -3468,7 +3857,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { if (r < 0) goto fail; - ev = (struct epoll_event) { + struct epoll_event ev = { .events = EPOLLIN, .data.ptr = INT_TO_PTR(SOURCE_WATCHDOG), }; @@ -3481,7 +3870,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) { } else { if (e->watchdog_fd >= 0) { - epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); + (void) epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, e->watchdog_fd, NULL); e->watchdog_fd = safe_close(e->watchdog_fd); } } diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index f8f0883c..3cb96378 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -14,7 +14,7 @@ #include "stdio-util.h" #if 0 /* NM_IGNORED */ -char *id128_to_uuid_string(sd_id128_t id, char s[37]) { +char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]) { unsigned n, k = 0; assert(s); @@ -195,5 +195,18 @@ int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) { return memcmp(a, b, 16); } +sd_id128_t id128_make_v4_uuid(sd_id128_t id) { + /* Stolen from generate_random_uuid() of drivers/char/random.c + * in the kernel sources */ + + /* Set UUID version to 4 --- truly random generation */ + id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; + + /* Set the UUID variant to DCE */ + id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; + + return id; +} + DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func); #endif /* NM_IGNORED */ diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h index 82a69a77..1901bf11 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.h +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -8,7 +8,9 @@ #include "hash-funcs.h" #include "macro.h" -char *id128_to_uuid_string(sd_id128_t id, char s[37]); +#define ID128_UUID_STRING_MAX 37 + +char *id128_to_uuid_string(sd_id128_t id, char s[static ID128_UUID_STRING_MAX]); bool id128_is_valid(const char *s) _pure_; @@ -28,3 +30,5 @@ int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync); void id128_hash_func(const sd_id128_t *p, struct siphash *state); int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) _pure_; extern const struct hash_ops id128_hash_ops; + +sd_id128_t id128_make_v4_uuid(sd_id128_t id); diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index c0d0fe81..d585ff25 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -255,19 +255,6 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) { return 0; } -static sd_id128_t make_v4_uuid(sd_id128_t id) { - /* Stolen from generate_random_uuid() of drivers/char/random.c - * in the kernel sources */ - - /* Set UUID version to 4 --- truly random generation */ - id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; - - /* Set the UUID variant to DCE */ - id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; - - return id; -} - _public_ int sd_id128_randomize(sd_id128_t *ret) { sd_id128_t t; int r; @@ -284,7 +271,7 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) { * only guarantee this for newly generated UUIDs, not for * pre-existing ones. */ - *ret = make_v4_uuid(t); + *ret = id128_make_v4_uuid(t); return 0; } @@ -311,7 +298,7 @@ static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) /* We chop off the trailing 16 bytes */ memcpy(&result, p, MIN(khash_get_size(h), sizeof(result))); - *ret = make_v4_uuid(result); + *ret = id128_make_v4_uuid(result); return 0; } diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h index b3ee7bbc..8158ee73 100644 --- a/src/systemd/src/systemd/_sd-common.h +++ b/src/systemd/src/systemd/_sd-common.h @@ -45,6 +45,18 @@ typedef void (*_sd_destroy_t)(void *userdata); # define _sd_pure_ __attribute__((__pure__)) #endif +/* Note that strictly speaking __deprecated__ has been available before GCC 6. However, starting with GCC 6 + * it also works on enum values, which we are interested in. Since this is a developer-facing feature anyway + * (as opposed to build engineer-facing), let's hence conditionalize this to gcc 6, given that the developers + * are probably going to use something newer anyway. */ +#ifndef _sd_deprecated_ +# if __GNUC__ >= 6 +# define _sd_deprecated_ __attribute__((__deprecated__)) +# else +# define _sd_deprecated_ +# endif +#endif + #ifndef _SD_STRINGIFY # define _SD_XSTRINGIFY(x) #x # define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x) diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index f97e35b6..da2aa6c7 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -83,6 +83,8 @@ enum { SD_DHCP_OPTION_REBINDING_T2_TIME = 59, SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, + SD_DHCP_OPTION_SMTP_SERVER = 69, + SD_DHCP_OPTION_POP3_SERVER = 70, SD_DHCP_OPTION_USER_CLASS = 77, SD_DHCP_OPTION_FQDN = 81, SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, @@ -90,6 +92,7 @@ enum { SD_DHCP_OPTION_DOMAIN_SEARCH_LIST = 119, SD_DHCP_OPTION_SIP_SERVER = 120, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, + SD_DHCP_OPTION_MUD_URL = 161, SD_DHCP_OPTION_PRIVATE_BASE = 224, /* Windows 10 option to send when Anonymize=true */ SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, @@ -169,6 +172,9 @@ int sd_dhcp_client_set_hostname( int sd_dhcp_client_set_vendor_class_identifier( sd_dhcp_client *client, const char *vci); +int sd_dhcp_client_set_mud_url( + sd_dhcp_client *client, + const char *mudurl); int sd_dhcp_client_set_user_class( sd_dhcp_client *client, const char* const *user_class); @@ -179,11 +185,13 @@ int sd_dhcp_client_set_service_type( sd_dhcp_client *client, int type); -int sd_dhcp_client_set_dhcp_option(sd_dhcp_client *client, sd_dhcp_option *v); +int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v); +int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v); int sd_dhcp_client_stop(sd_dhcp_client *client); int sd_dhcp_client_start(sd_dhcp_client *client); int sd_dhcp_client_send_release(sd_dhcp_client *client); +int sd_dhcp_client_send_decline(sd_dhcp_client *client); int sd_dhcp_client_send_renew(sd_dhcp_client *client); sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client); diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h index b80d607f..1ed5bf27 100644 --- a/src/systemd/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -45,6 +45,8 @@ int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *ad int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr); +int sd_dhcp_lease_get_pop3_server(sd_dhcp_lease *lease, const struct in_addr **addr); +int sd_dhcp_lease_get_smtp_server(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains); diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h index be34d43e..42d4ec75 100644 --- a/src/systemd/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -73,6 +73,7 @@ enum { SD_DHCP6_OPTION_FQDN = 39, /* RFC 4704 */ SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */ + SD_DHCP6_OPTION_MUD_URL = 112, /* RFC 8250 */ /* option codes 89-142 are unassigned */ /* option codes 144-65535 are unassigned */ @@ -120,6 +121,9 @@ int sd_dhcp6_client_get_information_request( int sd_dhcp6_client_set_request_option( sd_dhcp6_client *client, uint16_t option); +int sd_dhcp6_client_set_request_mud_url( + sd_dhcp6_client *client, + char *mudurl); int sd_dhcp6_client_set_prefix_delegation_hint( sd_dhcp6_client *client, uint8_t prefixlen, diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h index b14c9269..2ec726a8 100644 --- a/src/systemd/src/systemd/sd-event.h +++ b/src/systemd/src/systemd/sd-event.h @@ -23,6 +23,7 @@ #include <sys/inotify.h> #include <sys/signalfd.h> #include <sys/types.h> +#include <sys/wait.h> #include <time.h> #include "_sd-common.h" @@ -89,6 +90,7 @@ int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, s int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata); int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata); +int sd_event_add_child_pidfd(sd_event *e, sd_event_source **s, int pidfd, int options, sd_event_child_handler_t callback, void *userdata); int sd_event_add_inotify(sd_event *e, sd_event_source **s, const char *path, uint32_t mask, sd_event_inotify_handler_t callback, void *userdata); int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); @@ -141,6 +143,16 @@ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec); int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock); int sd_event_source_get_signal(sd_event_source *s); int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); +int sd_event_source_get_child_pidfd(sd_event_source *s); +int sd_event_source_get_child_pidfd_own(sd_event_source *s); +int sd_event_source_set_child_pidfd_own(sd_event_source *s, int own); +int sd_event_source_get_child_process_own(sd_event_source *s); +int sd_event_source_set_child_process_own(sd_event_source *s, int own); +#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L) +int sd_event_source_send_child_signal(sd_event_source *s, int sig, const siginfo_t *si, unsigned flags); +#else +int sd_event_source_send_child_signal(sd_event_source *s, int sig, const void *si, unsigned flags); +#endif int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret); int sd_event_source_set_destroy_callback(sd_event_source *s, sd_event_destroy_t callback); int sd_event_source_get_destroy_callback(sd_event_source *s, sd_event_destroy_t *ret); diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h index 039ed3c7..ebf723fc 100644 --- a/src/systemd/src/systemd/sd-ipv4acd.h +++ b/src/systemd/src/systemd/sd-ipv4acd.h @@ -20,6 +20,7 @@ #include <net/ethernet.h> #include <netinet/in.h> +#include <stdbool.h> #include "sd-event.h" @@ -44,7 +45,7 @@ int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); int sd_ipv4acd_is_running(sd_ipv4acd *acd); -int sd_ipv4acd_start(sd_ipv4acd *acd); +int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts); int sd_ipv4acd_stop(sd_ipv4acd *acd); sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd); sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd); diff --git a/src/tests/config/meson.build b/src/tests/config/meson.build index e3ebfa19..cfe9c615 100644 --- a/src/tests/config/meson.build +++ b/src/tests/config/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + test_config_dir = meson.current_source_dir() test_unit = 'test-config' diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c index 1c28e976..e6c04efd 100644 --- a/src/tests/config/test-config.c +++ b/src/tests/config/test-config.c @@ -978,7 +978,7 @@ test_config_enable (void) guint match_nm_version = _nm_config_match_nm_version; char *match_env = g_strdup (_nm_config_match_env); - g_clear_pointer (&_nm_config_match_env, g_free); + nm_clear_g_free (&_nm_config_match_env); _nm_config_match_env = g_strdup ("something-else"); _nm_config_match_nm_version = nm_encode_version (1, 3, 4); @@ -992,14 +992,14 @@ test_config_enable (void) g_clear_object (&config); _nm_config_match_nm_version = nm_encode_version (1, 5, 3); - g_clear_pointer (&_nm_config_match_env, g_free); + nm_clear_g_free (&_nm_config_match_env); _nm_config_match_env = g_strdup ("test-match-env-1"); config = setup_config (NULL, TEST_DIR "/NetworkManager.conf", "", NULL, TEST_DIR "/conf.d", "", NULL); assert_config_value (nm_config_get_data_orig (config), "test-group-config-enable-1", "key1", "enabled"); g_clear_object (&config); _nm_config_match_nm_version = match_nm_version; - g_clear_pointer (&_nm_config_match_env, g_free); + nm_clear_g_free (&_nm_config_match_env); _nm_config_match_env = match_env; } diff --git a/src/tests/meson.build b/src/tests/meson.build index ac877e18..df8d1cf8 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + subdir('config') test_units = [ diff --git a/src/tests/test-core-with-expect.c b/src/tests/test-core-with-expect.c index 74e1043b..555b9624 100644 --- a/src/tests/test-core-with-expect.c +++ b/src/tests/test-core-with-expect.c @@ -20,7 +20,7 @@ static void test_nm_utils_monotonic_timestamp_as_boottime (void) { - gint64 timestamp_ns_per_tick, now, now_boottime, now_boottime_2, now_boottime_3; + gint64 timestamp_nsec_per_tick, now, now_boottime, now_boottime_2, now_boottime_3; struct timespec tp; clockid_t clockid; guint i; @@ -35,22 +35,22 @@ test_nm_utils_monotonic_timestamp_as_boottime (void) if (clock_gettime (clockid, &tp) != 0) g_assert_not_reached (); - now_boottime = ( ((gint64) tp.tv_sec) * NM_UTILS_NS_PER_SECOND ) + ((gint64) tp.tv_nsec); + now_boottime = ( ((gint64) tp.tv_sec) * NM_UTILS_NSEC_PER_SEC ) + ((gint64) tp.tv_nsec); - now = nm_utils_get_monotonic_timestamp_ns (); + now = nm_utils_get_monotonic_timestamp_nsec (); now_boottime_2 = nm_utils_monotonic_timestamp_as_boottime (now, 1); g_assert_cmpint (now_boottime_2, >=, 0); g_assert_cmpint (now_boottime_2, >=, now_boottime); - g_assert_cmpint (now_boottime_2 - now_boottime, <=, NM_UTILS_NS_PER_SECOND / 10); + g_assert_cmpint (now_boottime_2 - now_boottime, <=, NM_UTILS_NSEC_PER_SEC / 10); g_assert_cmpint (now, ==, nm_utils_monotonic_timestamp_from_boottime (now_boottime_2, 1)); - for (timestamp_ns_per_tick = 1; timestamp_ns_per_tick <= NM_UTILS_NS_PER_SECOND; timestamp_ns_per_tick *= 10) { - now_boottime_3 = nm_utils_monotonic_timestamp_as_boottime (now / timestamp_ns_per_tick, timestamp_ns_per_tick); + for (timestamp_nsec_per_tick = 1; timestamp_nsec_per_tick <= NM_UTILS_NSEC_PER_SEC; timestamp_nsec_per_tick *= 10) { + now_boottime_3 = nm_utils_monotonic_timestamp_as_boottime (now / timestamp_nsec_per_tick, timestamp_nsec_per_tick); - g_assert_cmpint (now_boottime_2 / timestamp_ns_per_tick, ==, now_boottime_3); - g_assert_cmpint (now / timestamp_ns_per_tick, ==, nm_utils_monotonic_timestamp_from_boottime (now_boottime_3, timestamp_ns_per_tick)); + g_assert_cmpint (now_boottime_2 / timestamp_nsec_per_tick, ==, now_boottime_3); + g_assert_cmpint (now / timestamp_nsec_per_tick, ==, nm_utils_monotonic_timestamp_from_boottime (now_boottime_3, timestamp_nsec_per_tick)); } } } diff --git a/src/tests/test-core.c b/src/tests/test-core.c index 590f7c36..b90a8fac 100644 --- a/src/tests/test-core.c +++ b/src/tests/test-core.c @@ -1019,7 +1019,7 @@ _test_connection_sort_autoconnect_priority_one (NMConnection **list, gboolean sh if (shuffle) { for (i = count - 1; i > 0; i--) { j = g_rand_int (nmtst_get_rand ()) % (i + 1); - NMTST_SWAP (connections->pdata[i], connections->pdata[j]); + NM_SWAP (connections->pdata[i], connections->pdata[j]); } } diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index 401d1eee..efc32983 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -246,7 +246,7 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config for (i = 0; i < addr_count; i++) { int j = g_rand_int_range (nmtst_get_rand (), i, addr_count); - NMTST_SWAP (idx[i], idx[j]); + NM_SWAP (idx[i], idx[j]); nm_ip6_config_add_address (copy, _nmtst_ip6_config_get_address (config, idx[i])); } diff --git a/src/tests/test-systemd.c b/src/tests/test-systemd.c index faed0e56..6425c294 100644 --- a/src/tests/test-systemd.c +++ b/src/tests/test-systemd.c @@ -27,7 +27,7 @@ _nm_utils_set_testing (NMUtilsTestFlags flags) } gint32 -nm_utils_get_monotonic_timestamp_s (void) +nm_utils_get_monotonic_timestamp_sec (void) { return 1; } diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 974009f9..35bf4afb 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -141,7 +141,7 @@ struct _NMVpnConnectionClass { G_DEFINE_TYPE (NMVpnConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION) -#define NM_VPN_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMVpnConnection, NM_IS_VPN_CONNECTION) +#define NM_VPN_CONNECTION_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMVpnConnection, NM_IS_VPN_CONNECTION, NMActiveConnection) /*****************************************************************************/ @@ -872,7 +872,8 @@ nm_vpn_connection_get_service (NMVpnConnection *self) return nm_setting_vpn_get_service_type (s_vpn); } -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_vpn_plugin_failure_to_string, NMVpnPluginFailure, +static +NM_UTILS_LOOKUP_STR_DEFINE (_vpn_plugin_failure_to_string, NMVpnPluginFailure, NM_UTILS_LOOKUP_DEFAULT (NULL), NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED, "login-failed"), NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED, "connect-failed"), @@ -901,7 +902,8 @@ plugin_failed (NMVpnConnection *self, guint reason) } } -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_vpn_service_state_to_string, NMVpnServiceState, +static +NM_UTILS_LOOKUP_STR_DEFINE (_vpn_service_state_to_string, NMVpnServiceState, NM_UTILS_LOOKUP_DEFAULT (NULL), NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_UNKNOWN, "unknown"), NM_UTILS_LOOKUP_STR_ITEM (NM_VPN_SERVICE_STATE_INIT, "init"), @@ -914,7 +916,8 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_vpn_service_state_to_string, NMVpnServiceSta #define vpn_service_state_to_string_a(state) NM_UTILS_LOOKUP_STR_A (_vpn_service_state_to_string, state) -NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_vpn_state_to_string, VpnState, +static +NM_UTILS_LOOKUP_STR_DEFINE (_vpn_state_to_string, VpnState, NM_UTILS_LOOKUP_DEFAULT (NULL), NM_UTILS_LOOKUP_STR_ITEM (STATE_UNKNOWN, "unknown"), NM_UTILS_LOOKUP_STR_ITEM (STATE_WAITING, "waiting"), @@ -984,10 +987,10 @@ print_vpn_config (NMVpnConnection *self) if (priv->ip4_external_gw) { _LOGI ("Data: VPN Gateway: %s", - nm_utils_inet4_ntop (priv->ip4_external_gw, b1)); + _nm_utils_inet4_ntop (priv->ip4_external_gw, b1)); } else if (priv->ip6_external_gw) { _LOGI ("Data: VPN Gateway: %s", - nm_utils_inet6_ntop (priv->ip6_external_gw, b1)); + _nm_utils_inet6_ntop (priv->ip6_external_gw, b1)); } _LOGI ("Data: Tunnel Device: %s%s%s", NM_PRINT_FMT_QUOTE_STRING (priv->ip_iface)); @@ -1001,22 +1004,22 @@ print_vpn_config (NMVpnConnection *self) nm_assert (address4); if (priv->ip4_internal_gw) - _LOGI ("Data: Internal Gateway: %s", nm_utils_inet4_ntop (priv->ip4_internal_gw, b1)); - _LOGI ("Data: Internal Address: %s", address4 ? nm_utils_inet4_ntop (address4->address, b1) : "??"); + _LOGI ("Data: Internal Gateway: %s", _nm_utils_inet4_ntop (priv->ip4_internal_gw, b1)); + _LOGI ("Data: Internal Address: %s", address4 ? _nm_utils_inet4_ntop (address4->address, b1) : "??"); _LOGI ("Data: Internal Prefix: %d", address4 ? (int) address4->plen : -1); - _LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet4_ntop (address4->peer_address, b1)); + _LOGI ("Data: Internal Point-to-Point Address: %s", _nm_utils_inet4_ntop (address4->peer_address, b1)); nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) { _LOGI ("Data: Static Route: %s/%d Next Hop: %s", - nm_utils_inet4_ntop (route->network, b1), + _nm_utils_inet4_ntop (route->network, b1), route->plen, - nm_utils_inet4_ntop (route->gateway, b2)); + _nm_utils_inet4_ntop (route->gateway, b2)); } num = nm_ip4_config_get_num_nameservers (priv->ip4_config); for (i = 0; i < num; i++) { _LOGI ("Data: Internal DNS: %s", - nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (priv->ip4_config, i), b1)); + _nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (priv->ip4_config, i), b1)); } if (nm_ip4_config_get_num_domains (priv->ip4_config) > 0) @@ -1035,22 +1038,22 @@ print_vpn_config (NMVpnConnection *self) nm_assert (address6); if (priv->ip6_internal_gw) - _LOGI ("Data: Internal Gateway: %s", nm_utils_inet6_ntop (priv->ip6_internal_gw, b1)); - _LOGI ("Data: Internal Address: %s", nm_utils_inet6_ntop (&address6->address, b1)); + _LOGI ("Data: Internal Gateway: %s", _nm_utils_inet6_ntop (priv->ip6_internal_gw, b1)); + _LOGI ("Data: Internal Address: %s", _nm_utils_inet6_ntop (&address6->address, b1)); _LOGI ("Data: Internal Prefix: %d", address6->plen); - _LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet6_ntop (&address6->peer_address, b1)); + _LOGI ("Data: Internal Point-to-Point Address: %s", _nm_utils_inet6_ntop (&address6->peer_address, b1)); nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) { _LOGI ("Data: Static Route: %s/%d Next Hop: %s", - nm_utils_inet6_ntop (&route->network, b1), + _nm_utils_inet6_ntop (&route->network, b1), route->plen, - nm_utils_inet6_ntop (&route->gateway, b2)); + _nm_utils_inet6_ntop (&route->gateway, b2)); } num = nm_ip6_config_get_num_nameservers (priv->ip6_config); for (i = 0; i < num; i++) { _LOGI ("Data: Internal DNS: %s", - nm_utils_inet6_ntop (nm_ip6_config_get_nameserver (priv->ip6_config, i), b1)); + _nm_utils_inet6_ntop (nm_ip6_config_get_nameserver (priv->ip6_config, i), b1)); } if (nm_ip6_config_get_num_domains (priv->ip6_config) > 0) @@ -1194,7 +1197,7 @@ fw_change_zone_cb (NMFirewallManager *firewall_manager, priv->fw_call = NULL; - if (nm_utils_error_is_cancelled (error, FALSE)) + if (nm_utils_error_is_cancelled (error)) return; if (error) { @@ -1300,7 +1303,7 @@ process_generic_config (NMVpnConnection *self, GVariant *dict) priv->service_can_persist = TRUE; } - g_clear_pointer (&priv->ip_iface, g_free); + nm_clear_g_free (&priv->ip_iface); priv->ip_ifindex = 0; if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_TUNDEV, "&s", &str)) { @@ -1318,14 +1321,14 @@ process_generic_config (NMVpnConnection *self, GVariant *dict) } if (priv->ip_ifindex <= 0) { _LOGE ("failed to look up VPN interface index for \"%s\"", priv->ip_iface); - g_clear_pointer (&priv->ip_iface, g_free); + nm_clear_g_free (&priv->ip_iface); priv->ip_ifindex = 0; nm_vpn_connection_config_maybe_complete (self, FALSE); return FALSE; } } - g_clear_pointer (&priv->banner, g_free); + nm_clear_g_free (&priv->banner); if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_BANNER, "&s", &str)) { priv->banner = g_strdup (str); _notify (self, PROP_BANNER); @@ -1347,7 +1350,7 @@ process_generic_config (NMVpnConnection *self, GVariant *dict) /* External world-visible address of the VPN server */ priv->ip4_external_gw = 0; - g_clear_pointer (&priv->ip6_external_gw, g_free); + nm_clear_g_free (&priv->ip6_external_gw); if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "u", &u32)) { priv->ip4_external_gw = u32; @@ -1633,7 +1636,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) nm_ip4_config_add_route (config, &r, NULL); } - g_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); + nm_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); nm_ip4_config_add_dependent_routes (config, route_table, @@ -1699,7 +1702,7 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) address.plen = 128; /* Internal address of the VPN subnet's gateway */ - g_clear_pointer (&priv->ip6_internal_gw, g_free); + nm_clear_g_free (&priv->ip6_internal_gw); if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, "@ay", &v)) { priv->ip6_internal_gw = ip6_addr_dup_from_variant (v); g_variant_unref (v); @@ -1880,7 +1883,7 @@ connect_success (NMVpnConnection *self) } priv->connect_timeout = g_timeout_add_seconds (timeout, connect_timeout_cb, self); - g_clear_pointer (&priv->connect_hash, g_variant_unref); + nm_clear_pointer (&priv->connect_hash, g_variant_unref); } static void @@ -1977,7 +1980,7 @@ really_activate (NMVpnConnection *self, const char *username) priv = NM_VPN_CONNECTION_GET_PRIVATE (self); g_return_if_fail (priv->vpn_state == STATE_NEED_AUTH); - g_clear_pointer (&priv->connect_hash, g_variant_unref); + nm_clear_pointer (&priv->connect_hash, g_variant_unref); priv->connect_hash = _hash_with_username (_get_applied_connection (self), username); g_variant_ref_sink (priv->connect_hash); @@ -2714,7 +2717,7 @@ device_changed (NMActiveConnection *active, NMDevice *new_device, NMDevice *old_device) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE ((NMVpnConnection *) active); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (active); if (!_service_and_connection_can_persist (NM_VPN_CONNECTION (active))) return; @@ -2761,9 +2764,9 @@ dispose (GObject *object) nm_clear_g_source (&priv->start_timeout); - g_clear_pointer (&priv->connect_hash, g_variant_unref); + nm_clear_pointer (&priv->connect_hash, g_variant_unref); - g_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); + nm_clear_pointer (&priv->ip4_dev_route_blacklist, g_ptr_array_unref); nm_clear_g_source (&priv->connect_timeout); @@ -2789,7 +2792,7 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE ((NMVpnConnection *) object); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object); g_free (priv->banner); g_free (priv->ip_iface); @@ -2812,7 +2815,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE ((NMVpnConnection *) object); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object); NMDevice *parent_dev; switch (prop_id) { diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h index 43242a8e..b2d3e370 100644 --- a/src/vpn/nm-vpn-connection.h +++ b/src/vpn/nm-vpn-connection.h @@ -9,7 +9,7 @@ #include "nm-vpn-dbus-interface.h" #include "devices/nm-device.h" -#include "nm-auth-subject.h" +#include "nm-libnm-core-intern/nm-auth-subject.h" #include "nm-active-connection.h" #include "nm-vpn-plugin-info.h" diff --git a/src/vpn/nm-vpn-manager.c b/src/vpn/nm-vpn-manager.c index 4c94a260..a80ab71e 100644 --- a/src/vpn/nm-vpn-manager.c +++ b/src/vpn/nm-vpn-manager.c @@ -244,7 +244,7 @@ nm_vpn_manager_init (NMVpnManager *self) static void dispose (GObject *object) { - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE ((NMVpnManager *) object); + NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (object); if (priv->monitor_etc) { if (priv->monitor_id_etc) |