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/devices | |
| parent | b012fa6e1d808e0736c009799c62d835cbfcc1dd (diff) | |
New upstream version 1.23.90 upstream/1.23.90
Diffstat (limited to 'src/devices')
61 files changed, 3421 insertions, 2983 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; } } |